xref: /openbsd-src/usr.sbin/ospf6d/database.c (revision 297c3ba291b3015556550fcfed815a77d53e1189)
1*297c3ba2Sclaudio /*	$OpenBSD: database.c,v 1.23 2023/06/21 07:45:47 claudio 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/socket.h>
22a1a4e97bSnorby #include <netinet/in.h>
23df59d22fSclaudio #include <netinet/ip6.h>
24a1a4e97bSnorby #include <arpa/inet.h>
25a1a4e97bSnorby #include <stdlib.h>
26a1a4e97bSnorby #include <string.h>
27a1a4e97bSnorby #include <unistd.h>
28a1a4e97bSnorby 
29a1a4e97bSnorby #include "ospf6d.h"
30a1a4e97bSnorby #include "ospf6.h"
31a1a4e97bSnorby #include "log.h"
32a1a4e97bSnorby #include "ospfe.h"
33a1a4e97bSnorby 
34a1a4e97bSnorby void	db_sum_list_next(struct nbr *);
35a1a4e97bSnorby 
36a1a4e97bSnorby /* database description packet handling */
37a1a4e97bSnorby int
send_db_description(struct nbr * nbr)38a1a4e97bSnorby send_db_description(struct nbr *nbr)
39a1a4e97bSnorby {
4052bf80cbSclaudio 	struct in6_addr		 dst;
41a1a4e97bSnorby 	struct db_dscrp_hdr	 dd_hdr;
42a1a4e97bSnorby 	struct lsa_entry	*le, *nle;
43e39620e5Snicm 	struct ibuf		*buf;
447b65306cSclaudio 	u_int8_t		 bits = 0;
45a1a4e97bSnorby 
46df59d22fSclaudio 	if ((buf = ibuf_open(nbr->iface->mtu - sizeof(struct ip6_hdr))) == NULL)
47a1a4e97bSnorby 		fatal("send_db_description");
48a1a4e97bSnorby 
49a1a4e97bSnorby 	/* OSPF header */
50a1a4e97bSnorby 	if (gen_ospf_hdr(buf, nbr->iface, PACKET_TYPE_DD))
51a1a4e97bSnorby 		goto fail;
52a1a4e97bSnorby 
53a1a4e97bSnorby 	/* reserve space for database description header */
54*297c3ba2Sclaudio 	if (ibuf_add_zero(buf, sizeof(dd_hdr)) == -1)
55a1a4e97bSnorby 		goto fail;
56a1a4e97bSnorby 
57a1a4e97bSnorby 	switch (nbr->state) {
58a1a4e97bSnorby 	case NBR_STA_DOWN:
59a1a4e97bSnorby 	case NBR_STA_ATTEMPT:
60a1a4e97bSnorby 	case NBR_STA_INIT:
61a1a4e97bSnorby 	case NBR_STA_2_WAY:
62a1a4e97bSnorby 	case NBR_STA_SNAP:
639cc19ef1Ssthen 		log_debug("send_db_description: neighbor ID %s (%s): "
647945b887Sdenis 		    "cannot send packet in state %s", inet_ntoa(nbr->id),
659cc19ef1Ssthen 		    nbr->iface->name, nbr_state_name(nbr->state));
667945b887Sdenis 		goto fail;
67a1a4e97bSnorby 	case NBR_STA_XSTRT:
687b65306cSclaudio 		bits |= OSPF_DBD_MS | OSPF_DBD_M | OSPF_DBD_I;
697b65306cSclaudio 		nbr->dd_more = 1;
70a1a4e97bSnorby 		break;
71a1a4e97bSnorby 	case NBR_STA_XCHNG:
727b65306cSclaudio 		if (nbr->dd_master)
737b65306cSclaudio 			bits |= OSPF_DBD_MS;
747b65306cSclaudio 		else
757b65306cSclaudio 			bits &= ~OSPF_DBD_MS;
767b65306cSclaudio 
777b65306cSclaudio 		if (TAILQ_EMPTY(&nbr->db_sum_list)) {
787b65306cSclaudio 			bits &= ~OSPF_DBD_M;
797b65306cSclaudio 			nbr->dd_more = 0;
80a1a4e97bSnorby 		} else {
817b65306cSclaudio 			bits |= OSPF_DBD_M;
827b65306cSclaudio 			nbr->dd_more = 1;
83a1a4e97bSnorby 		}
84a1a4e97bSnorby 
857b65306cSclaudio 		bits &= ~OSPF_DBD_I;
86a1a4e97bSnorby 
870edf49a6Sbluhm 		/* build LSA list */
88a1a4e97bSnorby 		for (le = TAILQ_FIRST(&nbr->db_sum_list); le != NULL &&
897945b887Sdenis 		    ibuf_left(buf) >=  sizeof(struct lsa_hdr); le = nle) {
90a1a4e97bSnorby 			nbr->dd_end = nle = TAILQ_NEXT(le, entry);
91e39620e5Snicm 			if (ibuf_add(buf, le->le_lsa, sizeof(struct lsa_hdr)))
92a1a4e97bSnorby 				goto fail;
93a1a4e97bSnorby 		}
94a1a4e97bSnorby 		break;
95a1a4e97bSnorby 	case NBR_STA_LOAD:
96a1a4e97bSnorby 	case NBR_STA_FULL:
977b65306cSclaudio 		if (nbr->dd_master)
987b65306cSclaudio 			bits |= OSPF_DBD_MS;
997b65306cSclaudio 		else
1007b65306cSclaudio 			bits &= ~OSPF_DBD_MS;
1017b65306cSclaudio 		bits &= ~OSPF_DBD_M;
1027b65306cSclaudio 		bits &= ~OSPF_DBD_I;
103a1a4e97bSnorby 
1047b65306cSclaudio 		nbr->dd_more = 0;
105a1a4e97bSnorby 		break;
106a1a4e97bSnorby 	default:
107a1a4e97bSnorby 		fatalx("send_db_description: unknown neighbor state");
108a1a4e97bSnorby 	}
109a1a4e97bSnorby 
11080375038Sclaudio 	bzero(&dd_hdr, sizeof(dd_hdr));
11180375038Sclaudio 
112a1a4e97bSnorby 	switch (nbr->iface->type) {
113a1a4e97bSnorby 	case IF_TYPE_POINTOPOINT:
11452bf80cbSclaudio 		inet_pton(AF_INET6, AllSPFRouters, &dst);
115a1a4e97bSnorby 		dd_hdr.iface_mtu = htons(nbr->iface->mtu);
116a1a4e97bSnorby 		break;
117a1a4e97bSnorby 	case IF_TYPE_BROADCAST:
11852bf80cbSclaudio 		dst = nbr->addr;
119a1a4e97bSnorby 		dd_hdr.iface_mtu = htons(nbr->iface->mtu);
120a1a4e97bSnorby 		break;
121a1a4e97bSnorby 	case IF_TYPE_NBMA:
122a1a4e97bSnorby 	case IF_TYPE_POINTOMULTIPOINT:
123a1a4e97bSnorby 		/* XXX not supported */
124a1a4e97bSnorby 		break;
125a1a4e97bSnorby 	case IF_TYPE_VIRTUALLINK:
12652bf80cbSclaudio 		dst = nbr->iface->dst;
127a1a4e97bSnorby 		dd_hdr.iface_mtu = 0;
128a1a4e97bSnorby 		break;
129a1a4e97bSnorby 	default:
130a1a4e97bSnorby 		fatalx("send_db_description: unknown interface type");
131a1a4e97bSnorby 	}
132a1a4e97bSnorby 
13377fbfa19Sdenis 	dd_hdr.opts = htonl(area_ospf_options(nbr->iface->area));
1347b65306cSclaudio 	dd_hdr.bits = bits;
135a1a4e97bSnorby 	dd_hdr.dd_seq_num = htonl(nbr->dd_seq_num);
136a1a4e97bSnorby 
137*297c3ba2Sclaudio 	if (ibuf_set(buf, sizeof(struct ospf_hdr), &dd_hdr,
138*297c3ba2Sclaudio 	    sizeof(dd_hdr)) == -1)
139*297c3ba2Sclaudio 		goto fail;
140a1a4e97bSnorby 
141a1a4e97bSnorby 	/* calculate checksum */
142a1a4e97bSnorby 	if (upd_ospf_hdr(buf, nbr->iface))
143a1a4e97bSnorby 		goto fail;
144a1a4e97bSnorby 
145a1a4e97bSnorby 	/* transmit packet */
1467945b887Sdenis 	if (send_packet(nbr->iface, buf, &dst) == -1)
1477945b887Sdenis 		goto fail;
1487945b887Sdenis 
149e39620e5Snicm 	ibuf_free(buf);
1507945b887Sdenis 	return (0);
151a1a4e97bSnorby fail:
152a1a4e97bSnorby 	log_warn("send_db_description");
153e39620e5Snicm 	ibuf_free(buf);
154a1a4e97bSnorby 	return (-1);
155a1a4e97bSnorby }
156a1a4e97bSnorby 
157a1a4e97bSnorby void
recv_db_description(struct nbr * nbr,char * buf,u_int16_t len)158a1a4e97bSnorby recv_db_description(struct nbr *nbr, char *buf, u_int16_t len)
159a1a4e97bSnorby {
160a1a4e97bSnorby 	struct db_dscrp_hdr	 dd_hdr;
161a1a4e97bSnorby 	int			 dupe = 0;
162a1a4e97bSnorby 
163a1a4e97bSnorby 	if (len < sizeof(dd_hdr)) {
1649cc19ef1Ssthen 		log_warnx("recv_db_description: neighbor ID %s (%s): "
1659cc19ef1Ssthen 		    "bad packet size", inet_ntoa(nbr->id), nbr->iface->name);
166a1a4e97bSnorby 		return;
167a1a4e97bSnorby 	}
168a1a4e97bSnorby 	memcpy(&dd_hdr, buf, sizeof(dd_hdr));
169a1a4e97bSnorby 	buf += sizeof(dd_hdr);
170a1a4e97bSnorby 	len -= sizeof(dd_hdr);
171a1a4e97bSnorby 
172a1a4e97bSnorby 	/* db description packet sanity checks */
173a1a4e97bSnorby 	if (ntohs(dd_hdr.iface_mtu) > nbr->iface->mtu) {
1749cc19ef1Ssthen 		log_warnx("recv_db_description: neighbor ID %s (%s): "
1757945b887Sdenis 		    "invalid MTU %d expected %d", inet_ntoa(nbr->id),
1769cc19ef1Ssthen 		    nbr->iface->name, ntohs(dd_hdr.iface_mtu),
1779cc19ef1Ssthen 		    nbr->iface->mtu);
178a1a4e97bSnorby 		return;
179a1a4e97bSnorby 	}
180a1a4e97bSnorby 
181a1a4e97bSnorby 	if (nbr->last_rx_options == dd_hdr.opts &&
182a1a4e97bSnorby 	    nbr->last_rx_bits == dd_hdr.bits &&
1837b65306cSclaudio 	    ntohl(dd_hdr.dd_seq_num) == nbr->dd_seq_num - nbr->dd_master ?
1847b65306cSclaudio 	    1 : 0) {
1859cc19ef1Ssthen 		log_debug("recv_db_description: dupe from "
1869cc19ef1Ssthen 		    "neighbor ID %s (%s)", inet_ntoa(nbr->id),
1879cc19ef1Ssthen 		    nbr->iface->name);
188a1a4e97bSnorby 		dupe = 1;
189a1a4e97bSnorby 	}
190a1a4e97bSnorby 
191a1a4e97bSnorby 	switch (nbr->state) {
192a1a4e97bSnorby 	case NBR_STA_DOWN:
193a1a4e97bSnorby 	case NBR_STA_ATTEMPT:
194a1a4e97bSnorby 	case NBR_STA_2_WAY:
195a1a4e97bSnorby 	case NBR_STA_SNAP:
1969cc19ef1Ssthen 		log_debug("recv_db_description: neighbor ID %s (%s): "
1977945b887Sdenis 		    "packet ignored in state %s", inet_ntoa(nbr->id),
1989cc19ef1Ssthen 		    nbr->iface->name, nbr_state_name(nbr->state));
199a1a4e97bSnorby 		return;
200a1a4e97bSnorby 	case NBR_STA_INIT:
201a1a4e97bSnorby 		/* evaluate dr and bdr after issuing a 2-Way event */
202a1a4e97bSnorby 		nbr_fsm(nbr, NBR_EVT_2_WAY_RCVD);
203a1a4e97bSnorby 		if_fsm(nbr->iface, IF_EVT_NBR_CHNG);
204a1a4e97bSnorby 		if (nbr->state != NBR_STA_XSTRT)
205a1a4e97bSnorby 			return;
206a1a4e97bSnorby 		/* FALLTHROUGH */
207a1a4e97bSnorby 	case NBR_STA_XSTRT:
208a1a4e97bSnorby 		if (dupe)
209a1a4e97bSnorby 			return;
210a1a4e97bSnorby 		/*
211a1a4e97bSnorby 		 * check bits: either I,M,MS or only M
212a1a4e97bSnorby 		 */
213a1a4e97bSnorby 		if (dd_hdr.bits == (OSPF_DBD_I | OSPF_DBD_M | OSPF_DBD_MS)) {
214a1a4e97bSnorby 			/* if nbr Router ID is larger than own -> slave */
215a1a4e97bSnorby 			if ((ntohl(nbr->id.s_addr)) >
216a1a4e97bSnorby 			    ntohl(ospfe_router_id())) {
217a1a4e97bSnorby 				/* slave */
2187b65306cSclaudio 				nbr->dd_master = 0;
219a1a4e97bSnorby 				nbr->dd_seq_num = ntohl(dd_hdr.dd_seq_num);
220a1a4e97bSnorby 
221a1a4e97bSnorby 				/* event negotiation done */
222a1a4e97bSnorby 				nbr_fsm(nbr, NBR_EVT_NEG_DONE);
223a1a4e97bSnorby 			}
224a1a4e97bSnorby 		} else if (!(dd_hdr.bits & (OSPF_DBD_I | OSPF_DBD_MS))) {
225a1a4e97bSnorby 			/* M only case: we are master */
226a1a4e97bSnorby 			if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num) {
2277945b887Sdenis 				log_warnx("recv_db_description: "
2289cc19ef1Ssthen 				    "neighbor ID %s (%s): "
2297945b887Sdenis 				    "invalid seq num, mine %x his %x",
2309cc19ef1Ssthen 				    inet_ntoa(nbr->id), nbr->iface->name,
2319cc19ef1Ssthen 				    nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
232a1a4e97bSnorby 				return;
233a1a4e97bSnorby 			}
234a1a4e97bSnorby 			nbr->dd_seq_num++;
235a1a4e97bSnorby 
236fadd0157Sclaudio 			/* event negotiation done */
237fadd0157Sclaudio 			nbr_fsm(nbr, NBR_EVT_NEG_DONE);
238fadd0157Sclaudio 
239a1a4e97bSnorby 			/* this packet may already have data so pass it on */
240a1a4e97bSnorby 			if (len > 0) {
241a1a4e97bSnorby 				nbr->dd_pending++;
242a1a4e97bSnorby 				ospfe_imsg_compose_rde(IMSG_DD, nbr->peerid,
243a1a4e97bSnorby 				    0, buf, len);
244a1a4e97bSnorby 			}
245a1a4e97bSnorby 		} else {
246a1a4e97bSnorby 			/* ignore packet */
2479cc19ef1Ssthen 			log_debug("recv_db_description: neighbor ID %s (%s): "
2487945b887Sdenis 			    "packet ignored in state %s (bad flags)",
2499cc19ef1Ssthen 			    inet_ntoa(nbr->id), nbr->iface->name,
2509cc19ef1Ssthen 			    nbr_state_name(nbr->state));
251a1a4e97bSnorby 		}
252a1a4e97bSnorby 		break;
253a1a4e97bSnorby 	case NBR_STA_XCHNG:
254a1a4e97bSnorby 	case NBR_STA_LOAD:
255a1a4e97bSnorby 	case NBR_STA_FULL:
256a1a4e97bSnorby 		if (dd_hdr.bits & OSPF_DBD_I ||
2577b65306cSclaudio 		    !(dd_hdr.bits & OSPF_DBD_MS) == !nbr->dd_master) {
2589cc19ef1Ssthen 			log_warnx("recv_db_description: neighbor ID %s (%s): "
2599cc19ef1Ssthen 			    "seq num mismatch, bad flags", inet_ntoa(nbr->id),
2609cc19ef1Ssthen 			    nbr->iface->name);
261a1a4e97bSnorby 			nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
262a1a4e97bSnorby 			return;
263a1a4e97bSnorby 		}
264a1a4e97bSnorby 
265a1a4e97bSnorby 		if (nbr->last_rx_options != dd_hdr.opts) {
2669cc19ef1Ssthen 			log_warnx("recv_db_description: neighbor ID %s (%s): "
2677945b887Sdenis 			    "seq num mismatch, bad options",
2689cc19ef1Ssthen 			    inet_ntoa(nbr->id), nbr->iface->name);
269a1a4e97bSnorby 			nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
270a1a4e97bSnorby 			return;
271a1a4e97bSnorby 		}
272a1a4e97bSnorby 
273a1a4e97bSnorby 		if (dupe) {
2747b65306cSclaudio 			if (!nbr->dd_master)
275a1a4e97bSnorby 				/* retransmit */
276a1a4e97bSnorby 				start_db_tx_timer(nbr);
277a1a4e97bSnorby 			return;
278a1a4e97bSnorby 		}
279a1a4e97bSnorby 
280a1a4e97bSnorby 		if (nbr->state != NBR_STA_XCHNG) {
2819cc19ef1Ssthen 			log_warnx("recv_db_description: neighbor ID %s (%s): "
2827945b887Sdenis 			    "invalid seq num, mine %x his %x",
2839cc19ef1Ssthen 			    inet_ntoa(nbr->id), nbr->iface->name,
2849cc19ef1Ssthen 			    nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
285a1a4e97bSnorby 			nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
286a1a4e97bSnorby 			return;
287a1a4e97bSnorby 		}
288a1a4e97bSnorby 
289a1a4e97bSnorby 		/* sanity check dd seq number */
2907b65306cSclaudio 		if (nbr->dd_master) {
291a1a4e97bSnorby 			/* master */
292a1a4e97bSnorby 			if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num) {
2937945b887Sdenis 				log_warnx("recv_db_description: "
2949cc19ef1Ssthen 				    "neighbor ID %s (%s): "
2957945b887Sdenis 				    "invalid seq num, mine %x his %x, master",
2969cc19ef1Ssthen 				    inet_ntoa(nbr->id), nbr->iface->name,
2979cc19ef1Ssthen 				    nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
298a1a4e97bSnorby 				nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
299a1a4e97bSnorby 				return;
300a1a4e97bSnorby 			}
301a1a4e97bSnorby 			nbr->dd_seq_num++;
302a1a4e97bSnorby 		} else {
303a1a4e97bSnorby 			/* slave */
304a1a4e97bSnorby 			if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num + 1) {
3057945b887Sdenis 				log_warnx("recv_db_description: "
3069cc19ef1Ssthen 				    "neighbor ID %s (%s): "
3077945b887Sdenis 				    "invalid seq num, mine %x his %x, slave",
3089cc19ef1Ssthen 				    inet_ntoa(nbr->id), nbr->iface->name,
3099cc19ef1Ssthen 				    nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
310a1a4e97bSnorby 				nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
311a1a4e97bSnorby 				return;
312a1a4e97bSnorby 			}
313a1a4e97bSnorby 			nbr->dd_seq_num = ntohl(dd_hdr.dd_seq_num);
314a1a4e97bSnorby 		}
315a1a4e97bSnorby 
316a1a4e97bSnorby 		/* forward to RDE and let it decide which LSAs to request */
317a1a4e97bSnorby 		if (len > 0) {
318a1a4e97bSnorby 			nbr->dd_pending++;
319a1a4e97bSnorby 			ospfe_imsg_compose_rde(IMSG_DD, nbr->peerid, 0,
320a1a4e97bSnorby 			    buf, len);
321a1a4e97bSnorby 		}
322a1a4e97bSnorby 
323a1a4e97bSnorby 		/* next packet */
324a1a4e97bSnorby 		db_sum_list_next(nbr);
325a1a4e97bSnorby 		start_db_tx_timer(nbr);
326a1a4e97bSnorby 
327a1a4e97bSnorby 		if (!(dd_hdr.bits & OSPF_DBD_M) &&
328a1a4e97bSnorby 		    TAILQ_EMPTY(&nbr->db_sum_list))
3297b65306cSclaudio 			if (!nbr->dd_master || !nbr->dd_more)
330a1a4e97bSnorby 				nbr_fsm(nbr, NBR_EVT_XCHNG_DONE);
331a1a4e97bSnorby 		break;
332a1a4e97bSnorby 	default:
333a1a4e97bSnorby 		fatalx("recv_db_description: unknown neighbor state");
334a1a4e97bSnorby 	}
335a1a4e97bSnorby 
336a1a4e97bSnorby 	nbr->last_rx_options = dd_hdr.opts;
337a1a4e97bSnorby 	nbr->last_rx_bits = dd_hdr.bits;
338a1a4e97bSnorby }
339a1a4e97bSnorby 
340a1a4e97bSnorby void
db_sum_list_add(struct nbr * nbr,struct lsa_hdr * lsa)341a1a4e97bSnorby db_sum_list_add(struct nbr *nbr, struct lsa_hdr *lsa)
342a1a4e97bSnorby {
343a1a4e97bSnorby 	struct lsa_entry	*le;
344a1a4e97bSnorby 
345a1a4e97bSnorby 	if ((le = calloc(1, sizeof(*le))) == NULL)
346a1a4e97bSnorby 		fatal("db_sum_list_add");
347a1a4e97bSnorby 
348a1a4e97bSnorby 	TAILQ_INSERT_TAIL(&nbr->db_sum_list, le, entry);
349a1a4e97bSnorby 	le->le_lsa = lsa;
350a1a4e97bSnorby }
351a1a4e97bSnorby 
352a1a4e97bSnorby void
db_sum_list_next(struct nbr * nbr)353a1a4e97bSnorby db_sum_list_next(struct nbr *nbr)
354a1a4e97bSnorby {
355a1a4e97bSnorby 	struct lsa_entry	*le;
356a1a4e97bSnorby 
357a1a4e97bSnorby 	while ((le = TAILQ_FIRST(&nbr->db_sum_list)) != nbr->dd_end) {
358a1a4e97bSnorby 		TAILQ_REMOVE(&nbr->db_sum_list, le, entry);
359a1a4e97bSnorby 		free(le->le_lsa);
360a1a4e97bSnorby 		free(le);
361a1a4e97bSnorby 	}
362a1a4e97bSnorby }
363a1a4e97bSnorby 
364a1a4e97bSnorby void
db_sum_list_clr(struct nbr * nbr)365a1a4e97bSnorby db_sum_list_clr(struct nbr *nbr)
366a1a4e97bSnorby {
367a1a4e97bSnorby 	nbr->dd_end = NULL;
368a1a4e97bSnorby 	db_sum_list_next(nbr);
369a1a4e97bSnorby }
370a1a4e97bSnorby 
371a1a4e97bSnorby /* timers */
372a1a4e97bSnorby void
db_tx_timer(int fd,short event,void * arg)373a1a4e97bSnorby db_tx_timer(int fd, short event, void *arg)
374a1a4e97bSnorby {
375a1a4e97bSnorby 	struct nbr *nbr = arg;
376a1a4e97bSnorby 	struct timeval tv;
377a1a4e97bSnorby 
378a1a4e97bSnorby 	switch (nbr->state) {
379a1a4e97bSnorby 	case NBR_STA_DOWN:
380a1a4e97bSnorby 	case NBR_STA_ATTEMPT:
381a1a4e97bSnorby 	case NBR_STA_INIT:
382a1a4e97bSnorby 	case NBR_STA_2_WAY:
383a1a4e97bSnorby 	case NBR_STA_SNAP:
384a1a4e97bSnorby 		return ;
385a1a4e97bSnorby 	case NBR_STA_XSTRT:
386a1a4e97bSnorby 	case NBR_STA_XCHNG:
387a1a4e97bSnorby 	case NBR_STA_LOAD:
388a1a4e97bSnorby 	case NBR_STA_FULL:
389a1a4e97bSnorby 		send_db_description(nbr);
390a1a4e97bSnorby 		break;
391a1a4e97bSnorby 	default:
3929cc19ef1Ssthen 		log_debug("db_tx_timer: neighbor ID %s (%s): "
3939cc19ef1Ssthen 		    "unknown neighbor state",
3949cc19ef1Ssthen 		    inet_ntoa(nbr->id), nbr->iface->name);
395a1a4e97bSnorby 		break;
396a1a4e97bSnorby 	}
397a1a4e97bSnorby 
398a1a4e97bSnorby 	/* reschedule db_tx_timer but only in master mode */
3997b65306cSclaudio 	if (nbr->dd_master) {
400a1a4e97bSnorby 		timerclear(&tv);
401a1a4e97bSnorby 		tv.tv_sec = nbr->iface->rxmt_interval;
402a1a4e97bSnorby 		if (evtimer_add(&nbr->db_tx_timer, &tv) == -1)
403a1a4e97bSnorby 			fatal("db_tx_timer");
404a1a4e97bSnorby 	}
405a1a4e97bSnorby }
406a1a4e97bSnorby 
407a1a4e97bSnorby void
start_db_tx_timer(struct nbr * nbr)408a1a4e97bSnorby start_db_tx_timer(struct nbr *nbr)
409a1a4e97bSnorby {
410a1a4e97bSnorby 	struct timeval	tv;
411a1a4e97bSnorby 
412a1a4e97bSnorby 	if (nbr == nbr->iface->self)
413a1a4e97bSnorby 		return;
414a1a4e97bSnorby 
415a1a4e97bSnorby 	timerclear(&tv);
416a1a4e97bSnorby 	if (evtimer_add(&nbr->db_tx_timer, &tv) == -1)
417a1a4e97bSnorby 		fatal("start_db_tx_timer");
418a1a4e97bSnorby }
419a1a4e97bSnorby 
420a1a4e97bSnorby void
stop_db_tx_timer(struct nbr * nbr)421a1a4e97bSnorby stop_db_tx_timer(struct nbr *nbr)
422a1a4e97bSnorby {
423a1a4e97bSnorby 	if (nbr == nbr->iface->self)
424a1a4e97bSnorby 		return;
425a1a4e97bSnorby 
426a1a4e97bSnorby 	if (evtimer_del(&nbr->db_tx_timer) == -1)
427a1a4e97bSnorby 		fatal("stop_db_tx_timer");
428a1a4e97bSnorby }
429