1 /* $OpenBSD: neighbor.c,v 1.51 2023/03/08 04:43:14 guenther Exp $ */
2
3 /*
4 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
5 * Copyright (c) 2004, 2005 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 "ospfd.h"
36 #include "ospf.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 /* state change inform RDE */
201 ospfe_imsg_compose_rde(IMSG_NEIGHBOR_CHANGE,
202 nbr->peerid, 0, &nbr->state, sizeof(nbr->state));
203
204 if (old_state & NBR_STA_FULL || nbr->state & NBR_STA_FULL) {
205 /*
206 * neighbor changed from/to FULL
207 * originate new rtr and net LSA
208 */
209 orig_rtr_lsa(nbr->iface->area);
210 if (nbr->iface->state & IF_STA_DR)
211 orig_net_lsa(nbr->iface);
212
213 gettimeofday(&now, NULL);
214 nbr->uptime = now.tv_sec;
215 }
216
217 /* bidirectional communication lost */
218 if (old_state & ~NBR_STA_PRELIM && nbr->state & NBR_STA_PRELIM)
219 if_fsm(nbr->iface, IF_EVT_NBR_CHNG);
220
221 log_debug("nbr_fsm: event %s resulted in action %s and "
222 "changing state for neighbor ID %s (%s) from %s to %s",
223 nbr_event_names[event],
224 nbr_action_names[nbr_fsm_tbl[i].action],
225 inet_ntoa(nbr->id), nbr->iface->name,
226 nbr_state_name(old_state),
227 nbr_state_name(nbr->state));
228
229 if (nbr->iface->type == IF_TYPE_VIRTUALLINK) {
230 orig_rtr_lsa(nbr->iface->area);
231 }
232 }
233
234 return (ret);
235 }
236
237 void
nbr_init(u_int32_t hashsize)238 nbr_init(u_int32_t hashsize)
239 {
240 struct nbr_head *head;
241 struct nbr *nbr;
242 u_int32_t hs, i;
243
244 for (hs = 1; hs < hashsize; hs <<= 1)
245 ;
246 nbrtable.hashtbl = calloc(hs, sizeof(struct nbr_head));
247 if (nbrtable.hashtbl == NULL)
248 fatal("nbr_init");
249
250 for (i = 0; i < hs; i++)
251 LIST_INIT(&nbrtable.hashtbl[i]);
252
253 nbrtable.hashmask = hs - 1;
254
255 /* allocate a dummy neighbor used for self originated AS ext routes */
256 if ((nbr = calloc(1, sizeof(*nbr))) == NULL)
257 fatal("nbr_init");
258
259 nbr->id.s_addr = ospfe_router_id();
260 nbr->state = NBR_STA_DOWN;
261 nbr->peerid = NBR_IDSELF;
262 head = NBR_HASH(nbr->peerid);
263 LIST_INSERT_HEAD(head, nbr, hash);
264
265 TAILQ_INIT(&nbr->ls_retrans_list);
266 TAILQ_INIT(&nbr->db_sum_list);
267 TAILQ_INIT(&nbr->ls_req_list);
268 }
269
270 struct nbr *
nbr_new(u_int32_t nbr_id,struct iface * iface,int self)271 nbr_new(u_int32_t nbr_id, struct iface *iface, int self)
272 {
273 struct nbr_head *head;
274 struct nbr *nbr;
275 struct rde_nbr rn;
276
277 if ((nbr = calloc(1, sizeof(*nbr))) == NULL)
278 fatal("nbr_new");
279
280 nbr->state = NBR_STA_DOWN;
281 nbr->dd_master = 1;
282 nbr->dd_seq_num = arc4random(); /* RFC: some unique value */
283 nbr->id.s_addr = nbr_id;
284
285 /* get next unused peerid */
286 while (nbr_find_peerid(++peercnt))
287 ;
288 nbr->peerid = peercnt;
289 head = NBR_HASH(nbr->peerid);
290 LIST_INSERT_HEAD(head, nbr, hash);
291
292 /* add to peer list */
293 nbr->iface = iface;
294 LIST_INSERT_HEAD(&iface->nbr_list, nbr, entry);
295
296 TAILQ_INIT(&nbr->ls_retrans_list);
297 TAILQ_INIT(&nbr->db_sum_list);
298 TAILQ_INIT(&nbr->ls_req_list);
299
300 nbr->ls_req = NULL;
301
302 if (self) {
303 nbr->state = NBR_STA_FULL;
304 nbr->addr.s_addr = iface->addr.s_addr;
305 nbr->priority = iface->priority;
306 }
307
308 /* set event structures */
309 evtimer_set(&nbr->inactivity_timer, nbr_itimer, nbr);
310 evtimer_set(&nbr->db_tx_timer, db_tx_timer, nbr);
311 evtimer_set(&nbr->lsreq_tx_timer, ls_req_tx_timer, nbr);
312 evtimer_set(&nbr->ls_retrans_timer, ls_retrans_timer, nbr);
313 evtimer_set(&nbr->adj_timer, nbr_adj_timer, nbr);
314
315 bzero(&rn, sizeof(rn));
316 rn.id.s_addr = nbr->id.s_addr;
317 rn.area_id.s_addr = nbr->iface->area->id.s_addr;
318 rn.addr.s_addr = nbr->addr.s_addr;
319 rn.ifindex = nbr->iface->ifindex;
320 rn.state = nbr->state;
321 rn.self = self;
322 ospfe_imsg_compose_rde(IMSG_NEIGHBOR_UP, nbr->peerid, 0, &rn,
323 sizeof(rn));
324
325 return (nbr);
326 }
327
328 void
nbr_del(struct nbr * nbr)329 nbr_del(struct nbr *nbr)
330 {
331 ospfe_imsg_compose_rde(IMSG_NEIGHBOR_DOWN, nbr->peerid, 0, NULL, 0);
332
333 if (evtimer_pending(&nbr->inactivity_timer, NULL))
334 evtimer_del(&nbr->inactivity_timer);
335 if (evtimer_pending(&nbr->db_tx_timer, NULL))
336 evtimer_del(&nbr->db_tx_timer);
337 if (evtimer_pending(&nbr->lsreq_tx_timer, NULL))
338 evtimer_del(&nbr->lsreq_tx_timer);
339 if (evtimer_pending(&nbr->ls_retrans_timer, NULL))
340 evtimer_del(&nbr->ls_retrans_timer);
341 if (evtimer_pending(&nbr->adj_timer, NULL))
342 evtimer_del(&nbr->adj_timer);
343
344 /* clear lists */
345 ls_retrans_list_clr(nbr);
346 db_sum_list_clr(nbr);
347 ls_req_list_clr(nbr);
348
349 if (nbr->peerid != NBR_IDSELF)
350 LIST_REMOVE(nbr, entry);
351 LIST_REMOVE(nbr, hash);
352
353 free(nbr);
354 }
355
356 struct nbr *
nbr_find_peerid(u_int32_t peerid)357 nbr_find_peerid(u_int32_t peerid)
358 {
359 struct nbr_head *head;
360 struct nbr *nbr;
361
362 head = NBR_HASH(peerid);
363
364 LIST_FOREACH(nbr, head, hash) {
365 if (nbr->peerid == peerid)
366 return (nbr);
367 }
368
369 return (NULL);
370 }
371
372 struct nbr *
nbr_find_id(struct iface * iface,u_int32_t rtr_id)373 nbr_find_id(struct iface *iface, u_int32_t rtr_id)
374 {
375 struct nbr *nbr = NULL;
376
377 LIST_FOREACH(nbr, &iface->nbr_list, entry) {
378 if (nbr->id.s_addr == rtr_id)
379 return (nbr);
380 }
381
382 return (NULL);
383 }
384
385 /* timers */
386 void
nbr_itimer(int fd,short event,void * arg)387 nbr_itimer(int fd, short event, void *arg)
388 {
389 struct nbr *nbr = arg;
390
391 if (nbr->state == NBR_STA_DOWN)
392 nbr_del(nbr);
393 else
394 nbr_fsm(nbr, NBR_EVT_ITIMER);
395 }
396
397 void
nbr_start_itimer(struct nbr * nbr)398 nbr_start_itimer(struct nbr *nbr)
399 {
400 struct timeval tv;
401
402 timerclear(&tv);
403 tv.tv_sec = nbr->iface->dead_interval;
404
405 if (evtimer_add(&nbr->inactivity_timer, &tv) == -1)
406 fatal("nbr_start_itimer");
407 }
408
409 void
nbr_stop_itimer(struct nbr * nbr)410 nbr_stop_itimer(struct nbr *nbr)
411 {
412 if (evtimer_del(&nbr->inactivity_timer) == -1)
413 fatal("nbr_stop_itimer");
414 }
415
416 void
nbr_reset_itimer(struct nbr * nbr)417 nbr_reset_itimer(struct nbr *nbr)
418 {
419 struct timeval tv;
420
421 timerclear(&tv);
422 tv.tv_sec = nbr->iface->dead_interval;
423
424 if (evtimer_add(&nbr->inactivity_timer, &tv) == -1)
425 fatal("nbr_reset_itimer");
426 }
427
428 void
nbr_adj_timer(int fd,short event,void * arg)429 nbr_adj_timer(int fd, short event, void *arg)
430 {
431 struct nbr *nbr = arg;
432
433 if (!(nbr->state & NBR_STA_ADJFORM))
434 return;
435
436 if (nbr->state & NBR_STA_ACTIVE && nbr->state != NBR_STA_FULL) {
437 log_warnx("nbr_adj_timer: failed to form adjacency with %s "
438 "on interface %s", inet_ntoa(nbr->id), nbr->iface->name);
439 nbr_fsm(nbr, NBR_EVT_ADJTMOUT);
440 }
441 }
442
443 void
nbr_start_adj_timer(struct nbr * nbr)444 nbr_start_adj_timer(struct nbr *nbr)
445 {
446 struct timeval tv;
447
448 timerclear(&tv);
449 tv.tv_sec = DEFAULT_ADJ_TMOUT;
450
451 if (evtimer_add(&nbr->adj_timer, &tv) == -1)
452 fatal("nbr_start_adj_timer");
453 }
454
455 /* actions */
456 int
nbr_act_reset_itimer(struct nbr * nbr)457 nbr_act_reset_itimer(struct nbr *nbr)
458 {
459 nbr_reset_itimer(nbr);
460
461 return (0);
462 }
463
464 int
nbr_act_start_itimer(struct nbr * nbr)465 nbr_act_start_itimer(struct nbr *nbr)
466 {
467 nbr_start_itimer(nbr);
468
469 return (0);
470 }
471
472 int
nbr_adj_ok(struct nbr * nbr)473 nbr_adj_ok(struct nbr *nbr)
474 {
475 struct iface *iface = nbr->iface;
476
477 switch (iface->type) {
478 case IF_TYPE_POINTOPOINT:
479 case IF_TYPE_VIRTUALLINK:
480 case IF_TYPE_POINTOMULTIPOINT:
481 /* always ok */
482 break;
483 case IF_TYPE_BROADCAST:
484 case IF_TYPE_NBMA:
485 /*
486 * if neighbor is dr, bdr or router self is dr or bdr
487 * start forming adjacency
488 */
489 if (iface->dr == nbr || iface->bdr == nbr ||
490 iface->state & IF_STA_DRORBDR)
491 break;
492 return (0);
493 default:
494 fatalx("nbr_adj_ok: unknown interface type");
495 }
496 return (1);
497 }
498
499 int
nbr_act_eval(struct nbr * nbr)500 nbr_act_eval(struct nbr *nbr)
501 {
502 if (!nbr_adj_ok(nbr)) {
503 nbr->state = NBR_STA_2_WAY;
504 return (0);
505 }
506
507 nbr->state = NBR_STA_XSTRT;
508 nbr->dd_master = 1;
509 nbr->dd_seq_num++; /* as per RFC */
510 nbr->dd_pending = 0;
511 /* initial db negotiation */
512 start_db_tx_timer(nbr);
513
514 nbr_start_adj_timer(nbr);
515
516 return (0);
517 }
518
519 int
nbr_act_snapshot(struct nbr * nbr)520 nbr_act_snapshot(struct nbr *nbr)
521 {
522 stop_db_tx_timer(nbr);
523
524 /* we need to wait for the old snapshot to finish */
525 if (nbr->dd_snapshot) {
526 log_debug("nbr_act_snapshot: giving up, old snapshot running "
527 "for neighbor ID %s (%s)", inet_ntoa(nbr->id),
528 nbr->iface->name);
529 return (nbr_act_restart_dd(nbr));
530 }
531 ospfe_imsg_compose_rde(IMSG_NEIGHBOR_CAPA, nbr->peerid, 0,
532 &nbr->capa_options, sizeof(nbr->capa_options));
533 ospfe_imsg_compose_rde(IMSG_DB_SNAPSHOT, nbr->peerid, 0, NULL, 0);
534
535 nbr->dd_snapshot = 1; /* wait for IMSG_DB_END */
536 nbr->state = NBR_STA_SNAP;
537
538 return (0);
539 }
540
541 int
nbr_act_exchange_done(struct nbr * nbr)542 nbr_act_exchange_done(struct nbr *nbr)
543 {
544 if (nbr->dd_master)
545 stop_db_tx_timer(nbr);
546
547 if (ls_req_list_empty(nbr) && nbr->state == NBR_STA_XCHNG &&
548 nbr->dd_pending == 0) {
549 nbr->state = NBR_STA_FULL;
550 return (0);
551 }
552
553 nbr->state = NBR_STA_LOAD;
554
555 if (!ls_req_list_empty(nbr))
556 start_ls_req_tx_timer(nbr);
557
558 return (0);
559 }
560
561 int
nbr_act_adj_ok(struct nbr * nbr)562 nbr_act_adj_ok(struct nbr *nbr)
563 {
564 if (nbr_adj_ok(nbr)) {
565 if (nbr->state == NBR_STA_2_WAY)
566 return (nbr_act_eval(nbr));
567 } else {
568 nbr->state = NBR_STA_2_WAY;
569 return (nbr_act_clear_lists(nbr));
570 }
571
572 return (0);
573 }
574
575 int
nbr_act_restart_dd(struct nbr * nbr)576 nbr_act_restart_dd(struct nbr *nbr)
577 {
578 nbr_act_clear_lists(nbr);
579
580 if (!nbr_adj_ok(nbr)) {
581 nbr->state = NBR_STA_2_WAY;
582 return (0);
583 }
584
585 nbr->state = NBR_STA_XSTRT;
586 nbr->dd_master = 1;
587 nbr->dd_seq_num += arc4random() & 0xffff;
588 nbr->dd_pending = 0;
589
590 /* initial db negotiation */
591 start_db_tx_timer(nbr);
592
593 nbr_start_adj_timer(nbr);
594
595 return (0);
596 }
597
598 int
nbr_act_delete(struct nbr * nbr)599 nbr_act_delete(struct nbr *nbr)
600 {
601 struct timeval tv;
602
603 /* clear dr and bdr */
604 nbr->dr.s_addr = 0;
605 nbr->bdr.s_addr = 0;
606
607 if (nbr == nbr->iface->self)
608 return (0);
609
610 /* stop timers */
611 nbr_stop_itimer(nbr);
612
613 /* XXX reset crypt_seq_num will allow replay attacks. */
614 nbr->crypt_seq_num = 0;
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 | nbr->capa_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