xref: /openbsd/usr.sbin/ospfd/neighbor.c (revision a302a2ce)
1 /*	$OpenBSD: neighbor.c,v 1.34 2007/01/24 14:08:28 claudio 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;
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 };
116 
117 int
118 nbr_fsm(struct nbr *nbr, enum nbr_event event)
119 {
120 	struct timeval	now;
121 	int		old_state;
122 	int		new_state = 0;
123 	int		i, ret = 0;
124 
125 	if (nbr == nbr->iface->self)
126 		return (0);
127 
128 	old_state = nbr->state;
129 	for (i = 0; nbr_fsm_tbl[i].state != -1; i++)
130 		if ((nbr_fsm_tbl[i].state & old_state) &&
131 		    (nbr_fsm_tbl[i].event == event)) {
132 			new_state = nbr_fsm_tbl[i].new_state;
133 			break;
134 		}
135 
136 	if (nbr_fsm_tbl[i].state == -1) {
137 		/* event outside of the defined fsm, ignore it. */
138 		log_warnx("nbr_fsm: neighbor ID %s, "
139 		    "event %s not expected in state %s",
140 		    inet_ntoa(nbr->id), nbr_event_names[event],
141 		    nbr_state_name(old_state));
142 		return (0);
143 	}
144 
145 	switch (nbr_fsm_tbl[i].action) {
146 	case NBR_ACT_RST_ITIMER:
147 		ret = nbr_act_reset_itimer(nbr);
148 		break;
149 	case NBR_ACT_STRT_ITIMER:
150 		ret = nbr_act_start_itimer(nbr);
151 		break;
152 	case NBR_ACT_EVAL:
153 		ret = nbr_act_eval(nbr);
154 		break;
155 	case NBR_ACT_SNAP:
156 		ret = nbr_act_snapshot(nbr);
157 		break;
158 	case NBR_ACT_SNAP_DONE:
159 		/* start db exchange */
160 		start_db_tx_timer(nbr);
161 		break;
162 	case NBR_ACT_XCHNG_DONE:
163 		ret = nbr_act_exchange_done(nbr);
164 		break;
165 	case NBR_ACT_ADJ_OK:
166 		ret = nbr_act_adj_ok(nbr);
167 		break;
168 	case NBR_ACT_RESTRT_DD:
169 		ret = nbr_act_restart_dd(nbr);
170 		break;
171 	case NBR_ACT_DEL:
172 		ret = nbr_act_delete(nbr);
173 		break;
174 	case NBR_ACT_CLR_LST:
175 		ret = nbr_act_clear_lists(nbr);
176 		break;
177 	case NBR_ACT_HELLO_CHK:
178 		ret = nbr_act_hello_check(nbr);
179 		break;
180 	case NBR_ACT_NOTHING:
181 		/* do nothing */
182 		break;
183 	}
184 
185 	if (ret) {
186 		log_warnx("nbr_fsm: error changing state for neighbor ID %s, "
187 		    "event %s, state %s", inet_ntoa(nbr->id),
188 		    nbr_event_names[event], nbr_state_name(old_state));
189 		return (-1);
190 	}
191 
192 	if (new_state != 0)
193 		nbr->state = new_state;
194 
195 	if (old_state != nbr->state) {
196 		nbr->stats.sta_chng++;
197 		/* state change inform RDE */
198 		ospfe_imsg_compose_rde(IMSG_NEIGHBOR_CHANGE,
199 		    nbr->peerid, 0, &new_state, sizeof(new_state));
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 			area_track(nbr->iface->area, nbr->state);
207 			orig_rtr_lsa(nbr->iface->area);
208 			if (nbr->iface->state & IF_STA_DR)
209 				orig_net_lsa(nbr->iface);
210 
211 			gettimeofday(&now, NULL);
212 			nbr->uptime = now.tv_sec;
213 		}
214 
215 		/* bidirectional communication lost */
216 		if (old_state & ~NBR_STA_PRELIM && nbr->state & NBR_STA_PRELIM)
217 			if_fsm(nbr->iface, IF_EVT_NBR_CHNG);
218 
219 		log_debug("nbr_fsm: event %s resulted in action %s and "
220 		    "changing state for neighbor ID %s from %s to %s",
221 		    nbr_event_names[event],
222 		    nbr_action_names[nbr_fsm_tbl[i].action],
223 		    inet_ntoa(nbr->id), nbr_state_name(old_state),
224 		    nbr_state_name(nbr->state));
225 
226 		if (nbr->iface->type == IF_TYPE_VIRTUALLINK) {
227 			orig_rtr_lsa(nbr->iface->area);
228 		}
229 	}
230 
231 	return (ret);
232 }
233 
234 void
235 nbr_init(u_int32_t hashsize)
236 {
237 	struct nbr_head	*head;
238 	struct nbr	*nbr;
239 	u_int32_t        hs, i;
240 
241 	for (hs = 1; hs < hashsize; hs <<= 1)
242 		;
243 	nbrtable.hashtbl = calloc(hs, sizeof(struct nbr_head));
244 	if (nbrtable.hashtbl == NULL)
245 		fatal("nbr_init");
246 
247 	for (i = 0; i < hs; i++)
248 		LIST_INIT(&nbrtable.hashtbl[i]);
249 
250 	nbrtable.hashmask = hs - 1;
251 
252 	/* allocate a dummy neighbor used for self originated AS ext routes */
253 	if ((nbr = calloc(1, sizeof(*nbr))) == NULL)
254 		fatal("nbr_init");
255 
256 	nbr->id.s_addr = ospfe_router_id();
257 	nbr->state = NBR_STA_DOWN;
258 	nbr->peerid = NBR_IDSELF;
259 	head = NBR_HASH(nbr->peerid);
260 	LIST_INSERT_HEAD(head, nbr, hash);
261 
262 	TAILQ_INIT(&nbr->ls_retrans_list);
263 	TAILQ_INIT(&nbr->db_sum_list);
264 	TAILQ_INIT(&nbr->ls_req_list);
265 }
266 
267 struct nbr *
268 nbr_new(u_int32_t nbr_id, struct iface *iface, int self)
269 {
270 	struct nbr_head	*head;
271 	struct nbr	*nbr;
272 	struct rde_nbr	 rn;
273 
274 	if ((nbr = calloc(1, sizeof(*nbr))) == NULL)
275 		fatal("nbr_new");
276 
277 	nbr->state = NBR_STA_DOWN;
278 	nbr->master = 1;
279 	nbr->dd_seq_num = arc4random();	/* RFC: some unique value */
280 	nbr->id.s_addr = nbr_id;
281 
282 	/* get next unused peerid */
283 	while (nbr_find_peerid(++peercnt))
284 		;
285 	nbr->peerid = peercnt;
286 	head = NBR_HASH(nbr->peerid);
287 	LIST_INSERT_HEAD(head, nbr, hash);
288 
289 	/* add to peer list */
290 	nbr->iface = iface;
291 	LIST_INSERT_HEAD(&iface->nbr_list, nbr, entry);
292 
293 	TAILQ_INIT(&nbr->ls_retrans_list);
294 	TAILQ_INIT(&nbr->db_sum_list);
295 	TAILQ_INIT(&nbr->ls_req_list);
296 
297 	nbr->ls_req = NULL;
298 
299 	if (self) {
300 		nbr->state = NBR_STA_FULL;
301 		nbr->addr.s_addr = iface->addr.s_addr;
302 		nbr->priority = iface->priority;
303 	}
304 
305 	/* set event structures */
306 	evtimer_set(&nbr->inactivity_timer, nbr_itimer, nbr);
307 	evtimer_set(&nbr->db_tx_timer, db_tx_timer, nbr);
308 	evtimer_set(&nbr->lsreq_tx_timer, ls_req_tx_timer, nbr);
309 	evtimer_set(&nbr->ls_retrans_timer, ls_retrans_timer, nbr);
310 	evtimer_set(&nbr->adj_timer, nbr_adj_timer, nbr);
311 
312 	bzero(&rn, sizeof(rn));
313 	rn.id.s_addr = nbr->id.s_addr;
314 	rn.area_id.s_addr = nbr->iface->area->id.s_addr;
315 	rn.state = nbr->state;
316 	rn.self = self;
317 	ospfe_imsg_compose_rde(IMSG_NEIGHBOR_UP, nbr->peerid, 0, &rn,
318 	    sizeof(rn));
319 
320 	return (nbr);
321 }
322 
323 void
324 nbr_del(struct nbr *nbr)
325 {
326 	ospfe_imsg_compose_rde(IMSG_NEIGHBOR_DOWN, nbr->peerid, 0, NULL, 0);
327 
328 	if (evtimer_pending(&nbr->inactivity_timer, NULL))
329 		evtimer_del(&nbr->inactivity_timer);
330 	if (evtimer_pending(&nbr->db_tx_timer, NULL))
331 		evtimer_del(&nbr->db_tx_timer);
332 	if (evtimer_pending(&nbr->lsreq_tx_timer, NULL))
333 		evtimer_del(&nbr->lsreq_tx_timer);
334 	if (evtimer_pending(&nbr->ls_retrans_timer, NULL))
335 		evtimer_del(&nbr->ls_retrans_timer);
336 	if (evtimer_pending(&nbr->adj_timer, NULL))
337 		evtimer_del(&nbr->adj_timer);
338 
339 	/* clear lists */
340 	ls_retrans_list_clr(nbr);
341 	db_sum_list_clr(nbr);
342 	ls_req_list_clr(nbr);
343 
344 	LIST_REMOVE(nbr, entry);
345 	LIST_REMOVE(nbr, hash);
346 
347 	free(nbr);
348 }
349 
350 struct nbr *
351 nbr_find_peerid(u_int32_t peerid)
352 {
353 	struct nbr_head	*head;
354 	struct nbr	*nbr;
355 
356 	head = NBR_HASH(peerid);
357 
358 	LIST_FOREACH(nbr, head, hash) {
359 		if (nbr->peerid == peerid)
360 			return (nbr);
361 	}
362 
363 	return (NULL);
364 }
365 
366 struct nbr *
367 nbr_find_id(struct iface *iface, u_int32_t rtr_id)
368 {
369 	struct nbr	*nbr = NULL;
370 
371 	LIST_FOREACH(nbr, &iface->nbr_list, entry) {
372 		if (nbr->id.s_addr == rtr_id)
373 			return (nbr);
374 	}
375 
376 	return (NULL);
377 }
378 
379 /* timers */
380 /* ARGSUSED */
381 void
382 nbr_itimer(int fd, short event, void *arg)
383 {
384 	struct nbr *nbr = arg;
385 
386 	if (nbr->state == NBR_STA_DOWN)
387 		nbr_del(nbr);
388 	else
389 		nbr_fsm(nbr, NBR_EVT_ITIMER);
390 }
391 
392 void
393 nbr_start_itimer(struct nbr *nbr)
394 {
395 	struct timeval	tv;
396 
397 	timerclear(&tv);
398 	tv.tv_sec = nbr->iface->dead_interval;
399 
400 	if (evtimer_add(&nbr->inactivity_timer, &tv) == -1)
401 		fatal("nbr_start_itimer");
402 }
403 
404 void
405 nbr_stop_itimer(struct nbr *nbr)
406 {
407 	if (evtimer_del(&nbr->inactivity_timer) == -1)
408 		fatal("nbr_stop_itimer");
409 }
410 
411 void
412 nbr_reset_itimer(struct nbr *nbr)
413 {
414 	struct timeval	tv;
415 
416 	timerclear(&tv);
417 	tv.tv_sec = nbr->iface->dead_interval;
418 
419 	if (evtimer_add(&nbr->inactivity_timer, &tv) == -1)
420 		fatal("nbr_reset_itimer");
421 }
422 
423 /* ARGSUSED */
424 void
425 nbr_adj_timer(int fd, short event, void *arg)
426 {
427 	struct nbr *nbr = arg;
428 
429 	if (nbr->state == NBR_STA_2_WAY)
430 		return ;
431 
432 	if (nbr->state & NBR_STA_ACTIVE && nbr->state != NBR_STA_FULL) {
433 		log_warnx("nbr_adj_timer: failed to form adjacency with %s",
434 		    inet_ntoa(nbr->id));
435 		nbr_fsm(nbr, NBR_EVT_ADJTMOUT);
436 	}
437 }
438 
439 void
440 nbr_start_adj_timer(struct nbr *nbr)
441 {
442 	struct timeval	tv;
443 
444 	timerclear(&tv);
445 	tv.tv_sec = DEFAULT_ADJ_TMOUT;
446 
447 	if (evtimer_add(&nbr->adj_timer, &tv) == -1)
448 		fatal("nbr_start_adj_timer");
449 }
450 
451 /* actions */
452 int
453 nbr_act_reset_itimer(struct nbr *nbr)
454 {
455 	nbr_reset_itimer(nbr);
456 
457 	return (0);
458 }
459 
460 int
461 nbr_act_start_itimer(struct nbr *nbr)
462 {
463 	nbr_start_itimer(nbr);
464 
465 	return (0);
466 }
467 
468 int
469 nbr_adj_ok(struct nbr *nbr)
470 {
471 	struct iface	*iface = nbr->iface;
472 
473 	switch (iface->type) {
474 	case IF_TYPE_POINTOPOINT:
475 	case IF_TYPE_VIRTUALLINK:
476 	case IF_TYPE_POINTOMULTIPOINT:
477 		/* always ok */
478 		break;
479 	case IF_TYPE_BROADCAST:
480 	case IF_TYPE_NBMA:
481 		/*
482 		 * if neighbor is dr, bdr or router self is dr or bdr
483 		 * start forming adjacency
484 		 */
485 		if (iface->dr == nbr || iface->bdr == nbr ||
486 		    iface->state & IF_STA_DRORBDR)
487 			break;
488 		return (0);
489 	default:
490 		fatalx("nbr_act_ok: unknown interface type");
491 	}
492 	return (1);
493 }
494 
495 int
496 nbr_act_eval(struct nbr *nbr)
497 {
498 	if (!nbr_adj_ok(nbr)) {
499 		nbr->state = NBR_STA_2_WAY;
500 		return (0);
501 	}
502 
503 	nbr->state = NBR_STA_XSTRT;
504 	nbr->master = 1;
505 	nbr->dd_seq_num++;	/* as per RFC */
506 	nbr->dd_pending = 0;
507 	/* initial db negotiation */
508 	start_db_tx_timer(nbr);
509 
510 	nbr_start_adj_timer(nbr);
511 
512 	return (0);
513 }
514 
515 int
516 nbr_act_snapshot(struct nbr *nbr)
517 {
518 	stop_db_tx_timer(nbr);
519 
520 	ospfe_imsg_compose_rde(IMSG_DB_SNAPSHOT, nbr->peerid, 0, NULL, 0);
521 
522 	return (0);
523 }
524 
525 int
526 nbr_act_exchange_done(struct nbr *nbr)
527 {
528 	if (nbr->master)
529 		stop_db_tx_timer(nbr);
530 
531 	if (ls_req_list_empty(nbr) && nbr->state == NBR_STA_XCHNG &&
532 	    nbr->dd_pending == 0) {
533 		nbr->state = NBR_STA_FULL;
534 		return (0);
535 	}
536 
537 	nbr->state = NBR_STA_LOAD;
538 
539 	if (!ls_req_list_empty(nbr))
540 		start_ls_req_tx_timer(nbr);
541 
542 	return (0);
543 }
544 
545 int
546 nbr_act_adj_ok(struct nbr *nbr)
547 {
548 	if (nbr_adj_ok(nbr)) {
549 		if (nbr->state == NBR_STA_2_WAY)
550 			return (nbr_act_eval(nbr));
551 	} else {
552 		nbr->state = NBR_STA_2_WAY;
553 		return (nbr_act_clear_lists(nbr));
554 	}
555 
556 	return (0);
557 }
558 
559 int
560 nbr_act_restart_dd(struct nbr *nbr)
561 {
562 	nbr_act_clear_lists(nbr);
563 
564 	if (!nbr_adj_ok(nbr)) {
565 		nbr->state = NBR_STA_2_WAY;
566 		return (0);
567 	}
568 
569 	nbr->state = NBR_STA_XSTRT;
570 	nbr->master = 1;
571 	nbr->dd_seq_num += arc4random() & 0xffff;
572 	nbr->dd_pending = 0;
573 
574 	/* initial db negotiation */
575 	start_db_tx_timer(nbr);
576 
577 	nbr_start_adj_timer(nbr);
578 
579 	return (0);
580 }
581 
582 int
583 nbr_act_delete(struct nbr *nbr)
584 {
585 	struct timeval	tv;
586 
587 	if (nbr == nbr->iface->self)
588 		return (0);
589 
590 	/* stop timers */
591 	nbr_stop_itimer(nbr);
592 
593 	/* clear dr and bdr */
594 	nbr->dr.s_addr = 0;
595 	nbr->bdr.s_addr = 0;
596 	nbr->crypt_seq_num = 0;
597 
598 	/* schedule kill timer */
599 	timerclear(&tv);
600 	tv.tv_sec = DEFAULT_NBR_TMOUT;
601 
602 	if (evtimer_add(&nbr->inactivity_timer, &tv)) {
603 		log_warnx("nbr_act_delete: error scheduling neighbor ID %s "
604 		    "for removal", inet_ntoa(nbr->id));
605 	}
606 
607 	return (nbr_act_clear_lists(nbr));
608 }
609 
610 int
611 nbr_act_clear_lists(struct nbr *nbr)
612 {
613 	/* stop timers */
614 	stop_db_tx_timer(nbr);
615 	stop_ls_req_tx_timer(nbr);
616 
617 	/* clear lists */
618 	ls_retrans_list_clr(nbr);
619 	db_sum_list_clr(nbr);
620 	ls_req_list_clr(nbr);
621 
622 	return (0);
623 }
624 
625 int
626 nbr_act_hello_check(struct nbr *nbr)
627 {
628 	log_debug("nbr_act_hello_check: neighbor ID %s", inet_ntoa(nbr->id));
629 
630 	return (-1);
631 }
632 
633 struct ctl_nbr *
634 nbr_to_ctl(struct nbr *nbr)
635 {
636 	static struct ctl_nbr	 nctl;
637 	struct timeval		 tv, now, res;
638 	struct lsa_entry	*le;
639 
640 	memcpy(nctl.name, nbr->iface->name, sizeof(nctl.name));
641 	memcpy(&nctl.id, &nbr->id, sizeof(nctl.id));
642 	memcpy(&nctl.addr, &nbr->addr, sizeof(nctl.addr));
643 	memcpy(&nctl.dr, &nbr->dr, sizeof(nctl.dr));
644 	memcpy(&nctl.bdr, &nbr->bdr, sizeof(nctl.bdr));
645 	memcpy(&nctl.area, &nbr->iface->area->id, sizeof(nctl.area));
646 
647 	/* this list is 99% of the time empty so that's OK for now */
648 	nctl.db_sum_lst_cnt = 0;
649 	TAILQ_FOREACH(le, &nbr->db_sum_list, entry)
650 		nctl.db_sum_lst_cnt++;
651 
652 	nctl.ls_req_lst_cnt = nbr->ls_req_cnt;
653 	nctl.ls_retrans_lst_cnt = nbr->ls_ret_cnt;
654 
655 	nctl.nbr_state = nbr->state;
656 
657 	/*
658 	 * We need to trick a bit to show the remote iface state.
659 	 * The idea is to print DR, BDR or DROther dependent on
660 	 * the type of the neighbor.
661 	 */
662 	if (nbr->iface->dr == nbr)
663 		nctl.iface_state = IF_STA_DR;
664 	else if (nbr->iface->bdr == nbr)
665 		nctl.iface_state = IF_STA_BACKUP;
666 	else if (nbr->iface->state & IF_STA_MULTI)
667 		nctl.iface_state = IF_STA_DROTHER;
668 	else
669 		nctl.iface_state = nbr->iface->state;
670 
671 	nctl.state_chng_cnt = nbr->stats.sta_chng;
672 
673 	nctl.priority = nbr->priority;
674 	nctl.options = nbr->options;
675 
676 	gettimeofday(&now, NULL);
677 	if (evtimer_pending(&nbr->inactivity_timer, &tv)) {
678 		timersub(&tv, &now, &res);
679 		if (nbr->state & NBR_STA_DOWN)
680 			nctl.dead_timer = DEFAULT_NBR_TMOUT - res.tv_sec;
681 		else
682 			nctl.dead_timer = res.tv_sec;
683 	} else
684 		nctl.dead_timer = 0;
685 
686 	if (nbr->state == NBR_STA_FULL) {
687 		nctl.uptime = now.tv_sec - nbr->uptime;
688 	} else
689 		nctl.uptime = 0;
690 
691 	return (&nctl);
692 }
693 
694 struct lsa_hdr *
695 lsa_hdr_new(void)
696 {
697 	struct lsa_hdr	*lsa_hdr = NULL;
698 
699 	if ((lsa_hdr = calloc(1, sizeof(*lsa_hdr))) == NULL)
700 		fatal("lsa_hdr_new");
701 
702 	return (lsa_hdr);
703 }
704