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
41int	 nbr_adj_ok(struct nbr *);
42
43LIST_HEAD(nbr_head, nbr);
44
45struct 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
53u_int32_t	peercnt = NBR_CNTSTART;
54
55struct {
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
85const 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
103const 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
118int
119nbr_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
237void
238nbr_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
270struct nbr *
271nbr_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
328void
329nbr_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
356struct nbr *
357nbr_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
372struct nbr *
373nbr_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 */
386void
387nbr_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
397void
398nbr_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
409void
410nbr_stop_itimer(struct nbr *nbr)
411{
412	if (evtimer_del(&nbr->inactivity_timer) == -1)
413		fatal("nbr_stop_itimer");
414}
415
416void
417nbr_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
428void
429nbr_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
443void
444nbr_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 */
456int
457nbr_act_reset_itimer(struct nbr *nbr)
458{
459	nbr_reset_itimer(nbr);
460
461	return (0);
462}
463
464int
465nbr_act_start_itimer(struct nbr *nbr)
466{
467	nbr_start_itimer(nbr);
468
469	return (0);
470}
471
472int
473nbr_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
499int
500nbr_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
519int
520nbr_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
541int
542nbr_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
561int
562nbr_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
575int
576nbr_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
598int
599nbr_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
629int
630nbr_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
644int
645nbr_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
653struct ctl_nbr *
654nbr_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
714struct lsa_hdr *
715lsa_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