xref: /openbsd-src/usr.sbin/ospf6d/neighbor.c (revision 850e275390052b330d93020bf619a739a3c277ac)
1 /*	$OpenBSD: neighbor.c,v 1.6 2008/02/11 13:48:39 norby 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;
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,		NBR_STA_SNAP},
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,	NBR_STA_XSTRT},
77     {NBR_STA_FLOOD,	NBR_EVT_BAD_LS_REQ,	NBR_ACT_RESTRT_DD,	NBR_STA_XSTRT},
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
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, "
140 		    "event %s not expected in state %s",
141 		    inet_ntoa(nbr->id), nbr_event_names[event],
142 		    nbr_state_name(old_state));
143 		return (0);
144 	}
145 
146 	switch (nbr_fsm_tbl[i].action) {
147 	case NBR_ACT_RST_ITIMER:
148 		ret = nbr_act_reset_itimer(nbr);
149 		break;
150 	case NBR_ACT_STRT_ITIMER:
151 		ret = nbr_act_start_itimer(nbr);
152 		break;
153 	case NBR_ACT_EVAL:
154 		ret = nbr_act_eval(nbr);
155 		break;
156 	case NBR_ACT_SNAP:
157 		ret = nbr_act_snapshot(nbr);
158 		break;
159 	case NBR_ACT_SNAP_DONE:
160 		/* start db exchange */
161 		start_db_tx_timer(nbr);
162 		break;
163 	case NBR_ACT_XCHNG_DONE:
164 		ret = nbr_act_exchange_done(nbr);
165 		break;
166 	case NBR_ACT_ADJ_OK:
167 		ret = nbr_act_adj_ok(nbr);
168 		break;
169 	case NBR_ACT_RESTRT_DD:
170 		ret = nbr_act_restart_dd(nbr);
171 		break;
172 	case NBR_ACT_DEL:
173 		ret = nbr_act_delete(nbr);
174 		break;
175 	case NBR_ACT_CLR_LST:
176 		ret = nbr_act_clear_lists(nbr);
177 		break;
178 	case NBR_ACT_HELLO_CHK:
179 		ret = nbr_act_hello_check(nbr);
180 		break;
181 	case NBR_ACT_NOTHING:
182 		/* do nothing */
183 		break;
184 	}
185 
186 	if (ret) {
187 		log_warnx("nbr_fsm: error changing state for neighbor ID %s, "
188 		    "event %s, state %s", inet_ntoa(nbr->id),
189 		    nbr_event_names[event], nbr_state_name(old_state));
190 		return (-1);
191 	}
192 
193 	if (new_state != 0)
194 		nbr->state = new_state;
195 
196 	if (old_state != nbr->state) {
197 		nbr->stats.sta_chng++;
198 		/* state change inform RDE */
199 		ospfe_imsg_compose_rde(IMSG_NEIGHBOR_CHANGE,
200 		    nbr->peerid, 0, &new_state, sizeof(new_state));
201 
202 		if (old_state & NBR_STA_FULL || nbr->state & NBR_STA_FULL) {
203 			extern struct ospfd_conf        *oeconf; /* XXX */
204 			/*
205 			 * neighbor changed from/to FULL
206 			 * originate new rtr and net LSA
207 			 */
208 			area_track(area_find(oeconf, nbr->iface->area_id),
209 			    nbr->state);
210 			orig_rtr_lsa(nbr->iface);
211 			if (nbr->iface->state & IF_STA_DR)
212 				orig_net_lsa(nbr->iface);
213 
214 			gettimeofday(&now, NULL);
215 			nbr->uptime = now.tv_sec;
216 		}
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 from %s to %s",
224 		    nbr_event_names[event],
225 		    nbr_action_names[nbr_fsm_tbl[i].action],
226 		    inet_ntoa(nbr->id), 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);
231 		}
232 	}
233 
234 	return (ret);
235 }
236 
237 void
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 *
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 //XXX		nbr->addr.s_addr = iface->addr.s_addr;
305 		nbr->addr = iface->addr;
306 		nbr->priority = iface->priority;
307 	}
308 
309 	/* set event structures */
310 	evtimer_set(&nbr->inactivity_timer, nbr_itimer, nbr);
311 	evtimer_set(&nbr->db_tx_timer, db_tx_timer, nbr);
312 	evtimer_set(&nbr->lsreq_tx_timer, ls_req_tx_timer, nbr);
313 	evtimer_set(&nbr->ls_retrans_timer, ls_retrans_timer, nbr);
314 	evtimer_set(&nbr->adj_timer, nbr_adj_timer, nbr);
315 
316 	bzero(&rn, sizeof(rn));
317 	rn.id.s_addr = nbr->id.s_addr;
318 	rn.area_id.s_addr = nbr->iface->area_id.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
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 	LIST_REMOVE(nbr, entry);
350 	LIST_REMOVE(nbr, hash);
351 
352 	free(nbr);
353 }
354 
355 struct nbr *
356 nbr_find_peerid(u_int32_t peerid)
357 {
358 	struct nbr_head	*head;
359 	struct nbr	*nbr;
360 
361 	head = NBR_HASH(peerid);
362 
363 	LIST_FOREACH(nbr, head, hash) {
364 		if (nbr->peerid == peerid)
365 			return (nbr);
366 	}
367 
368 	return (NULL);
369 }
370 
371 struct nbr *
372 nbr_find_id(struct iface *iface, u_int32_t rtr_id)
373 {
374 	struct nbr	*nbr = NULL;
375 
376 	LIST_FOREACH(nbr, &iface->nbr_list, entry) {
377 		if (nbr->id.s_addr == rtr_id)
378 			return (nbr);
379 	}
380 
381 	return (NULL);
382 }
383 
384 /* timers */
385 /* ARGSUSED */
386 void
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
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
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
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 /* ARGSUSED */
429 void
430 nbr_adj_timer(int fd, short event, void *arg)
431 {
432 	struct nbr *nbr = arg;
433 
434 	if (nbr->state == NBR_STA_2_WAY)
435 		return ;
436 
437 	if (nbr->state & NBR_STA_ACTIVE && nbr->state != NBR_STA_FULL) {
438 		log_warnx("nbr_adj_timer: failed to form adjacency with %s",
439 		    inet_ntoa(nbr->id));
440 		nbr_fsm(nbr, NBR_EVT_ADJTMOUT);
441 	}
442 }
443 
444 void
445 nbr_start_adj_timer(struct nbr *nbr)
446 {
447 	struct timeval	tv;
448 
449 	timerclear(&tv);
450 	tv.tv_sec = DEFAULT_ADJ_TMOUT;
451 
452 	if (evtimer_add(&nbr->adj_timer, &tv) == -1)
453 		fatal("nbr_start_adj_timer");
454 }
455 
456 /* actions */
457 int
458 nbr_act_reset_itimer(struct nbr *nbr)
459 {
460 	nbr_reset_itimer(nbr);
461 
462 	return (0);
463 }
464 
465 int
466 nbr_act_start_itimer(struct nbr *nbr)
467 {
468 	nbr_start_itimer(nbr);
469 
470 	return (0);
471 }
472 
473 int
474 nbr_adj_ok(struct nbr *nbr)
475 {
476 	struct iface	*iface = nbr->iface;
477 
478 	switch (iface->type) {
479 	case IF_TYPE_POINTOPOINT:
480 	case IF_TYPE_VIRTUALLINK:
481 	case IF_TYPE_POINTOMULTIPOINT:
482 		/* always ok */
483 		break;
484 	case IF_TYPE_BROADCAST:
485 	case IF_TYPE_NBMA:
486 		/*
487 		 * if neighbor is dr, bdr or router self is dr or bdr
488 		 * start forming adjacency
489 		 */
490 		if (iface->dr == nbr || iface->bdr == nbr ||
491 		    iface->state & IF_STA_DRORBDR)
492 			break;
493 		return (0);
494 	default:
495 		fatalx("nbr_adj_ok: unknown interface type");
496 	}
497 	return (1);
498 }
499 
500 int
501 nbr_act_eval(struct nbr *nbr)
502 {
503 	if (!nbr_adj_ok(nbr)) {
504 		nbr->state = NBR_STA_2_WAY;
505 		return (0);
506 	}
507 
508 	nbr->state = NBR_STA_XSTRT;
509 	nbr->dd_master = 1;
510 	nbr->dd_seq_num++;	/* as per RFC */
511 	nbr->dd_pending = 0;
512 	/* initial db negotiation */
513 	start_db_tx_timer(nbr);
514 
515 	nbr_start_adj_timer(nbr);
516 
517 	return (0);
518 }
519 
520 int
521 nbr_act_snapshot(struct nbr *nbr)
522 {
523 	stop_db_tx_timer(nbr);
524 
525 	ospfe_imsg_compose_rde(IMSG_DB_SNAPSHOT, nbr->peerid, 0, NULL, 0);
526 
527 	return (0);
528 }
529 
530 int
531 nbr_act_exchange_done(struct nbr *nbr)
532 {
533 	if (nbr->dd_master)
534 		stop_db_tx_timer(nbr);
535 
536 	if (ls_req_list_empty(nbr) && nbr->state == NBR_STA_XCHNG &&
537 	    nbr->dd_pending == 0) {
538 		nbr->state = NBR_STA_FULL;
539 		return (0);
540 	}
541 
542 	nbr->state = NBR_STA_LOAD;
543 
544 	if (!ls_req_list_empty(nbr))
545 		start_ls_req_tx_timer(nbr);
546 
547 	return (0);
548 }
549 
550 int
551 nbr_act_adj_ok(struct nbr *nbr)
552 {
553 	if (nbr_adj_ok(nbr)) {
554 		if (nbr->state == NBR_STA_2_WAY)
555 			return (nbr_act_eval(nbr));
556 	} else {
557 		nbr->state = NBR_STA_2_WAY;
558 		return (nbr_act_clear_lists(nbr));
559 	}
560 
561 	return (0);
562 }
563 
564 int
565 nbr_act_restart_dd(struct nbr *nbr)
566 {
567 	nbr_act_clear_lists(nbr);
568 
569 	if (!nbr_adj_ok(nbr)) {
570 		nbr->state = NBR_STA_2_WAY;
571 		return (0);
572 	}
573 
574 	nbr->state = NBR_STA_XSTRT;
575 	nbr->dd_master = 1;
576 	nbr->dd_seq_num += arc4random() & 0xffff;
577 	nbr->dd_pending = 0;
578 
579 	/* initial db negotiation */
580 	start_db_tx_timer(nbr);
581 
582 	nbr_start_adj_timer(nbr);
583 
584 	return (0);
585 }
586 
587 int
588 nbr_act_delete(struct nbr *nbr)
589 {
590 	struct timeval	tv;
591 
592 	if (nbr == nbr->iface->self)
593 		return (0);
594 
595 	/* stop timers */
596 	nbr_stop_itimer(nbr);
597 
598 	/* clear dr and bdr */
599 	nbr->dr.s_addr = 0;
600 	nbr->bdr.s_addr = 0;
601 
602 	/* schedule kill timer */
603 	timerclear(&tv);
604 	tv.tv_sec = DEFAULT_NBR_TMOUT;
605 
606 	if (evtimer_add(&nbr->inactivity_timer, &tv)) {
607 		log_warnx("nbr_act_delete: error scheduling neighbor ID %s "
608 		    "for removal", inet_ntoa(nbr->id));
609 	}
610 
611 	return (nbr_act_clear_lists(nbr));
612 }
613 
614 int
615 nbr_act_clear_lists(struct nbr *nbr)
616 {
617 	/* stop timers */
618 	stop_db_tx_timer(nbr);
619 	stop_ls_req_tx_timer(nbr);
620 
621 	/* clear lists */
622 	ls_retrans_list_clr(nbr);
623 	db_sum_list_clr(nbr);
624 	ls_req_list_clr(nbr);
625 
626 	return (0);
627 }
628 
629 int
630 nbr_act_hello_check(struct nbr *nbr)
631 {
632 	log_debug("nbr_act_hello_check: neighbor ID %s", inet_ntoa(nbr->id));
633 
634 	return (-1);
635 }
636 
637 struct ctl_nbr *
638 nbr_to_ctl(struct nbr *nbr)
639 {
640 	static struct ctl_nbr	 nctl;
641 	struct timeval		 tv, now, res;
642 	struct lsa_entry	*le;
643 
644 	memcpy(nctl.name, nbr->iface->name, sizeof(nctl.name));
645 	memcpy(&nctl.id, &nbr->id, sizeof(nctl.id));
646 	memcpy(&nctl.addr, &nbr->addr, sizeof(nctl.addr));
647 	memcpy(&nctl.dr, &nbr->dr, sizeof(nctl.dr));
648 	memcpy(&nctl.bdr, &nbr->bdr, sizeof(nctl.bdr));
649 	memcpy(&nctl.area, &nbr->iface->area_id, sizeof(nctl.area));
650 
651 	/* this list is 99% of the time empty so that's OK for now */
652 	nctl.db_sum_lst_cnt = 0;
653 	TAILQ_FOREACH(le, &nbr->db_sum_list, entry)
654 		nctl.db_sum_lst_cnt++;
655 
656 	nctl.ls_req_lst_cnt = nbr->ls_req_cnt;
657 	nctl.ls_retrans_lst_cnt = nbr->ls_ret_cnt;
658 
659 	nctl.nbr_state = nbr->state;
660 
661 	/*
662 	 * We need to trick a bit to show the remote iface state.
663 	 * The idea is to print DR, BDR or DROther dependent on
664 	 * the type of the neighbor.
665 	 */
666 	if (nbr->iface->dr == nbr)
667 		nctl.iface_state = IF_STA_DR;
668 	else if (nbr->iface->bdr == nbr)
669 		nctl.iface_state = IF_STA_BACKUP;
670 	else if (nbr->iface->state & IF_STA_MULTI)
671 		nctl.iface_state = IF_STA_DROTHER;
672 	else
673 		nctl.iface_state = nbr->iface->state;
674 
675 	nctl.state_chng_cnt = nbr->stats.sta_chng;
676 
677 	nctl.priority = nbr->priority;
678 	nctl.options = nbr->options;
679 
680 	gettimeofday(&now, NULL);
681 	if (evtimer_pending(&nbr->inactivity_timer, &tv)) {
682 		timersub(&tv, &now, &res);
683 		if (nbr->state & NBR_STA_DOWN)
684 			nctl.dead_timer = DEFAULT_NBR_TMOUT - res.tv_sec;
685 		else
686 			nctl.dead_timer = res.tv_sec;
687 	} else
688 		nctl.dead_timer = 0;
689 
690 	if (nbr->state == NBR_STA_FULL) {
691 		nctl.uptime = now.tv_sec - nbr->uptime;
692 	} else
693 		nctl.uptime = 0;
694 
695 	return (&nctl);
696 }
697 
698 struct lsa_hdr *
699 lsa_hdr_new(void)
700 {
701 	struct lsa_hdr	*lsa_hdr = NULL;
702 
703 	if ((lsa_hdr = calloc(1, sizeof(*lsa_hdr))) == NULL)
704 		fatal("lsa_hdr_new");
705 
706 	return (lsa_hdr);
707 }
708