xref: /openbsd-src/usr.sbin/ospf6d/neighbor.c (revision 5b133f3f277e80f096764111e64f3a1284acb179)
1*5b133f3fSguenther /*	$OpenBSD: neighbor.c,v 1.19 2023/03/08 04:43:14 guenther Exp $ */
2a1a4e97bSnorby 
3a1a4e97bSnorby /*
4a1a4e97bSnorby  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
5a1a4e97bSnorby  * Copyright (c) 2004, 2005, 2007 Esben Norby <norby@openbsd.org>
6a1a4e97bSnorby  *
7a1a4e97bSnorby  * Permission to use, copy, modify, and distribute this software for any
8a1a4e97bSnorby  * purpose with or without fee is hereby granted, provided that the above
9a1a4e97bSnorby  * copyright notice and this permission notice appear in all copies.
10a1a4e97bSnorby  *
11a1a4e97bSnorby  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12a1a4e97bSnorby  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13a1a4e97bSnorby  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14a1a4e97bSnorby  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15a1a4e97bSnorby  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16a1a4e97bSnorby  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17a1a4e97bSnorby  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18a1a4e97bSnorby  */
19a1a4e97bSnorby 
20a1a4e97bSnorby #include <sys/types.h>
21a1a4e97bSnorby #include <sys/ioctl.h>
22a1a4e97bSnorby #include <sys/time.h>
23a1a4e97bSnorby #include <sys/socket.h>
24a1a4e97bSnorby #include <netinet/in.h>
25a1a4e97bSnorby #include <arpa/inet.h>
26a1a4e97bSnorby #include <net/if.h>
27a1a4e97bSnorby 
28a1a4e97bSnorby #include <ctype.h>
29a1a4e97bSnorby #include <err.h>
30a1a4e97bSnorby #include <stdio.h>
31a1a4e97bSnorby #include <stdlib.h>
32a1a4e97bSnorby #include <string.h>
33a1a4e97bSnorby #include <event.h>
34a1a4e97bSnorby 
35a1a4e97bSnorby #include "ospf6d.h"
36a1a4e97bSnorby #include "ospf6.h"
37a1a4e97bSnorby #include "ospfe.h"
38a1a4e97bSnorby #include "log.h"
39a1a4e97bSnorby #include "rde.h"
40a1a4e97bSnorby 
41a1a4e97bSnorby int	 nbr_adj_ok(struct nbr *);
42a1a4e97bSnorby 
43a1a4e97bSnorby LIST_HEAD(nbr_head, nbr);
44a1a4e97bSnorby 
45a1a4e97bSnorby struct nbr_table {
46a1a4e97bSnorby 	struct nbr_head		*hashtbl;
47a1a4e97bSnorby 	u_int32_t		 hashmask;
48a1a4e97bSnorby } nbrtable;
49a1a4e97bSnorby 
50a1a4e97bSnorby #define NBR_HASH(x)		\
51a1a4e97bSnorby 	&nbrtable.hashtbl[(x) & nbrtable.hashmask]
52a1a4e97bSnorby 
53a1a4e97bSnorby u_int32_t	peercnt = NBR_CNTSTART;
54a1a4e97bSnorby 
55a1a4e97bSnorby struct {
56a1a4e97bSnorby 	int		state;
57a1a4e97bSnorby 	enum nbr_event	event;
58a1a4e97bSnorby 	enum nbr_action	action;
5925bf10dbSmarkus 	int		new_state; /* 0 means action decides or unchanged */
60a1a4e97bSnorby } nbr_fsm_tbl[] = {
61a1a4e97bSnorby     /* current state	event that happened	action to take		resulting state */
62a1a4e97bSnorby     {NBR_STA_ACTIVE,	NBR_EVT_HELLO_RCVD,	NBR_ACT_RST_ITIMER,	0},
63a1a4e97bSnorby     {NBR_STA_BIDIR,	NBR_EVT_2_WAY_RCVD,	NBR_ACT_NOTHING,	0},
64a1a4e97bSnorby     {NBR_STA_INIT,	NBR_EVT_1_WAY_RCVD,	NBR_ACT_NOTHING,	0},
65a1a4e97bSnorby     {NBR_STA_DOWN,	NBR_EVT_HELLO_RCVD,	NBR_ACT_STRT_ITIMER,	NBR_STA_INIT},
66a1a4e97bSnorby     {NBR_STA_ATTEMPT,	NBR_EVT_HELLO_RCVD,	NBR_ACT_RST_ITIMER,	NBR_STA_INIT},
67a1a4e97bSnorby     {NBR_STA_INIT,	NBR_EVT_2_WAY_RCVD,	NBR_ACT_EVAL,		0},
6825bf10dbSmarkus     {NBR_STA_XSTRT,	NBR_EVT_NEG_DONE,	NBR_ACT_SNAP,		0},
69a1a4e97bSnorby     {NBR_STA_SNAP,	NBR_EVT_SNAP_DONE,	NBR_ACT_SNAP_DONE,	NBR_STA_XCHNG},
70a1a4e97bSnorby     {NBR_STA_XCHNG,	NBR_EVT_XCHNG_DONE,	NBR_ACT_XCHNG_DONE,	0},
71a1a4e97bSnorby     {NBR_STA_LOAD,	NBR_EVT_LOAD_DONE,	NBR_ACT_NOTHING,	NBR_STA_FULL},
72a1a4e97bSnorby     {NBR_STA_2_WAY,	NBR_EVT_ADJ_OK,		NBR_ACT_EVAL,		0},
73a1a4e97bSnorby     {NBR_STA_ADJFORM,	NBR_EVT_ADJ_OK,		NBR_ACT_ADJ_OK,		0},
74a1a4e97bSnorby     {NBR_STA_PRELIM,	NBR_EVT_ADJ_OK,		NBR_ACT_HELLO_CHK,	0},
75a1a4e97bSnorby     {NBR_STA_ADJFORM,	NBR_EVT_ADJTMOUT,	NBR_ACT_RESTRT_DD,	0},
7625bf10dbSmarkus     {NBR_STA_FLOOD,	NBR_EVT_SEQ_NUM_MIS,	NBR_ACT_RESTRT_DD,	0},
7725bf10dbSmarkus     {NBR_STA_FLOOD,	NBR_EVT_BAD_LS_REQ,	NBR_ACT_RESTRT_DD,	0},
78a1a4e97bSnorby     {NBR_STA_ANY,	NBR_EVT_KILL_NBR,	NBR_ACT_DEL,		NBR_STA_DOWN},
79a1a4e97bSnorby     {NBR_STA_ANY,	NBR_EVT_LL_DOWN,	NBR_ACT_DEL,		NBR_STA_DOWN},
80a1a4e97bSnorby     {NBR_STA_ANY,	NBR_EVT_ITIMER,		NBR_ACT_DEL,		NBR_STA_DOWN},
81a1a4e97bSnorby     {NBR_STA_BIDIR,	NBR_EVT_1_WAY_RCVD,	NBR_ACT_CLR_LST,	NBR_STA_INIT},
82a1a4e97bSnorby     {-1,		NBR_EVT_NOTHING,	NBR_ACT_NOTHING,	0},
83a1a4e97bSnorby };
84a1a4e97bSnorby 
85a1a4e97bSnorby const char * const nbr_event_names[] = {
86a1a4e97bSnorby 	"NOTHING",
87a1a4e97bSnorby 	"HELLO_RECEIVED",
88a1a4e97bSnorby 	"2_WAY_RECEIVED",
89a1a4e97bSnorby 	"NEGOTIATION_DONE",
90a1a4e97bSnorby 	"SNAPSHOT_DONE",
91a1a4e97bSnorby 	"EXCHANGE_DONE",
92a1a4e97bSnorby 	"BAD_LS_REQ",
93a1a4e97bSnorby 	"LOADING_DONE",
94a1a4e97bSnorby 	"ADJ_OK",
95a1a4e97bSnorby 	"SEQ_NUM_MISMATCH",
96a1a4e97bSnorby 	"1_WAY_RECEIVED",
97a1a4e97bSnorby 	"KILL_NBR",
98a1a4e97bSnorby 	"INACTIVITY_TIMER",
99a1a4e97bSnorby 	"LL_DOWN",
100a1a4e97bSnorby 	"ADJ_TIMEOUT"
101a1a4e97bSnorby };
102a1a4e97bSnorby 
103a1a4e97bSnorby const char * const nbr_action_names[] = {
104a1a4e97bSnorby 	"NOTHING",
105a1a4e97bSnorby 	"RESET_INACTIVITY_TIMER",
106a1a4e97bSnorby 	"START_INACTIVITY_TIMER",
107a1a4e97bSnorby 	"EVAL",
108a1a4e97bSnorby 	"SNAPSHOT",
109a1a4e97bSnorby 	"SNAPSHOT_DONE",
110a1a4e97bSnorby 	"EXCHANGE_DONE",
111a1a4e97bSnorby 	"ADJ_OK",
112a1a4e97bSnorby 	"RESET_DD",
113a1a4e97bSnorby 	"DELETE",
114a1a4e97bSnorby 	"CLEAR_LISTS",
115a1a4e97bSnorby 	"HELLO_CHK"
116a1a4e97bSnorby };
117a1a4e97bSnorby 
118a1a4e97bSnorby int
nbr_fsm(struct nbr * nbr,enum nbr_event event)119a1a4e97bSnorby nbr_fsm(struct nbr *nbr, enum nbr_event event)
120a1a4e97bSnorby {
121a1a4e97bSnorby 	struct timeval	now;
122a1a4e97bSnorby 	int		old_state;
123a1a4e97bSnorby 	int		new_state = 0;
124a1a4e97bSnorby 	int		i, ret = 0;
125a1a4e97bSnorby 
126a1a4e97bSnorby 	if (nbr == nbr->iface->self)
127a1a4e97bSnorby 		return (0);
128a1a4e97bSnorby 
129a1a4e97bSnorby 	old_state = nbr->state;
130a1a4e97bSnorby 	for (i = 0; nbr_fsm_tbl[i].state != -1; i++)
131a1a4e97bSnorby 		if ((nbr_fsm_tbl[i].state & old_state) &&
132a1a4e97bSnorby 		    (nbr_fsm_tbl[i].event == event)) {
133a1a4e97bSnorby 			new_state = nbr_fsm_tbl[i].new_state;
134a1a4e97bSnorby 			break;
135a1a4e97bSnorby 		}
136a1a4e97bSnorby 
137a1a4e97bSnorby 	if (nbr_fsm_tbl[i].state == -1) {
138a1a4e97bSnorby 		/* event outside of the defined fsm, ignore it. */
1399cc19ef1Ssthen 		log_warnx("nbr_fsm: neighbor ID %s (%s), "
140a1a4e97bSnorby 		    "event %s not expected in state %s",
1419cc19ef1Ssthen 		    inet_ntoa(nbr->id), nbr->iface->name,
1429cc19ef1Ssthen 		    nbr_event_names[event],
143a1a4e97bSnorby 		    nbr_state_name(old_state));
144a1a4e97bSnorby 		return (0);
145a1a4e97bSnorby 	}
146a1a4e97bSnorby 
147a1a4e97bSnorby 	switch (nbr_fsm_tbl[i].action) {
148a1a4e97bSnorby 	case NBR_ACT_RST_ITIMER:
149a1a4e97bSnorby 		ret = nbr_act_reset_itimer(nbr);
150a1a4e97bSnorby 		break;
151a1a4e97bSnorby 	case NBR_ACT_STRT_ITIMER:
152a1a4e97bSnorby 		ret = nbr_act_start_itimer(nbr);
153a1a4e97bSnorby 		break;
154a1a4e97bSnorby 	case NBR_ACT_EVAL:
155a1a4e97bSnorby 		ret = nbr_act_eval(nbr);
156a1a4e97bSnorby 		break;
157a1a4e97bSnorby 	case NBR_ACT_SNAP:
158a1a4e97bSnorby 		ret = nbr_act_snapshot(nbr);
159a1a4e97bSnorby 		break;
160a1a4e97bSnorby 	case NBR_ACT_SNAP_DONE:
161a1a4e97bSnorby 		/* start db exchange */
162a1a4e97bSnorby 		start_db_tx_timer(nbr);
163a1a4e97bSnorby 		break;
164a1a4e97bSnorby 	case NBR_ACT_XCHNG_DONE:
165a1a4e97bSnorby 		ret = nbr_act_exchange_done(nbr);
166a1a4e97bSnorby 		break;
167a1a4e97bSnorby 	case NBR_ACT_ADJ_OK:
168a1a4e97bSnorby 		ret = nbr_act_adj_ok(nbr);
169a1a4e97bSnorby 		break;
170a1a4e97bSnorby 	case NBR_ACT_RESTRT_DD:
171a1a4e97bSnorby 		ret = nbr_act_restart_dd(nbr);
172a1a4e97bSnorby 		break;
173a1a4e97bSnorby 	case NBR_ACT_DEL:
174a1a4e97bSnorby 		ret = nbr_act_delete(nbr);
175a1a4e97bSnorby 		break;
176a1a4e97bSnorby 	case NBR_ACT_CLR_LST:
177a1a4e97bSnorby 		ret = nbr_act_clear_lists(nbr);
178a1a4e97bSnorby 		break;
179a1a4e97bSnorby 	case NBR_ACT_HELLO_CHK:
180a1a4e97bSnorby 		ret = nbr_act_hello_check(nbr);
181a1a4e97bSnorby 		break;
182a1a4e97bSnorby 	case NBR_ACT_NOTHING:
183a1a4e97bSnorby 		/* do nothing */
184a1a4e97bSnorby 		break;
185a1a4e97bSnorby 	}
186a1a4e97bSnorby 
187a1a4e97bSnorby 	if (ret) {
1889cc19ef1Ssthen 		log_warnx("nbr_fsm: error changing state for neighbor "
1899cc19ef1Ssthen 		    "ID %s (%s), event %s, state %s",
1909cc19ef1Ssthen 		    inet_ntoa(nbr->id), nbr->iface->name,
191a1a4e97bSnorby 		    nbr_event_names[event], nbr_state_name(old_state));
192a1a4e97bSnorby 		return (-1);
193a1a4e97bSnorby 	}
194a1a4e97bSnorby 
195a1a4e97bSnorby 	if (new_state != 0)
196a1a4e97bSnorby 		nbr->state = new_state;
197a1a4e97bSnorby 
198a1a4e97bSnorby 	if (old_state != nbr->state) {
199a1a4e97bSnorby 		nbr->stats.sta_chng++;
200a1a4e97bSnorby 
201a1a4e97bSnorby 		if (old_state & NBR_STA_FULL || nbr->state & NBR_STA_FULL) {
202a1a4e97bSnorby 			/*
203a1a4e97bSnorby 			 * neighbor changed from/to FULL
204a1a4e97bSnorby 			 * originate new rtr and net LSA
205a1a4e97bSnorby 			 */
206d18517d2Sdenis 			orig_rtr_lsa(nbr->iface->area);
207a1a4e97bSnorby 			if (nbr->iface->state & IF_STA_DR)
208a1a4e97bSnorby 				orig_net_lsa(nbr->iface);
209a1a4e97bSnorby 
210a1a4e97bSnorby 			gettimeofday(&now, NULL);
211a1a4e97bSnorby 			nbr->uptime = now.tv_sec;
212a1a4e97bSnorby 		}
213a1a4e97bSnorby 
21415d59eddSstsp 		/* state change inform RDE */
21515d59eddSstsp 		ospfe_imsg_compose_rde(IMSG_NEIGHBOR_CHANGE,
21615d59eddSstsp 		    nbr->peerid, 0, &nbr->state, sizeof(nbr->state));
21715d59eddSstsp 
218a1a4e97bSnorby 		/* bidirectional communication lost */
219a1a4e97bSnorby 		if (old_state & ~NBR_STA_PRELIM && nbr->state & NBR_STA_PRELIM)
220a1a4e97bSnorby 			if_fsm(nbr->iface, IF_EVT_NBR_CHNG);
221a1a4e97bSnorby 
222a1a4e97bSnorby 		log_debug("nbr_fsm: event %s resulted in action %s and "
2239cc19ef1Ssthen 		    "changing state for neighbor ID %s (%s) from %s to %s",
224a1a4e97bSnorby 		    nbr_event_names[event],
225a1a4e97bSnorby 		    nbr_action_names[nbr_fsm_tbl[i].action],
2269cc19ef1Ssthen 		    inet_ntoa(nbr->id), nbr->iface->name,
2279cc19ef1Ssthen 		    nbr_state_name(old_state),
228a1a4e97bSnorby 		    nbr_state_name(nbr->state));
229a1a4e97bSnorby 
230a1a4e97bSnorby 		if (nbr->iface->type == IF_TYPE_VIRTUALLINK) {
231d18517d2Sdenis 			orig_rtr_lsa(nbr->iface->area);
232a1a4e97bSnorby 		}
233a1a4e97bSnorby 	}
234a1a4e97bSnorby 
235a1a4e97bSnorby 	return (ret);
236a1a4e97bSnorby }
237a1a4e97bSnorby 
238a1a4e97bSnorby void
nbr_init(u_int32_t hashsize)239a1a4e97bSnorby nbr_init(u_int32_t hashsize)
240a1a4e97bSnorby {
241a1a4e97bSnorby 	struct nbr_head	*head;
242a1a4e97bSnorby 	struct nbr	*nbr;
243a1a4e97bSnorby 	u_int32_t        hs, i;
244a1a4e97bSnorby 
245a1a4e97bSnorby 	for (hs = 1; hs < hashsize; hs <<= 1)
246a1a4e97bSnorby 		;
247a1a4e97bSnorby 	nbrtable.hashtbl = calloc(hs, sizeof(struct nbr_head));
248a1a4e97bSnorby 	if (nbrtable.hashtbl == NULL)
249a1a4e97bSnorby 		fatal("nbr_init");
250a1a4e97bSnorby 
251a1a4e97bSnorby 	for (i = 0; i < hs; i++)
252a1a4e97bSnorby 		LIST_INIT(&nbrtable.hashtbl[i]);
253a1a4e97bSnorby 
254a1a4e97bSnorby 	nbrtable.hashmask = hs - 1;
255a1a4e97bSnorby 
256a1a4e97bSnorby 	/* allocate a dummy neighbor used for self originated AS ext routes */
257a1a4e97bSnorby 	if ((nbr = calloc(1, sizeof(*nbr))) == NULL)
258a1a4e97bSnorby 		fatal("nbr_init");
259a1a4e97bSnorby 
260a1a4e97bSnorby 	nbr->id.s_addr = ospfe_router_id();
261a1a4e97bSnorby 	nbr->state = NBR_STA_DOWN;
262a1a4e97bSnorby 	nbr->peerid = NBR_IDSELF;
263a1a4e97bSnorby 	head = NBR_HASH(nbr->peerid);
264a1a4e97bSnorby 	LIST_INSERT_HEAD(head, nbr, hash);
265a1a4e97bSnorby 
266a1a4e97bSnorby 	TAILQ_INIT(&nbr->ls_retrans_list);
267a1a4e97bSnorby 	TAILQ_INIT(&nbr->db_sum_list);
268a1a4e97bSnorby 	TAILQ_INIT(&nbr->ls_req_list);
269a1a4e97bSnorby }
270a1a4e97bSnorby 
271a1a4e97bSnorby struct nbr *
nbr_new(u_int32_t nbr_id,struct iface * iface,u_int32_t iface_id,int self,struct in6_addr * addr)272d2afa435Sstsp nbr_new(u_int32_t nbr_id, struct iface *iface, u_int32_t iface_id, int self,
273d2afa435Sstsp 	struct in6_addr *addr)
274a1a4e97bSnorby {
275a1a4e97bSnorby 	struct nbr_head	*head;
276a1a4e97bSnorby 	struct nbr	*nbr;
277a1a4e97bSnorby 	struct rde_nbr	 rn;
278a1a4e97bSnorby 
279a1a4e97bSnorby 	if ((nbr = calloc(1, sizeof(*nbr))) == NULL)
280a1a4e97bSnorby 		fatal("nbr_new");
281a1a4e97bSnorby 
282a1a4e97bSnorby 	nbr->state = NBR_STA_DOWN;
2837b65306cSclaudio 	nbr->dd_master = 1;
284a1a4e97bSnorby 	nbr->dd_seq_num = arc4random();	/* RFC: some unique value */
285a1a4e97bSnorby 	nbr->id.s_addr = nbr_id;
286a1a4e97bSnorby 
287a1a4e97bSnorby 	/* get next unused peerid */
288a1a4e97bSnorby 	while (nbr_find_peerid(++peercnt))
289a1a4e97bSnorby 		;
290a1a4e97bSnorby 	nbr->peerid = peercnt;
291a1a4e97bSnorby 	head = NBR_HASH(nbr->peerid);
292a1a4e97bSnorby 	LIST_INSERT_HEAD(head, nbr, hash);
293a1a4e97bSnorby 
294a1a4e97bSnorby 	/* add to peer list */
295a1a4e97bSnorby 	nbr->iface = iface;
296f0f73935Sstsp 	nbr->iface_id = iface_id;
297a1a4e97bSnorby 	LIST_INSERT_HEAD(&iface->nbr_list, nbr, entry);
298a1a4e97bSnorby 
299a1a4e97bSnorby 	TAILQ_INIT(&nbr->ls_retrans_list);
300a1a4e97bSnorby 	TAILQ_INIT(&nbr->db_sum_list);
301a1a4e97bSnorby 	TAILQ_INIT(&nbr->ls_req_list);
302a1a4e97bSnorby 
303a1a4e97bSnorby 	nbr->ls_req = NULL;
304a1a4e97bSnorby 
305a1a4e97bSnorby 	if (self) {
306a1a4e97bSnorby 		nbr->state = NBR_STA_FULL;
307a1a4e97bSnorby 		nbr->addr = iface->addr;
308a1a4e97bSnorby 		nbr->priority = iface->priority;
309a1a4e97bSnorby 	}
310a1a4e97bSnorby 
311a1a4e97bSnorby 	/* set event structures */
312a1a4e97bSnorby 	evtimer_set(&nbr->inactivity_timer, nbr_itimer, nbr);
313a1a4e97bSnorby 	evtimer_set(&nbr->db_tx_timer, db_tx_timer, nbr);
314a1a4e97bSnorby 	evtimer_set(&nbr->lsreq_tx_timer, ls_req_tx_timer, nbr);
315a1a4e97bSnorby 	evtimer_set(&nbr->ls_retrans_timer, ls_retrans_timer, nbr);
316a1a4e97bSnorby 	evtimer_set(&nbr->adj_timer, nbr_adj_timer, nbr);
317a1a4e97bSnorby 
318a1a4e97bSnorby 	bzero(&rn, sizeof(rn));
319d2afa435Sstsp 	if (addr)
320d2afa435Sstsp 		rn.addr = *addr;
321a1a4e97bSnorby 	rn.id.s_addr = nbr->id.s_addr;
32277fbfa19Sdenis 	rn.area_id.s_addr = nbr->iface->area->id.s_addr;
3234139c605Sclaudio 	rn.ifindex = nbr->iface->ifindex;
324f0f73935Sstsp 	rn.iface_id = nbr->iface_id;
325a1a4e97bSnorby 	rn.state = nbr->state;
326a1a4e97bSnorby 	rn.self = self;
327a1a4e97bSnorby 	ospfe_imsg_compose_rde(IMSG_NEIGHBOR_UP, nbr->peerid, 0, &rn,
328a1a4e97bSnorby 	    sizeof(rn));
329a1a4e97bSnorby 
330a1a4e97bSnorby 	return (nbr);
331a1a4e97bSnorby }
332a1a4e97bSnorby 
333a1a4e97bSnorby void
nbr_del(struct nbr * nbr)334a1a4e97bSnorby nbr_del(struct nbr *nbr)
335a1a4e97bSnorby {
336a1a4e97bSnorby 	ospfe_imsg_compose_rde(IMSG_NEIGHBOR_DOWN, nbr->peerid, 0, NULL, 0);
337a1a4e97bSnorby 
338a1a4e97bSnorby 	if (evtimer_pending(&nbr->inactivity_timer, NULL))
339a1a4e97bSnorby 		evtimer_del(&nbr->inactivity_timer);
340a1a4e97bSnorby 	if (evtimer_pending(&nbr->db_tx_timer, NULL))
341a1a4e97bSnorby 		evtimer_del(&nbr->db_tx_timer);
342a1a4e97bSnorby 	if (evtimer_pending(&nbr->lsreq_tx_timer, NULL))
343a1a4e97bSnorby 		evtimer_del(&nbr->lsreq_tx_timer);
344a1a4e97bSnorby 	if (evtimer_pending(&nbr->ls_retrans_timer, NULL))
345a1a4e97bSnorby 		evtimer_del(&nbr->ls_retrans_timer);
346a1a4e97bSnorby 	if (evtimer_pending(&nbr->adj_timer, NULL))
347a1a4e97bSnorby 		evtimer_del(&nbr->adj_timer);
348a1a4e97bSnorby 
349a1a4e97bSnorby 	/* clear lists */
350a1a4e97bSnorby 	ls_retrans_list_clr(nbr);
351a1a4e97bSnorby 	db_sum_list_clr(nbr);
352a1a4e97bSnorby 	ls_req_list_clr(nbr);
353a1a4e97bSnorby 
354a1a4e97bSnorby 	LIST_REMOVE(nbr, entry);
355a1a4e97bSnorby 	LIST_REMOVE(nbr, hash);
356a1a4e97bSnorby 
357a1a4e97bSnorby 	free(nbr);
358a1a4e97bSnorby }
359a1a4e97bSnorby 
360a1a4e97bSnorby struct nbr *
nbr_find_peerid(u_int32_t peerid)361a1a4e97bSnorby nbr_find_peerid(u_int32_t peerid)
362a1a4e97bSnorby {
363a1a4e97bSnorby 	struct nbr_head	*head;
364a1a4e97bSnorby 	struct nbr	*nbr;
365a1a4e97bSnorby 
366a1a4e97bSnorby 	head = NBR_HASH(peerid);
367a1a4e97bSnorby 
368a1a4e97bSnorby 	LIST_FOREACH(nbr, head, hash) {
369a1a4e97bSnorby 		if (nbr->peerid == peerid)
370a1a4e97bSnorby 			return (nbr);
371a1a4e97bSnorby 	}
372a1a4e97bSnorby 
373a1a4e97bSnorby 	return (NULL);
374a1a4e97bSnorby }
375a1a4e97bSnorby 
376a1a4e97bSnorby struct nbr *
nbr_find_id(struct iface * iface,u_int32_t rtr_id)377a1a4e97bSnorby nbr_find_id(struct iface *iface, u_int32_t rtr_id)
378a1a4e97bSnorby {
379a1a4e97bSnorby 	struct nbr	*nbr = NULL;
380a1a4e97bSnorby 
381a1a4e97bSnorby 	LIST_FOREACH(nbr, &iface->nbr_list, entry) {
382a1a4e97bSnorby 		if (nbr->id.s_addr == rtr_id)
383a1a4e97bSnorby 			return (nbr);
384a1a4e97bSnorby 	}
385a1a4e97bSnorby 
386a1a4e97bSnorby 	return (NULL);
387a1a4e97bSnorby }
388a1a4e97bSnorby 
389a1a4e97bSnorby /* timers */
390a1a4e97bSnorby void
nbr_itimer(int fd,short event,void * arg)391a1a4e97bSnorby nbr_itimer(int fd, short event, void *arg)
392a1a4e97bSnorby {
393a1a4e97bSnorby 	struct nbr *nbr = arg;
394a1a4e97bSnorby 
395a1a4e97bSnorby 	if (nbr->state == NBR_STA_DOWN)
396a1a4e97bSnorby 		nbr_del(nbr);
397a1a4e97bSnorby 	else
398a1a4e97bSnorby 		nbr_fsm(nbr, NBR_EVT_ITIMER);
399a1a4e97bSnorby }
400a1a4e97bSnorby 
401a1a4e97bSnorby void
nbr_start_itimer(struct nbr * nbr)402a1a4e97bSnorby nbr_start_itimer(struct nbr *nbr)
403a1a4e97bSnorby {
404a1a4e97bSnorby 	struct timeval	tv;
405a1a4e97bSnorby 
406a1a4e97bSnorby 	timerclear(&tv);
407a1a4e97bSnorby 	tv.tv_sec = nbr->iface->dead_interval;
408a1a4e97bSnorby 
409a1a4e97bSnorby 	if (evtimer_add(&nbr->inactivity_timer, &tv) == -1)
410a1a4e97bSnorby 		fatal("nbr_start_itimer");
411a1a4e97bSnorby }
412a1a4e97bSnorby 
413a1a4e97bSnorby void
nbr_stop_itimer(struct nbr * nbr)414a1a4e97bSnorby nbr_stop_itimer(struct nbr *nbr)
415a1a4e97bSnorby {
416a1a4e97bSnorby 	if (evtimer_del(&nbr->inactivity_timer) == -1)
417a1a4e97bSnorby 		fatal("nbr_stop_itimer");
418a1a4e97bSnorby }
419a1a4e97bSnorby 
420a1a4e97bSnorby void
nbr_reset_itimer(struct nbr * nbr)421a1a4e97bSnorby nbr_reset_itimer(struct nbr *nbr)
422a1a4e97bSnorby {
423a1a4e97bSnorby 	struct timeval	tv;
424a1a4e97bSnorby 
425a1a4e97bSnorby 	timerclear(&tv);
426a1a4e97bSnorby 	tv.tv_sec = nbr->iface->dead_interval;
427a1a4e97bSnorby 
428a1a4e97bSnorby 	if (evtimer_add(&nbr->inactivity_timer, &tv) == -1)
429a1a4e97bSnorby 		fatal("nbr_reset_itimer");
430a1a4e97bSnorby }
431a1a4e97bSnorby 
432a1a4e97bSnorby void
nbr_adj_timer(int fd,short event,void * arg)433a1a4e97bSnorby nbr_adj_timer(int fd, short event, void *arg)
434a1a4e97bSnorby {
435a1a4e97bSnorby 	struct nbr *nbr = arg;
436a1a4e97bSnorby 
4378dc7367fSmarkus 	if (!(nbr->state & NBR_STA_ADJFORM))
438a1a4e97bSnorby 		return;
439a1a4e97bSnorby 
440a1a4e97bSnorby 	if (nbr->state & NBR_STA_ACTIVE && nbr->state != NBR_STA_FULL) {
4419cc19ef1Ssthen 		log_warnx("nbr_adj_timer: failed to form adjacency with "
4429cc19ef1Ssthen 		    "neighbor ID %s on interface %s",
4439cc19ef1Ssthen 		    inet_ntoa(nbr->id), nbr->iface->name);
444a1a4e97bSnorby 		nbr_fsm(nbr, NBR_EVT_ADJTMOUT);
445a1a4e97bSnorby 	}
446a1a4e97bSnorby }
447a1a4e97bSnorby 
448a1a4e97bSnorby void
nbr_start_adj_timer(struct nbr * nbr)449a1a4e97bSnorby nbr_start_adj_timer(struct nbr *nbr)
450a1a4e97bSnorby {
451a1a4e97bSnorby 	struct timeval	tv;
452a1a4e97bSnorby 
453a1a4e97bSnorby 	timerclear(&tv);
454a1a4e97bSnorby 	tv.tv_sec = DEFAULT_ADJ_TMOUT;
455a1a4e97bSnorby 
456a1a4e97bSnorby 	if (evtimer_add(&nbr->adj_timer, &tv) == -1)
457a1a4e97bSnorby 		fatal("nbr_start_adj_timer");
458a1a4e97bSnorby }
459a1a4e97bSnorby 
460a1a4e97bSnorby /* actions */
461a1a4e97bSnorby int
nbr_act_reset_itimer(struct nbr * nbr)462a1a4e97bSnorby nbr_act_reset_itimer(struct nbr *nbr)
463a1a4e97bSnorby {
464a1a4e97bSnorby 	nbr_reset_itimer(nbr);
465a1a4e97bSnorby 
466a1a4e97bSnorby 	return (0);
467a1a4e97bSnorby }
468a1a4e97bSnorby 
469a1a4e97bSnorby int
nbr_act_start_itimer(struct nbr * nbr)470a1a4e97bSnorby nbr_act_start_itimer(struct nbr *nbr)
471a1a4e97bSnorby {
472a1a4e97bSnorby 	nbr_start_itimer(nbr);
473a1a4e97bSnorby 
474a1a4e97bSnorby 	return (0);
475a1a4e97bSnorby }
476a1a4e97bSnorby 
477a1a4e97bSnorby int
nbr_adj_ok(struct nbr * nbr)478a1a4e97bSnorby nbr_adj_ok(struct nbr *nbr)
479a1a4e97bSnorby {
480a1a4e97bSnorby 	struct iface	*iface = nbr->iface;
481a1a4e97bSnorby 
482a1a4e97bSnorby 	switch (iface->type) {
483a1a4e97bSnorby 	case IF_TYPE_POINTOPOINT:
484a1a4e97bSnorby 	case IF_TYPE_VIRTUALLINK:
485a1a4e97bSnorby 	case IF_TYPE_POINTOMULTIPOINT:
486a1a4e97bSnorby 		/* always ok */
487a1a4e97bSnorby 		break;
488a1a4e97bSnorby 	case IF_TYPE_BROADCAST:
489a1a4e97bSnorby 	case IF_TYPE_NBMA:
490a1a4e97bSnorby 		/*
491a1a4e97bSnorby 		 * if neighbor is dr, bdr or router self is dr or bdr
492a1a4e97bSnorby 		 * start forming adjacency
493a1a4e97bSnorby 		 */
494a1a4e97bSnorby 		if (iface->dr == nbr || iface->bdr == nbr ||
495a1a4e97bSnorby 		    iface->state & IF_STA_DRORBDR)
496a1a4e97bSnorby 			break;
497a1a4e97bSnorby 		return (0);
498a1a4e97bSnorby 	default:
4993af4e127Snorby 		fatalx("nbr_adj_ok: unknown interface type");
500a1a4e97bSnorby 	}
501a1a4e97bSnorby 	return (1);
502a1a4e97bSnorby }
503a1a4e97bSnorby 
504a1a4e97bSnorby int
nbr_act_eval(struct nbr * nbr)505a1a4e97bSnorby nbr_act_eval(struct nbr *nbr)
506a1a4e97bSnorby {
507a1a4e97bSnorby 	if (!nbr_adj_ok(nbr)) {
508a1a4e97bSnorby 		nbr->state = NBR_STA_2_WAY;
509a1a4e97bSnorby 		return (0);
510a1a4e97bSnorby 	}
511a1a4e97bSnorby 
512a1a4e97bSnorby 	nbr->state = NBR_STA_XSTRT;
5137b65306cSclaudio 	nbr->dd_master = 1;
514a1a4e97bSnorby 	nbr->dd_seq_num++;	/* as per RFC */
515a1a4e97bSnorby 	nbr->dd_pending = 0;
516a1a4e97bSnorby 	/* initial db negotiation */
517a1a4e97bSnorby 	start_db_tx_timer(nbr);
518a1a4e97bSnorby 
519a1a4e97bSnorby 	nbr_start_adj_timer(nbr);
520a1a4e97bSnorby 
521a1a4e97bSnorby 	return (0);
522a1a4e97bSnorby }
523a1a4e97bSnorby 
524a1a4e97bSnorby int
nbr_act_snapshot(struct nbr * nbr)525a1a4e97bSnorby nbr_act_snapshot(struct nbr *nbr)
526a1a4e97bSnorby {
527a1a4e97bSnorby 	stop_db_tx_timer(nbr);
528a1a4e97bSnorby 
52925bf10dbSmarkus 	/* we need to wait for the old snapshot to finish */
53025bf10dbSmarkus 	if (nbr->dd_snapshot) {
53125bf10dbSmarkus 		log_debug("nbr_act_snapshot: giving up, old snapshot running "
5329cc19ef1Ssthen 		    "for neighbor ID %s (%s)", inet_ntoa(nbr->id),
5339cc19ef1Ssthen 		    nbr->iface->name);
53425bf10dbSmarkus 		return (nbr_act_restart_dd(nbr));
53525bf10dbSmarkus 	}
536a1a4e97bSnorby 	ospfe_imsg_compose_rde(IMSG_DB_SNAPSHOT, nbr->peerid, 0, NULL, 0);
537a1a4e97bSnorby 
53825bf10dbSmarkus 	nbr->dd_snapshot = 1;	/* wait for IMSG_DB_END */
53925bf10dbSmarkus 	nbr->state = NBR_STA_SNAP;
54025bf10dbSmarkus 
541a1a4e97bSnorby 	return (0);
542a1a4e97bSnorby }
543a1a4e97bSnorby 
544a1a4e97bSnorby int
nbr_act_exchange_done(struct nbr * nbr)545a1a4e97bSnorby nbr_act_exchange_done(struct nbr *nbr)
546a1a4e97bSnorby {
5477b65306cSclaudio 	if (nbr->dd_master)
548a1a4e97bSnorby 		stop_db_tx_timer(nbr);
549a1a4e97bSnorby 
550a1a4e97bSnorby 	if (ls_req_list_empty(nbr) && nbr->state == NBR_STA_XCHNG &&
551a1a4e97bSnorby 	    nbr->dd_pending == 0) {
552a1a4e97bSnorby 		nbr->state = NBR_STA_FULL;
553a1a4e97bSnorby 		return (0);
554a1a4e97bSnorby 	}
555a1a4e97bSnorby 
556a1a4e97bSnorby 	nbr->state = NBR_STA_LOAD;
557a1a4e97bSnorby 
558a1a4e97bSnorby 	if (!ls_req_list_empty(nbr))
559a1a4e97bSnorby 		start_ls_req_tx_timer(nbr);
560a1a4e97bSnorby 
561a1a4e97bSnorby 	return (0);
562a1a4e97bSnorby }
563a1a4e97bSnorby 
564a1a4e97bSnorby int
nbr_act_adj_ok(struct nbr * nbr)565a1a4e97bSnorby nbr_act_adj_ok(struct nbr *nbr)
566a1a4e97bSnorby {
567a1a4e97bSnorby 	if (nbr_adj_ok(nbr)) {
568a1a4e97bSnorby 		if (nbr->state == NBR_STA_2_WAY)
569a1a4e97bSnorby 			return (nbr_act_eval(nbr));
570a1a4e97bSnorby 	} else {
571a1a4e97bSnorby 		nbr->state = NBR_STA_2_WAY;
572a1a4e97bSnorby 		return (nbr_act_clear_lists(nbr));
573a1a4e97bSnorby 	}
574a1a4e97bSnorby 
575a1a4e97bSnorby 	return (0);
576a1a4e97bSnorby }
577a1a4e97bSnorby 
578a1a4e97bSnorby int
nbr_act_restart_dd(struct nbr * nbr)579a1a4e97bSnorby nbr_act_restart_dd(struct nbr *nbr)
580a1a4e97bSnorby {
581a1a4e97bSnorby 	nbr_act_clear_lists(nbr);
582a1a4e97bSnorby 
583a1a4e97bSnorby 	if (!nbr_adj_ok(nbr)) {
584a1a4e97bSnorby 		nbr->state = NBR_STA_2_WAY;
585a1a4e97bSnorby 		return (0);
586a1a4e97bSnorby 	}
587a1a4e97bSnorby 
588a1a4e97bSnorby 	nbr->state = NBR_STA_XSTRT;
5897b65306cSclaudio 	nbr->dd_master = 1;
590a1a4e97bSnorby 	nbr->dd_seq_num += arc4random() & 0xffff;
591a1a4e97bSnorby 	nbr->dd_pending = 0;
592a1a4e97bSnorby 
593a1a4e97bSnorby 	/* initial db negotiation */
594a1a4e97bSnorby 	start_db_tx_timer(nbr);
595a1a4e97bSnorby 
596a1a4e97bSnorby 	nbr_start_adj_timer(nbr);
597a1a4e97bSnorby 
598a1a4e97bSnorby 	return (0);
599a1a4e97bSnorby }
600a1a4e97bSnorby 
601a1a4e97bSnorby int
nbr_act_delete(struct nbr * nbr)602a1a4e97bSnorby nbr_act_delete(struct nbr *nbr)
603a1a4e97bSnorby {
604a1a4e97bSnorby 	struct timeval	tv;
605a1a4e97bSnorby 
606cb595d3fSclaudio 	/* clear dr and bdr */
607cb595d3fSclaudio 	nbr->dr.s_addr = 0;
608cb595d3fSclaudio 	nbr->bdr.s_addr = 0;
609cb595d3fSclaudio 
610a1a4e97bSnorby 	if (nbr == nbr->iface->self)
611a1a4e97bSnorby 		return (0);
612a1a4e97bSnorby 
613a1a4e97bSnorby 	/* stop timers */
614a1a4e97bSnorby 	nbr_stop_itimer(nbr);
615a1a4e97bSnorby 
616a1a4e97bSnorby 	/* schedule kill timer */
617a1a4e97bSnorby 	timerclear(&tv);
618a1a4e97bSnorby 	tv.tv_sec = DEFAULT_NBR_TMOUT;
619a1a4e97bSnorby 
620a1a4e97bSnorby 	if (evtimer_add(&nbr->inactivity_timer, &tv)) {
6219cc19ef1Ssthen 		log_warnx("nbr_act_delete: error scheduling "
6229cc19ef1Ssthen 		    "neighbor ID %s (%s) for removal",
6239cc19ef1Ssthen 		    inet_ntoa(nbr->id), nbr->iface->name);
624a1a4e97bSnorby 	}
625a1a4e97bSnorby 
626a1a4e97bSnorby 	return (nbr_act_clear_lists(nbr));
627a1a4e97bSnorby }
628a1a4e97bSnorby 
629a1a4e97bSnorby int
nbr_act_clear_lists(struct nbr * nbr)630a1a4e97bSnorby nbr_act_clear_lists(struct nbr *nbr)
631a1a4e97bSnorby {
632a1a4e97bSnorby 	/* stop timers */
633a1a4e97bSnorby 	stop_db_tx_timer(nbr);
634a1a4e97bSnorby 	stop_ls_req_tx_timer(nbr);
635a1a4e97bSnorby 
636a1a4e97bSnorby 	/* clear lists */
637a1a4e97bSnorby 	ls_retrans_list_clr(nbr);
638a1a4e97bSnorby 	db_sum_list_clr(nbr);
639a1a4e97bSnorby 	ls_req_list_clr(nbr);
640a1a4e97bSnorby 
641a1a4e97bSnorby 	return (0);
642a1a4e97bSnorby }
643a1a4e97bSnorby 
644a1a4e97bSnorby int
nbr_act_hello_check(struct nbr * nbr)645a1a4e97bSnorby nbr_act_hello_check(struct nbr *nbr)
646a1a4e97bSnorby {
6479cc19ef1Ssthen 	log_debug("nbr_act_hello_check: neighbor ID %s (%s)",
6489cc19ef1Ssthen 	    inet_ntoa(nbr->id), nbr->iface->name);
649a1a4e97bSnorby 
650a1a4e97bSnorby 	return (-1);
651a1a4e97bSnorby }
652a1a4e97bSnorby 
653a1a4e97bSnorby struct ctl_nbr *
nbr_to_ctl(struct nbr * nbr)654a1a4e97bSnorby nbr_to_ctl(struct nbr *nbr)
655a1a4e97bSnorby {
656a1a4e97bSnorby 	static struct ctl_nbr	 nctl;
657a1a4e97bSnorby 	struct timeval		 tv, now, res;
658a1a4e97bSnorby 	struct lsa_entry	*le;
659a1a4e97bSnorby 
660a1a4e97bSnorby 	memcpy(nctl.name, nbr->iface->name, sizeof(nctl.name));
661a1a4e97bSnorby 	memcpy(&nctl.id, &nbr->id, sizeof(nctl.id));
662a1a4e97bSnorby 	memcpy(&nctl.addr, &nbr->addr, sizeof(nctl.addr));
663a1a4e97bSnorby 	memcpy(&nctl.dr, &nbr->dr, sizeof(nctl.dr));
664a1a4e97bSnorby 	memcpy(&nctl.bdr, &nbr->bdr, sizeof(nctl.bdr));
66577fbfa19Sdenis 	memcpy(&nctl.area, &nbr->iface->area->id, sizeof(nctl.area));
666a1a4e97bSnorby 
667a1a4e97bSnorby 	/* this list is 99% of the time empty so that's OK for now */
668a1a4e97bSnorby 	nctl.db_sum_lst_cnt = 0;
669a1a4e97bSnorby 	TAILQ_FOREACH(le, &nbr->db_sum_list, entry)
670a1a4e97bSnorby 		nctl.db_sum_lst_cnt++;
671a1a4e97bSnorby 
672a1a4e97bSnorby 	nctl.ls_req_lst_cnt = nbr->ls_req_cnt;
673a1a4e97bSnorby 	nctl.ls_retrans_lst_cnt = nbr->ls_ret_cnt;
674a1a4e97bSnorby 
675a1a4e97bSnorby 	nctl.nbr_state = nbr->state;
676a1a4e97bSnorby 
677a1a4e97bSnorby 	/*
678a1a4e97bSnorby 	 * We need to trick a bit to show the remote iface state.
679a1a4e97bSnorby 	 * The idea is to print DR, BDR or DROther dependent on
680a1a4e97bSnorby 	 * the type of the neighbor.
681a1a4e97bSnorby 	 */
682a1a4e97bSnorby 	if (nbr->iface->dr == nbr)
683a1a4e97bSnorby 		nctl.iface_state = IF_STA_DR;
684a1a4e97bSnorby 	else if (nbr->iface->bdr == nbr)
685a1a4e97bSnorby 		nctl.iface_state = IF_STA_BACKUP;
686a1a4e97bSnorby 	else if (nbr->iface->state & IF_STA_MULTI)
687a1a4e97bSnorby 		nctl.iface_state = IF_STA_DROTHER;
688a1a4e97bSnorby 	else
689a1a4e97bSnorby 		nctl.iface_state = nbr->iface->state;
690a1a4e97bSnorby 
691a1a4e97bSnorby 	nctl.state_chng_cnt = nbr->stats.sta_chng;
692a1a4e97bSnorby 
693a1a4e97bSnorby 	nctl.priority = nbr->priority;
694a1a4e97bSnorby 	nctl.options = nbr->options;
695a1a4e97bSnorby 
696a1a4e97bSnorby 	gettimeofday(&now, NULL);
697a1a4e97bSnorby 	if (evtimer_pending(&nbr->inactivity_timer, &tv)) {
698a1a4e97bSnorby 		timersub(&tv, &now, &res);
699a1a4e97bSnorby 		if (nbr->state & NBR_STA_DOWN)
700a1a4e97bSnorby 			nctl.dead_timer = DEFAULT_NBR_TMOUT - res.tv_sec;
701a1a4e97bSnorby 		else
702a1a4e97bSnorby 			nctl.dead_timer = res.tv_sec;
703a1a4e97bSnorby 	} else
704a1a4e97bSnorby 		nctl.dead_timer = 0;
705a1a4e97bSnorby 
706a1a4e97bSnorby 	if (nbr->state == NBR_STA_FULL) {
707a1a4e97bSnorby 		nctl.uptime = now.tv_sec - nbr->uptime;
708a1a4e97bSnorby 	} else
709a1a4e97bSnorby 		nctl.uptime = 0;
710a1a4e97bSnorby 
711a1a4e97bSnorby 	return (&nctl);
712a1a4e97bSnorby }
713a1a4e97bSnorby 
714a1a4e97bSnorby struct lsa_hdr *
lsa_hdr_new(void)715a1a4e97bSnorby lsa_hdr_new(void)
716a1a4e97bSnorby {
717a1a4e97bSnorby 	struct lsa_hdr	*lsa_hdr = NULL;
718a1a4e97bSnorby 
719a1a4e97bSnorby 	if ((lsa_hdr = calloc(1, sizeof(*lsa_hdr))) == NULL)
720a1a4e97bSnorby 		fatal("lsa_hdr_new");
721a1a4e97bSnorby 
722a1a4e97bSnorby 	return (lsa_hdr);
723a1a4e97bSnorby }
724