1 /* $OpenBSD: neighbor.c,v 1.19 2023/03/08 04:43:14 guenther Exp $ */
2
3 /*
4 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
5 * Copyright (c) 2004, 2005, 2007 Esben Norby <norby@openbsd.org>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 #include <sys/types.h>
21 #include <sys/ioctl.h>
22 #include <sys/time.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <net/if.h>
27
28 #include <ctype.h>
29 #include <err.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <event.h>
34
35 #include "ospf6d.h"
36 #include "ospf6.h"
37 #include "ospfe.h"
38 #include "log.h"
39 #include "rde.h"
40
41 int nbr_adj_ok(struct nbr *);
42
43 LIST_HEAD(nbr_head, nbr);
44
45 struct nbr_table {
46 struct nbr_head *hashtbl;
47 u_int32_t hashmask;
48 } nbrtable;
49
50 #define NBR_HASH(x) \
51 &nbrtable.hashtbl[(x) & nbrtable.hashmask]
52
53 u_int32_t peercnt = NBR_CNTSTART;
54
55 struct {
56 int state;
57 enum nbr_event event;
58 enum nbr_action action;
59 int new_state; /* 0 means action decides or unchanged */
60 } nbr_fsm_tbl[] = {
61 /* current state event that happened action to take resulting state */
62 {NBR_STA_ACTIVE, NBR_EVT_HELLO_RCVD, NBR_ACT_RST_ITIMER, 0},
63 {NBR_STA_BIDIR, NBR_EVT_2_WAY_RCVD, NBR_ACT_NOTHING, 0},
64 {NBR_STA_INIT, NBR_EVT_1_WAY_RCVD, NBR_ACT_NOTHING, 0},
65 {NBR_STA_DOWN, NBR_EVT_HELLO_RCVD, NBR_ACT_STRT_ITIMER, NBR_STA_INIT},
66 {NBR_STA_ATTEMPT, NBR_EVT_HELLO_RCVD, NBR_ACT_RST_ITIMER, NBR_STA_INIT},
67 {NBR_STA_INIT, NBR_EVT_2_WAY_RCVD, NBR_ACT_EVAL, 0},
68 {NBR_STA_XSTRT, NBR_EVT_NEG_DONE, NBR_ACT_SNAP, 0},
69 {NBR_STA_SNAP, NBR_EVT_SNAP_DONE, NBR_ACT_SNAP_DONE, NBR_STA_XCHNG},
70 {NBR_STA_XCHNG, NBR_EVT_XCHNG_DONE, NBR_ACT_XCHNG_DONE, 0},
71 {NBR_STA_LOAD, NBR_EVT_LOAD_DONE, NBR_ACT_NOTHING, NBR_STA_FULL},
72 {NBR_STA_2_WAY, NBR_EVT_ADJ_OK, NBR_ACT_EVAL, 0},
73 {NBR_STA_ADJFORM, NBR_EVT_ADJ_OK, NBR_ACT_ADJ_OK, 0},
74 {NBR_STA_PRELIM, NBR_EVT_ADJ_OK, NBR_ACT_HELLO_CHK, 0},
75 {NBR_STA_ADJFORM, NBR_EVT_ADJTMOUT, NBR_ACT_RESTRT_DD, 0},
76 {NBR_STA_FLOOD, NBR_EVT_SEQ_NUM_MIS, NBR_ACT_RESTRT_DD, 0},
77 {NBR_STA_FLOOD, NBR_EVT_BAD_LS_REQ, NBR_ACT_RESTRT_DD, 0},
78 {NBR_STA_ANY, NBR_EVT_KILL_NBR, NBR_ACT_DEL, NBR_STA_DOWN},
79 {NBR_STA_ANY, NBR_EVT_LL_DOWN, NBR_ACT_DEL, NBR_STA_DOWN},
80 {NBR_STA_ANY, NBR_EVT_ITIMER, NBR_ACT_DEL, NBR_STA_DOWN},
81 {NBR_STA_BIDIR, NBR_EVT_1_WAY_RCVD, NBR_ACT_CLR_LST, NBR_STA_INIT},
82 {-1, NBR_EVT_NOTHING, NBR_ACT_NOTHING, 0},
83 };
84
85 const char * const nbr_event_names[] = {
86 "NOTHING",
87 "HELLO_RECEIVED",
88 "2_WAY_RECEIVED",
89 "NEGOTIATION_DONE",
90 "SNAPSHOT_DONE",
91 "EXCHANGE_DONE",
92 "BAD_LS_REQ",
93 "LOADING_DONE",
94 "ADJ_OK",
95 "SEQ_NUM_MISMATCH",
96 "1_WAY_RECEIVED",
97 "KILL_NBR",
98 "INACTIVITY_TIMER",
99 "LL_DOWN",
100 "ADJ_TIMEOUT"
101 };
102
103 const char * const nbr_action_names[] = {
104 "NOTHING",
105 "RESET_INACTIVITY_TIMER",
106 "START_INACTIVITY_TIMER",
107 "EVAL",
108 "SNAPSHOT",
109 "SNAPSHOT_DONE",
110 "EXCHANGE_DONE",
111 "ADJ_OK",
112 "RESET_DD",
113 "DELETE",
114 "CLEAR_LISTS",
115 "HELLO_CHK"
116 };
117
118 int
nbr_fsm(struct nbr * nbr,enum nbr_event event)119 nbr_fsm(struct nbr *nbr, enum nbr_event event)
120 {
121 struct timeval now;
122 int old_state;
123 int new_state = 0;
124 int i, ret = 0;
125
126 if (nbr == nbr->iface->self)
127 return (0);
128
129 old_state = nbr->state;
130 for (i = 0; nbr_fsm_tbl[i].state != -1; i++)
131 if ((nbr_fsm_tbl[i].state & old_state) &&
132 (nbr_fsm_tbl[i].event == event)) {
133 new_state = nbr_fsm_tbl[i].new_state;
134 break;
135 }
136
137 if (nbr_fsm_tbl[i].state == -1) {
138 /* event outside of the defined fsm, ignore it. */
139 log_warnx("nbr_fsm: neighbor ID %s (%s), "
140 "event %s not expected in state %s",
141 inet_ntoa(nbr->id), nbr->iface->name,
142 nbr_event_names[event],
143 nbr_state_name(old_state));
144 return (0);
145 }
146
147 switch (nbr_fsm_tbl[i].action) {
148 case NBR_ACT_RST_ITIMER:
149 ret = nbr_act_reset_itimer(nbr);
150 break;
151 case NBR_ACT_STRT_ITIMER:
152 ret = nbr_act_start_itimer(nbr);
153 break;
154 case NBR_ACT_EVAL:
155 ret = nbr_act_eval(nbr);
156 break;
157 case NBR_ACT_SNAP:
158 ret = nbr_act_snapshot(nbr);
159 break;
160 case NBR_ACT_SNAP_DONE:
161 /* start db exchange */
162 start_db_tx_timer(nbr);
163 break;
164 case NBR_ACT_XCHNG_DONE:
165 ret = nbr_act_exchange_done(nbr);
166 break;
167 case NBR_ACT_ADJ_OK:
168 ret = nbr_act_adj_ok(nbr);
169 break;
170 case NBR_ACT_RESTRT_DD:
171 ret = nbr_act_restart_dd(nbr);
172 break;
173 case NBR_ACT_DEL:
174 ret = nbr_act_delete(nbr);
175 break;
176 case NBR_ACT_CLR_LST:
177 ret = nbr_act_clear_lists(nbr);
178 break;
179 case NBR_ACT_HELLO_CHK:
180 ret = nbr_act_hello_check(nbr);
181 break;
182 case NBR_ACT_NOTHING:
183 /* do nothing */
184 break;
185 }
186
187 if (ret) {
188 log_warnx("nbr_fsm: error changing state for neighbor "
189 "ID %s (%s), event %s, state %s",
190 inet_ntoa(nbr->id), nbr->iface->name,
191 nbr_event_names[event], nbr_state_name(old_state));
192 return (-1);
193 }
194
195 if (new_state != 0)
196 nbr->state = new_state;
197
198 if (old_state != nbr->state) {
199 nbr->stats.sta_chng++;
200
201 if (old_state & NBR_STA_FULL || nbr->state & NBR_STA_FULL) {
202 /*
203 * neighbor changed from/to FULL
204 * originate new rtr and net LSA
205 */
206 orig_rtr_lsa(nbr->iface->area);
207 if (nbr->iface->state & IF_STA_DR)
208 orig_net_lsa(nbr->iface);
209
210 gettimeofday(&now, NULL);
211 nbr->uptime = now.tv_sec;
212 }
213
214 /* state change inform RDE */
215 ospfe_imsg_compose_rde(IMSG_NEIGHBOR_CHANGE,
216 nbr->peerid, 0, &nbr->state, sizeof(nbr->state));
217
218 /* bidirectional communication lost */
219 if (old_state & ~NBR_STA_PRELIM && nbr->state & NBR_STA_PRELIM)
220 if_fsm(nbr->iface, IF_EVT_NBR_CHNG);
221
222 log_debug("nbr_fsm: event %s resulted in action %s and "
223 "changing state for neighbor ID %s (%s) from %s to %s",
224 nbr_event_names[event],
225 nbr_action_names[nbr_fsm_tbl[i].action],
226 inet_ntoa(nbr->id), nbr->iface->name,
227 nbr_state_name(old_state),
228 nbr_state_name(nbr->state));
229
230 if (nbr->iface->type == IF_TYPE_VIRTUALLINK) {
231 orig_rtr_lsa(nbr->iface->area);
232 }
233 }
234
235 return (ret);
236 }
237
238 void
nbr_init(u_int32_t hashsize)239 nbr_init(u_int32_t hashsize)
240 {
241 struct nbr_head *head;
242 struct nbr *nbr;
243 u_int32_t hs, i;
244
245 for (hs = 1; hs < hashsize; hs <<= 1)
246 ;
247 nbrtable.hashtbl = calloc(hs, sizeof(struct nbr_head));
248 if (nbrtable.hashtbl == NULL)
249 fatal("nbr_init");
250
251 for (i = 0; i < hs; i++)
252 LIST_INIT(&nbrtable.hashtbl[i]);
253
254 nbrtable.hashmask = hs - 1;
255
256 /* allocate a dummy neighbor used for self originated AS ext routes */
257 if ((nbr = calloc(1, sizeof(*nbr))) == NULL)
258 fatal("nbr_init");
259
260 nbr->id.s_addr = ospfe_router_id();
261 nbr->state = NBR_STA_DOWN;
262 nbr->peerid = NBR_IDSELF;
263 head = NBR_HASH(nbr->peerid);
264 LIST_INSERT_HEAD(head, nbr, hash);
265
266 TAILQ_INIT(&nbr->ls_retrans_list);
267 TAILQ_INIT(&nbr->db_sum_list);
268 TAILQ_INIT(&nbr->ls_req_list);
269 }
270
271 struct nbr *
nbr_new(u_int32_t nbr_id,struct iface * iface,u_int32_t iface_id,int self,struct in6_addr * addr)272 nbr_new(u_int32_t nbr_id, struct iface *iface, u_int32_t iface_id, int self,
273 struct in6_addr *addr)
274 {
275 struct nbr_head *head;
276 struct nbr *nbr;
277 struct rde_nbr rn;
278
279 if ((nbr = calloc(1, sizeof(*nbr))) == NULL)
280 fatal("nbr_new");
281
282 nbr->state = NBR_STA_DOWN;
283 nbr->dd_master = 1;
284 nbr->dd_seq_num = arc4random(); /* RFC: some unique value */
285 nbr->id.s_addr = nbr_id;
286
287 /* get next unused peerid */
288 while (nbr_find_peerid(++peercnt))
289 ;
290 nbr->peerid = peercnt;
291 head = NBR_HASH(nbr->peerid);
292 LIST_INSERT_HEAD(head, nbr, hash);
293
294 /* add to peer list */
295 nbr->iface = iface;
296 nbr->iface_id = iface_id;
297 LIST_INSERT_HEAD(&iface->nbr_list, nbr, entry);
298
299 TAILQ_INIT(&nbr->ls_retrans_list);
300 TAILQ_INIT(&nbr->db_sum_list);
301 TAILQ_INIT(&nbr->ls_req_list);
302
303 nbr->ls_req = NULL;
304
305 if (self) {
306 nbr->state = NBR_STA_FULL;
307 nbr->addr = iface->addr;
308 nbr->priority = iface->priority;
309 }
310
311 /* set event structures */
312 evtimer_set(&nbr->inactivity_timer, nbr_itimer, nbr);
313 evtimer_set(&nbr->db_tx_timer, db_tx_timer, nbr);
314 evtimer_set(&nbr->lsreq_tx_timer, ls_req_tx_timer, nbr);
315 evtimer_set(&nbr->ls_retrans_timer, ls_retrans_timer, nbr);
316 evtimer_set(&nbr->adj_timer, nbr_adj_timer, nbr);
317
318 bzero(&rn, sizeof(rn));
319 if (addr)
320 rn.addr = *addr;
321 rn.id.s_addr = nbr->id.s_addr;
322 rn.area_id.s_addr = nbr->iface->area->id.s_addr;
323 rn.ifindex = nbr->iface->ifindex;
324 rn.iface_id = nbr->iface_id;
325 rn.state = nbr->state;
326 rn.self = self;
327 ospfe_imsg_compose_rde(IMSG_NEIGHBOR_UP, nbr->peerid, 0, &rn,
328 sizeof(rn));
329
330 return (nbr);
331 }
332
333 void
nbr_del(struct nbr * nbr)334 nbr_del(struct nbr *nbr)
335 {
336 ospfe_imsg_compose_rde(IMSG_NEIGHBOR_DOWN, nbr->peerid, 0, NULL, 0);
337
338 if (evtimer_pending(&nbr->inactivity_timer, NULL))
339 evtimer_del(&nbr->inactivity_timer);
340 if (evtimer_pending(&nbr->db_tx_timer, NULL))
341 evtimer_del(&nbr->db_tx_timer);
342 if (evtimer_pending(&nbr->lsreq_tx_timer, NULL))
343 evtimer_del(&nbr->lsreq_tx_timer);
344 if (evtimer_pending(&nbr->ls_retrans_timer, NULL))
345 evtimer_del(&nbr->ls_retrans_timer);
346 if (evtimer_pending(&nbr->adj_timer, NULL))
347 evtimer_del(&nbr->adj_timer);
348
349 /* clear lists */
350 ls_retrans_list_clr(nbr);
351 db_sum_list_clr(nbr);
352 ls_req_list_clr(nbr);
353
354 LIST_REMOVE(nbr, entry);
355 LIST_REMOVE(nbr, hash);
356
357 free(nbr);
358 }
359
360 struct nbr *
nbr_find_peerid(u_int32_t peerid)361 nbr_find_peerid(u_int32_t peerid)
362 {
363 struct nbr_head *head;
364 struct nbr *nbr;
365
366 head = NBR_HASH(peerid);
367
368 LIST_FOREACH(nbr, head, hash) {
369 if (nbr->peerid == peerid)
370 return (nbr);
371 }
372
373 return (NULL);
374 }
375
376 struct nbr *
nbr_find_id(struct iface * iface,u_int32_t rtr_id)377 nbr_find_id(struct iface *iface, u_int32_t rtr_id)
378 {
379 struct nbr *nbr = NULL;
380
381 LIST_FOREACH(nbr, &iface->nbr_list, entry) {
382 if (nbr->id.s_addr == rtr_id)
383 return (nbr);
384 }
385
386 return (NULL);
387 }
388
389 /* timers */
390 void
nbr_itimer(int fd,short event,void * arg)391 nbr_itimer(int fd, short event, void *arg)
392 {
393 struct nbr *nbr = arg;
394
395 if (nbr->state == NBR_STA_DOWN)
396 nbr_del(nbr);
397 else
398 nbr_fsm(nbr, NBR_EVT_ITIMER);
399 }
400
401 void
nbr_start_itimer(struct nbr * nbr)402 nbr_start_itimer(struct nbr *nbr)
403 {
404 struct timeval tv;
405
406 timerclear(&tv);
407 tv.tv_sec = nbr->iface->dead_interval;
408
409 if (evtimer_add(&nbr->inactivity_timer, &tv) == -1)
410 fatal("nbr_start_itimer");
411 }
412
413 void
nbr_stop_itimer(struct nbr * nbr)414 nbr_stop_itimer(struct nbr *nbr)
415 {
416 if (evtimer_del(&nbr->inactivity_timer) == -1)
417 fatal("nbr_stop_itimer");
418 }
419
420 void
nbr_reset_itimer(struct nbr * nbr)421 nbr_reset_itimer(struct nbr *nbr)
422 {
423 struct timeval tv;
424
425 timerclear(&tv);
426 tv.tv_sec = nbr->iface->dead_interval;
427
428 if (evtimer_add(&nbr->inactivity_timer, &tv) == -1)
429 fatal("nbr_reset_itimer");
430 }
431
432 void
nbr_adj_timer(int fd,short event,void * arg)433 nbr_adj_timer(int fd, short event, void *arg)
434 {
435 struct nbr *nbr = arg;
436
437 if (!(nbr->state & NBR_STA_ADJFORM))
438 return;
439
440 if (nbr->state & NBR_STA_ACTIVE && nbr->state != NBR_STA_FULL) {
441 log_warnx("nbr_adj_timer: failed to form adjacency with "
442 "neighbor ID %s on interface %s",
443 inet_ntoa(nbr->id), nbr->iface->name);
444 nbr_fsm(nbr, NBR_EVT_ADJTMOUT);
445 }
446 }
447
448 void
nbr_start_adj_timer(struct nbr * nbr)449 nbr_start_adj_timer(struct nbr *nbr)
450 {
451 struct timeval tv;
452
453 timerclear(&tv);
454 tv.tv_sec = DEFAULT_ADJ_TMOUT;
455
456 if (evtimer_add(&nbr->adj_timer, &tv) == -1)
457 fatal("nbr_start_adj_timer");
458 }
459
460 /* actions */
461 int
nbr_act_reset_itimer(struct nbr * nbr)462 nbr_act_reset_itimer(struct nbr *nbr)
463 {
464 nbr_reset_itimer(nbr);
465
466 return (0);
467 }
468
469 int
nbr_act_start_itimer(struct nbr * nbr)470 nbr_act_start_itimer(struct nbr *nbr)
471 {
472 nbr_start_itimer(nbr);
473
474 return (0);
475 }
476
477 int
nbr_adj_ok(struct nbr * nbr)478 nbr_adj_ok(struct nbr *nbr)
479 {
480 struct iface *iface = nbr->iface;
481
482 switch (iface->type) {
483 case IF_TYPE_POINTOPOINT:
484 case IF_TYPE_VIRTUALLINK:
485 case IF_TYPE_POINTOMULTIPOINT:
486 /* always ok */
487 break;
488 case IF_TYPE_BROADCAST:
489 case IF_TYPE_NBMA:
490 /*
491 * if neighbor is dr, bdr or router self is dr or bdr
492 * start forming adjacency
493 */
494 if (iface->dr == nbr || iface->bdr == nbr ||
495 iface->state & IF_STA_DRORBDR)
496 break;
497 return (0);
498 default:
499 fatalx("nbr_adj_ok: unknown interface type");
500 }
501 return (1);
502 }
503
504 int
nbr_act_eval(struct nbr * nbr)505 nbr_act_eval(struct nbr *nbr)
506 {
507 if (!nbr_adj_ok(nbr)) {
508 nbr->state = NBR_STA_2_WAY;
509 return (0);
510 }
511
512 nbr->state = NBR_STA_XSTRT;
513 nbr->dd_master = 1;
514 nbr->dd_seq_num++; /* as per RFC */
515 nbr->dd_pending = 0;
516 /* initial db negotiation */
517 start_db_tx_timer(nbr);
518
519 nbr_start_adj_timer(nbr);
520
521 return (0);
522 }
523
524 int
nbr_act_snapshot(struct nbr * nbr)525 nbr_act_snapshot(struct nbr *nbr)
526 {
527 stop_db_tx_timer(nbr);
528
529 /* we need to wait for the old snapshot to finish */
530 if (nbr->dd_snapshot) {
531 log_debug("nbr_act_snapshot: giving up, old snapshot running "
532 "for neighbor ID %s (%s)", inet_ntoa(nbr->id),
533 nbr->iface->name);
534 return (nbr_act_restart_dd(nbr));
535 }
536 ospfe_imsg_compose_rde(IMSG_DB_SNAPSHOT, nbr->peerid, 0, NULL, 0);
537
538 nbr->dd_snapshot = 1; /* wait for IMSG_DB_END */
539 nbr->state = NBR_STA_SNAP;
540
541 return (0);
542 }
543
544 int
nbr_act_exchange_done(struct nbr * nbr)545 nbr_act_exchange_done(struct nbr *nbr)
546 {
547 if (nbr->dd_master)
548 stop_db_tx_timer(nbr);
549
550 if (ls_req_list_empty(nbr) && nbr->state == NBR_STA_XCHNG &&
551 nbr->dd_pending == 0) {
552 nbr->state = NBR_STA_FULL;
553 return (0);
554 }
555
556 nbr->state = NBR_STA_LOAD;
557
558 if (!ls_req_list_empty(nbr))
559 start_ls_req_tx_timer(nbr);
560
561 return (0);
562 }
563
564 int
nbr_act_adj_ok(struct nbr * nbr)565 nbr_act_adj_ok(struct nbr *nbr)
566 {
567 if (nbr_adj_ok(nbr)) {
568 if (nbr->state == NBR_STA_2_WAY)
569 return (nbr_act_eval(nbr));
570 } else {
571 nbr->state = NBR_STA_2_WAY;
572 return (nbr_act_clear_lists(nbr));
573 }
574
575 return (0);
576 }
577
578 int
nbr_act_restart_dd(struct nbr * nbr)579 nbr_act_restart_dd(struct nbr *nbr)
580 {
581 nbr_act_clear_lists(nbr);
582
583 if (!nbr_adj_ok(nbr)) {
584 nbr->state = NBR_STA_2_WAY;
585 return (0);
586 }
587
588 nbr->state = NBR_STA_XSTRT;
589 nbr->dd_master = 1;
590 nbr->dd_seq_num += arc4random() & 0xffff;
591 nbr->dd_pending = 0;
592
593 /* initial db negotiation */
594 start_db_tx_timer(nbr);
595
596 nbr_start_adj_timer(nbr);
597
598 return (0);
599 }
600
601 int
nbr_act_delete(struct nbr * nbr)602 nbr_act_delete(struct nbr *nbr)
603 {
604 struct timeval tv;
605
606 /* clear dr and bdr */
607 nbr->dr.s_addr = 0;
608 nbr->bdr.s_addr = 0;
609
610 if (nbr == nbr->iface->self)
611 return (0);
612
613 /* stop timers */
614 nbr_stop_itimer(nbr);
615
616 /* schedule kill timer */
617 timerclear(&tv);
618 tv.tv_sec = DEFAULT_NBR_TMOUT;
619
620 if (evtimer_add(&nbr->inactivity_timer, &tv)) {
621 log_warnx("nbr_act_delete: error scheduling "
622 "neighbor ID %s (%s) for removal",
623 inet_ntoa(nbr->id), nbr->iface->name);
624 }
625
626 return (nbr_act_clear_lists(nbr));
627 }
628
629 int
nbr_act_clear_lists(struct nbr * nbr)630 nbr_act_clear_lists(struct nbr *nbr)
631 {
632 /* stop timers */
633 stop_db_tx_timer(nbr);
634 stop_ls_req_tx_timer(nbr);
635
636 /* clear lists */
637 ls_retrans_list_clr(nbr);
638 db_sum_list_clr(nbr);
639 ls_req_list_clr(nbr);
640
641 return (0);
642 }
643
644 int
nbr_act_hello_check(struct nbr * nbr)645 nbr_act_hello_check(struct nbr *nbr)
646 {
647 log_debug("nbr_act_hello_check: neighbor ID %s (%s)",
648 inet_ntoa(nbr->id), nbr->iface->name);
649
650 return (-1);
651 }
652
653 struct ctl_nbr *
nbr_to_ctl(struct nbr * nbr)654 nbr_to_ctl(struct nbr *nbr)
655 {
656 static struct ctl_nbr nctl;
657 struct timeval tv, now, res;
658 struct lsa_entry *le;
659
660 memcpy(nctl.name, nbr->iface->name, sizeof(nctl.name));
661 memcpy(&nctl.id, &nbr->id, sizeof(nctl.id));
662 memcpy(&nctl.addr, &nbr->addr, sizeof(nctl.addr));
663 memcpy(&nctl.dr, &nbr->dr, sizeof(nctl.dr));
664 memcpy(&nctl.bdr, &nbr->bdr, sizeof(nctl.bdr));
665 memcpy(&nctl.area, &nbr->iface->area->id, sizeof(nctl.area));
666
667 /* this list is 99% of the time empty so that's OK for now */
668 nctl.db_sum_lst_cnt = 0;
669 TAILQ_FOREACH(le, &nbr->db_sum_list, entry)
670 nctl.db_sum_lst_cnt++;
671
672 nctl.ls_req_lst_cnt = nbr->ls_req_cnt;
673 nctl.ls_retrans_lst_cnt = nbr->ls_ret_cnt;
674
675 nctl.nbr_state = nbr->state;
676
677 /*
678 * We need to trick a bit to show the remote iface state.
679 * The idea is to print DR, BDR or DROther dependent on
680 * the type of the neighbor.
681 */
682 if (nbr->iface->dr == nbr)
683 nctl.iface_state = IF_STA_DR;
684 else if (nbr->iface->bdr == nbr)
685 nctl.iface_state = IF_STA_BACKUP;
686 else if (nbr->iface->state & IF_STA_MULTI)
687 nctl.iface_state = IF_STA_DROTHER;
688 else
689 nctl.iface_state = nbr->iface->state;
690
691 nctl.state_chng_cnt = nbr->stats.sta_chng;
692
693 nctl.priority = nbr->priority;
694 nctl.options = nbr->options;
695
696 gettimeofday(&now, NULL);
697 if (evtimer_pending(&nbr->inactivity_timer, &tv)) {
698 timersub(&tv, &now, &res);
699 if (nbr->state & NBR_STA_DOWN)
700 nctl.dead_timer = DEFAULT_NBR_TMOUT - res.tv_sec;
701 else
702 nctl.dead_timer = res.tv_sec;
703 } else
704 nctl.dead_timer = 0;
705
706 if (nbr->state == NBR_STA_FULL) {
707 nctl.uptime = now.tv_sec - nbr->uptime;
708 } else
709 nctl.uptime = 0;
710
711 return (&nctl);
712 }
713
714 struct lsa_hdr *
lsa_hdr_new(void)715 lsa_hdr_new(void)
716 {
717 struct lsa_hdr *lsa_hdr = NULL;
718
719 if ((lsa_hdr = calloc(1, sizeof(*lsa_hdr))) == NULL)
720 fatal("lsa_hdr_new");
721
722 return (lsa_hdr);
723 }
724