xref: /openbsd/usr.sbin/ospf6d/neighbor.c (revision 5b133f3f)
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