xref: /openbsd-src/usr.sbin/ospfd/database.c (revision 4f4fe40bc9d06de09f4af934b87299ab1ee3cc66)
1*4f4fe40bSflorian /*	$OpenBSD: database.c,v 1.38 2024/08/21 15:18:00 florian Exp $ */
2204df0f8Sclaudio 
3204df0f8Sclaudio /*
4204df0f8Sclaudio  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
5367f601bSnorby  * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
6204df0f8Sclaudio  *
7204df0f8Sclaudio  * Permission to use, copy, modify, and distribute this software for any
8204df0f8Sclaudio  * purpose with or without fee is hereby granted, provided that the above
9204df0f8Sclaudio  * copyright notice and this permission notice appear in all copies.
10204df0f8Sclaudio  *
11204df0f8Sclaudio  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12204df0f8Sclaudio  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13204df0f8Sclaudio  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14204df0f8Sclaudio  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15204df0f8Sclaudio  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16204df0f8Sclaudio  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17204df0f8Sclaudio  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18204df0f8Sclaudio  */
19204df0f8Sclaudio 
20204df0f8Sclaudio #include <sys/types.h>
21204df0f8Sclaudio #include <sys/socket.h>
22204df0f8Sclaudio #include <netinet/in.h>
230491ce75Sclaudio #include <netinet/ip.h>
24204df0f8Sclaudio #include <arpa/inet.h>
25204df0f8Sclaudio #include <stdlib.h>
26204df0f8Sclaudio #include <string.h>
27204df0f8Sclaudio #include <unistd.h>
28204df0f8Sclaudio 
29204df0f8Sclaudio #include "ospfd.h"
30204df0f8Sclaudio #include "ospf.h"
31204df0f8Sclaudio #include "log.h"
32204df0f8Sclaudio #include "ospfe.h"
33204df0f8Sclaudio 
34204df0f8Sclaudio extern struct ospfd_conf	*oeconf;
35204df0f8Sclaudio 
36204df0f8Sclaudio void	db_sum_list_next(struct nbr *);
37204df0f8Sclaudio 
38204df0f8Sclaudio /* database description packet handling */
39204df0f8Sclaudio int
40204df0f8Sclaudio send_db_description(struct nbr *nbr)
41204df0f8Sclaudio {
42204df0f8Sclaudio 	struct sockaddr_in	 dst;
430491ce75Sclaudio 	struct db_dscrp_hdr	 dd_hdr;
44204df0f8Sclaudio 	struct lsa_entry	*le, *nle;
45e39620e5Snicm 	struct ibuf		*buf;
464d267a96Sclaudio 	u_int8_t		 bits = 0;
47204df0f8Sclaudio 
48e39620e5Snicm 	if ((buf = ibuf_open(nbr->iface->mtu - sizeof(struct ip))) == NULL)
49204df0f8Sclaudio 		fatal("send_db_description");
50204df0f8Sclaudio 
51204df0f8Sclaudio 	/* OSPF header */
520491ce75Sclaudio 	if (gen_ospf_hdr(buf, nbr->iface, PACKET_TYPE_DD))
530491ce75Sclaudio 		goto fail;
54204df0f8Sclaudio 
550491ce75Sclaudio 	/* reserve space for database description header */
5643e70bb4Sclaudio 	if (ibuf_add_zero(buf, sizeof(dd_hdr)) == -1)
570491ce75Sclaudio 		goto fail;
58204df0f8Sclaudio 
59204df0f8Sclaudio 	switch (nbr->state) {
60204df0f8Sclaudio 	case NBR_STA_DOWN:
61204df0f8Sclaudio 	case NBR_STA_ATTEMPT:
62204df0f8Sclaudio 	case NBR_STA_INIT:
63204df0f8Sclaudio 	case NBR_STA_2_WAY:
64204df0f8Sclaudio 	case NBR_STA_SNAP:
659cc19ef1Ssthen 		log_debug("send_db_description: neighbor ID %s (%s): "
669a2eee35Sclaudio 		    "cannot send packet in state %s", inet_ntoa(nbr->id),
679cc19ef1Ssthen 		    nbr->iface->name, nbr_state_name(nbr->state));
6825a742ccSremi 		goto fail;
69204df0f8Sclaudio 	case NBR_STA_XSTRT:
704d267a96Sclaudio 		bits |= OSPF_DBD_MS | OSPF_DBD_M | OSPF_DBD_I;
714d267a96Sclaudio 		nbr->dd_more = 1;
72204df0f8Sclaudio 		break;
73204df0f8Sclaudio 	case NBR_STA_XCHNG:
744d267a96Sclaudio 		if (nbr->dd_master)
754d267a96Sclaudio 			bits |= OSPF_DBD_MS;
764d267a96Sclaudio 		else
774d267a96Sclaudio 			bits &= ~OSPF_DBD_MS;
784d267a96Sclaudio 
794d267a96Sclaudio 		if (TAILQ_EMPTY(&nbr->db_sum_list)) {
804d267a96Sclaudio 			bits &= ~OSPF_DBD_M;
814d267a96Sclaudio 			nbr->dd_more = 0;
82204df0f8Sclaudio 		} else {
834d267a96Sclaudio 			bits |= OSPF_DBD_M;
844d267a96Sclaudio 			nbr->dd_more = 1;
85204df0f8Sclaudio 		}
86204df0f8Sclaudio 
874d267a96Sclaudio 		bits &= ~OSPF_DBD_I;
88204df0f8Sclaudio 
890491ce75Sclaudio 		/* build LSA list, keep space for a possible md5 sum */
900491ce75Sclaudio 		for (le = TAILQ_FIRST(&nbr->db_sum_list); le != NULL &&
91e39620e5Snicm 		    ibuf_left(buf) >= MD5_DIGEST_LENGTH + sizeof(struct lsa_hdr);
929627de93Sclaudio 		    le = nle) {
93204df0f8Sclaudio 			nbr->dd_end = nle = TAILQ_NEXT(le, entry);
94e39620e5Snicm 			if (ibuf_add(buf, le->le_lsa, sizeof(struct lsa_hdr)))
950491ce75Sclaudio 				goto fail;
96204df0f8Sclaudio 		}
97204df0f8Sclaudio 		break;
98204df0f8Sclaudio 	case NBR_STA_LOAD:
99204df0f8Sclaudio 	case NBR_STA_FULL:
1004d267a96Sclaudio 		if (nbr->dd_master)
1014d267a96Sclaudio 			bits |= OSPF_DBD_MS;
1024d267a96Sclaudio 		else
1034d267a96Sclaudio 			bits &= ~OSPF_DBD_MS;
1044d267a96Sclaudio 		bits &= ~OSPF_DBD_M;
1054d267a96Sclaudio 		bits &= ~OSPF_DBD_I;
106204df0f8Sclaudio 
1074d267a96Sclaudio 		nbr->dd_more = 0;
108204df0f8Sclaudio 		break;
109204df0f8Sclaudio 	default:
1100491ce75Sclaudio 		fatalx("send_db_description: unknown neighbor state");
111204df0f8Sclaudio 	}
112204df0f8Sclaudio 
113204df0f8Sclaudio 	/* set destination */
114204df0f8Sclaudio 	dst.sin_family = AF_INET;
115204df0f8Sclaudio 	dst.sin_len = sizeof(struct sockaddr_in);
116204df0f8Sclaudio 
117204df0f8Sclaudio 	switch (nbr->iface->type) {
118204df0f8Sclaudio 	case IF_TYPE_POINTOPOINT:
119*4f4fe40bSflorian 		inet_pton(AF_INET, AllSPFRouters, &dst.sin_addr);
1200491ce75Sclaudio 		dd_hdr.iface_mtu = htons(nbr->iface->mtu);
121204df0f8Sclaudio 		break;
122204df0f8Sclaudio 	case IF_TYPE_BROADCAST:
123204df0f8Sclaudio 		dst.sin_addr = nbr->addr;
1240491ce75Sclaudio 		dd_hdr.iface_mtu = htons(nbr->iface->mtu);
125204df0f8Sclaudio 		break;
126204df0f8Sclaudio 	case IF_TYPE_NBMA:
127204df0f8Sclaudio 	case IF_TYPE_POINTOMULTIPOINT:
128bfa55e2fSnorby 		/* XXX not supported */
129bfa55e2fSnorby 		break;
130204df0f8Sclaudio 	case IF_TYPE_VIRTUALLINK:
131bfa55e2fSnorby 		dst.sin_addr = nbr->iface->dst;
1320491ce75Sclaudio 		dd_hdr.iface_mtu = 0;
133204df0f8Sclaudio 		break;
134204df0f8Sclaudio 	default:
135204df0f8Sclaudio 		fatalx("send_db_description: unknown interface type");
136204df0f8Sclaudio 	}
137204df0f8Sclaudio 
138097ed198Sclaudio 	/* XXX button or not for opaque LSA? */
139097ed198Sclaudio 	dd_hdr.opts = area_ospf_options(nbr->iface->area) | OSPF_OPTION_O;
1404d267a96Sclaudio 	dd_hdr.bits = bits;
1410491ce75Sclaudio 	dd_hdr.dd_seq_num = htonl(nbr->dd_seq_num);
1420491ce75Sclaudio 
14343e70bb4Sclaudio 	if (ibuf_set(buf, sizeof(struct ospf_hdr), &dd_hdr,
14443e70bb4Sclaudio 	    sizeof(dd_hdr)) == -1)
14543e70bb4Sclaudio 		goto fail;
146204df0f8Sclaudio 
147204df0f8Sclaudio 	/* update authentication and calculate checksum */
1480491ce75Sclaudio 	if (auth_gen(buf, nbr->iface))
1490491ce75Sclaudio 		goto fail;
150204df0f8Sclaudio 
151204df0f8Sclaudio 	/* transmit packet */
15225a742ccSremi 	if (send_packet(nbr->iface, buf, &dst) == -1)
15325a742ccSremi 		goto fail;
15425a742ccSremi 
155e39620e5Snicm 	ibuf_free(buf);
15625a742ccSremi 	return (0);
1570491ce75Sclaudio fail:
15825a742ccSremi 	log_warn("%s", __func__);
159e39620e5Snicm 	ibuf_free(buf);
1600491ce75Sclaudio 	return (-1);
161204df0f8Sclaudio }
162204df0f8Sclaudio 
163204df0f8Sclaudio void
164204df0f8Sclaudio recv_db_description(struct nbr *nbr, char *buf, u_int16_t len)
165204df0f8Sclaudio {
166204df0f8Sclaudio 	struct db_dscrp_hdr	 dd_hdr;
167204df0f8Sclaudio 	int			 dupe = 0;
168204df0f8Sclaudio 
169204df0f8Sclaudio 	if (len < sizeof(dd_hdr)) {
1709cc19ef1Ssthen 		log_warnx("recv_db_description: neighbor ID %s (%s): "
1719cc19ef1Ssthen 		    "bad packet size", inet_ntoa(nbr->id), nbr->iface->name);
172204df0f8Sclaudio 		return;
173204df0f8Sclaudio 	}
174204df0f8Sclaudio 	memcpy(&dd_hdr, buf, sizeof(dd_hdr));
175204df0f8Sclaudio 	buf += sizeof(dd_hdr);
176204df0f8Sclaudio 	len -= sizeof(dd_hdr);
177204df0f8Sclaudio 
178204df0f8Sclaudio 	/* db description packet sanity checks */
179c1d15234Sclaudio 	if (ntohs(dd_hdr.iface_mtu) > nbr->iface->mtu) {
1809cc19ef1Ssthen 		log_warnx("recv_db_description: neighbor ID %s (%s): "
1819a2eee35Sclaudio 		    "invalid MTU %d expected %d", inet_ntoa(nbr->id),
1829cc19ef1Ssthen 		    nbr->iface->name, ntohs(dd_hdr.iface_mtu),
1839cc19ef1Ssthen 		    nbr->iface->mtu);
184204df0f8Sclaudio 		return;
185204df0f8Sclaudio 	}
186204df0f8Sclaudio 
187204df0f8Sclaudio 	if (nbr->last_rx_options == dd_hdr.opts &&
188204df0f8Sclaudio 	    nbr->last_rx_bits == dd_hdr.bits &&
1894d267a96Sclaudio 	    ntohl(dd_hdr.dd_seq_num) == nbr->dd_seq_num - nbr->dd_master ?
1904d267a96Sclaudio 	    1 : 0) {
1919cc19ef1Ssthen 		log_debug("recv_db_description: dupe from "
1929cc19ef1Ssthen 		    "neighbor ID %s (%s)", inet_ntoa(nbr->id),
1939cc19ef1Ssthen 		    nbr->iface->name);
194204df0f8Sclaudio 		dupe = 1;
195204df0f8Sclaudio 	}
196204df0f8Sclaudio 
197204df0f8Sclaudio 	switch (nbr->state) {
198204df0f8Sclaudio 	case NBR_STA_DOWN:
199204df0f8Sclaudio 	case NBR_STA_ATTEMPT:
200204df0f8Sclaudio 	case NBR_STA_2_WAY:
201204df0f8Sclaudio 	case NBR_STA_SNAP:
2029cc19ef1Ssthen 		log_debug("recv_db_description: neighbor ID %s (%s): "
2039a2eee35Sclaudio 		    "packet ignored in state %s", inet_ntoa(nbr->id),
2049cc19ef1Ssthen 		    nbr->iface->name, nbr_state_name(nbr->state));
205204df0f8Sclaudio 		return;
206204df0f8Sclaudio 	case NBR_STA_INIT:
2073bb9eff8Sclaudio 		/* evaluate dr and bdr after issuing a 2-Way event */
208204df0f8Sclaudio 		nbr_fsm(nbr, NBR_EVT_2_WAY_RCVD);
2093bb9eff8Sclaudio 		if_fsm(nbr->iface, IF_EVT_NBR_CHNG);
210204df0f8Sclaudio 		if (nbr->state != NBR_STA_XSTRT)
211204df0f8Sclaudio 			return;
212204df0f8Sclaudio 		/* FALLTHROUGH */
213204df0f8Sclaudio 	case NBR_STA_XSTRT:
214204df0f8Sclaudio 		if (dupe)
215204df0f8Sclaudio 			return;
216097ed198Sclaudio 		nbr->capa_options = dd_hdr.opts;
217097ed198Sclaudio 		if ((nbr->capa_options & nbr->options) != nbr->options) {
2189cc19ef1Ssthen 			log_warnx("recv_db_description: neighbor ID %s (%s) "
219097ed198Sclaudio 			    "sent inconsistent options %x vs. %x",
2209cc19ef1Ssthen 			    inet_ntoa(nbr->id), nbr->iface->name,
2219cc19ef1Ssthen 			    nbr->capa_options, nbr->options);
222097ed198Sclaudio 		}
223204df0f8Sclaudio 		/*
224204df0f8Sclaudio 		 * check bits: either I,M,MS or only M
225204df0f8Sclaudio 		 */
226204df0f8Sclaudio 		if (dd_hdr.bits == (OSPF_DBD_I | OSPF_DBD_M | OSPF_DBD_MS)) {
227204df0f8Sclaudio 			/* if nbr Router ID is larger than own -> slave */
228204df0f8Sclaudio 			if ((ntohl(nbr->id.s_addr)) >
229f12637e5Smsf 			    ntohl(ospfe_router_id())) {
230204df0f8Sclaudio 				/* slave */
2314d267a96Sclaudio 				nbr->dd_master = 0;
232204df0f8Sclaudio 				nbr->dd_seq_num = ntohl(dd_hdr.dd_seq_num);
233204df0f8Sclaudio 
234204df0f8Sclaudio 				/* event negotiation done */
235204df0f8Sclaudio 				nbr_fsm(nbr, NBR_EVT_NEG_DONE);
236204df0f8Sclaudio 			}
237d7363de5Sclaudio 		} else if (!(dd_hdr.bits & (OSPF_DBD_I | OSPF_DBD_MS))) {
2383bb9eff8Sclaudio 			/* M only case: we are master */
239204df0f8Sclaudio 			if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num) {
2409a2eee35Sclaudio 				log_warnx("recv_db_description: "
2419cc19ef1Ssthen 				    "neighbor ID %s (%s): "
2429a2eee35Sclaudio 				    "invalid seq num, mine %x his %x",
2439cc19ef1Ssthen 				    inet_ntoa(nbr->id), nbr->iface->name,
2449cc19ef1Ssthen 				    nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
245204df0f8Sclaudio 				return;
246204df0f8Sclaudio 			}
247204df0f8Sclaudio 			nbr->dd_seq_num++;
248204df0f8Sclaudio 
24998b447a7Sclaudio 			/* event negotiation done */
25098b447a7Sclaudio 			nbr_fsm(nbr, NBR_EVT_NEG_DONE);
25198b447a7Sclaudio 
252204df0f8Sclaudio 			/* this packet may already have data so pass it on */
253299d99d9Sclaudio 			if (len > 0) {
254299d99d9Sclaudio 				nbr->dd_pending++;
255204df0f8Sclaudio 				ospfe_imsg_compose_rde(IMSG_DD, nbr->peerid,
256204df0f8Sclaudio 				    0, buf, len);
257299d99d9Sclaudio 			}
258204df0f8Sclaudio 		} else {
259204df0f8Sclaudio 			/* ignore packet */
2609cc19ef1Ssthen 			log_debug("recv_db_description: neighbor ID %s (%s): "
2619a2eee35Sclaudio 			    "packet ignored in state %s (bad flags)",
2629cc19ef1Ssthen 			    inet_ntoa(nbr->id), nbr->iface->name,
2639cc19ef1Ssthen 			    nbr_state_name(nbr->state));
264204df0f8Sclaudio 		}
265204df0f8Sclaudio 		break;
266204df0f8Sclaudio 	case NBR_STA_XCHNG:
267204df0f8Sclaudio 	case NBR_STA_LOAD:
268204df0f8Sclaudio 	case NBR_STA_FULL:
269204df0f8Sclaudio 		if (dd_hdr.bits & OSPF_DBD_I ||
2704d267a96Sclaudio 		    !(dd_hdr.bits & OSPF_DBD_MS) == !nbr->dd_master) {
2719cc19ef1Ssthen 			log_warnx("recv_db_description: neighbor ID %s (%s): "
2729cc19ef1Ssthen 			    "seq num mismatch, bad flags", inet_ntoa(nbr->id),
2739cc19ef1Ssthen 			    nbr->iface->name);
274204df0f8Sclaudio 			nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
275204df0f8Sclaudio 			return;
276204df0f8Sclaudio 		}
277204df0f8Sclaudio 
278204df0f8Sclaudio 		if (nbr->last_rx_options != dd_hdr.opts) {
2799cc19ef1Ssthen 			log_warnx("recv_db_description: neighbor ID %s (%s): "
2809a2eee35Sclaudio 			    "seq num mismatch, bad options",
2819cc19ef1Ssthen 			    inet_ntoa(nbr->id), nbr->iface->name);
282204df0f8Sclaudio 			nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
283204df0f8Sclaudio 			return;
284204df0f8Sclaudio 		}
285204df0f8Sclaudio 
286204df0f8Sclaudio 		if (dupe) {
2874d267a96Sclaudio 			if (!nbr->dd_master)
288204df0f8Sclaudio 				/* retransmit */
289204df0f8Sclaudio 				start_db_tx_timer(nbr);
290204df0f8Sclaudio 			return;
291204df0f8Sclaudio 		}
292204df0f8Sclaudio 
293204df0f8Sclaudio 		if (nbr->state != NBR_STA_XCHNG) {
2949cc19ef1Ssthen 			log_warnx("recv_db_description: neighbor ID %s (%s): "
2959a2eee35Sclaudio 			    "invalid seq num, mine %x his %x",
2969cc19ef1Ssthen 			    inet_ntoa(nbr->id), nbr->iface->name,
2979cc19ef1Ssthen 			    nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
298204df0f8Sclaudio 			nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
299204df0f8Sclaudio 			return;
300204df0f8Sclaudio 		}
301204df0f8Sclaudio 
302204df0f8Sclaudio 		/* sanity check dd seq number */
3034d267a96Sclaudio 		if (nbr->dd_master) {
304204df0f8Sclaudio 			/* master */
305204df0f8Sclaudio 			if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num) {
3069a2eee35Sclaudio 				log_warnx("recv_db_description: "
3079cc19ef1Ssthen 				    "neighbor ID %s (%s): "
3089a2eee35Sclaudio 				    "invalid seq num, mine %x his %x, master",
3099cc19ef1Ssthen 				    inet_ntoa(nbr->id), nbr->iface->name,
3109cc19ef1Ssthen 				    nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
311204df0f8Sclaudio 				nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
312204df0f8Sclaudio 				return;
313204df0f8Sclaudio 			}
314204df0f8Sclaudio 			nbr->dd_seq_num++;
315204df0f8Sclaudio 		} else {
316204df0f8Sclaudio 			/* slave */
317204df0f8Sclaudio 			if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num + 1) {
3189a2eee35Sclaudio 				log_warnx("recv_db_description: "
3199cc19ef1Ssthen 				    "neighbor ID %s (%s): "
3209a2eee35Sclaudio 				    "invalid seq num, mine %x his %x, slave",
3219cc19ef1Ssthen 				    inet_ntoa(nbr->id), nbr->iface->name,
3229cc19ef1Ssthen 				    nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
323204df0f8Sclaudio 				nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
324204df0f8Sclaudio 				return;
325204df0f8Sclaudio 			}
326204df0f8Sclaudio 			nbr->dd_seq_num = ntohl(dd_hdr.dd_seq_num);
327204df0f8Sclaudio 		}
328204df0f8Sclaudio 
329611e3786Sclaudio 		/* forward to RDE and let it decide which LSAs to request */
330299d99d9Sclaudio 		if (len > 0) {
331299d99d9Sclaudio 			nbr->dd_pending++;
332204df0f8Sclaudio 			ospfe_imsg_compose_rde(IMSG_DD, nbr->peerid, 0,
333204df0f8Sclaudio 			    buf, len);
334299d99d9Sclaudio 		}
335204df0f8Sclaudio 
336204df0f8Sclaudio 		/* next packet */
337204df0f8Sclaudio 		db_sum_list_next(nbr);
338204df0f8Sclaudio 		start_db_tx_timer(nbr);
339204df0f8Sclaudio 
340204df0f8Sclaudio 		if (!(dd_hdr.bits & OSPF_DBD_M) &&
341204df0f8Sclaudio 		    TAILQ_EMPTY(&nbr->db_sum_list))
3424d267a96Sclaudio 			if (!nbr->dd_master || !nbr->dd_more)
343204df0f8Sclaudio 				nbr_fsm(nbr, NBR_EVT_XCHNG_DONE);
344204df0f8Sclaudio 		break;
345204df0f8Sclaudio 	default:
346204df0f8Sclaudio 		fatalx("recv_db_description: unknown neighbor state");
347204df0f8Sclaudio 	}
348204df0f8Sclaudio 
349204df0f8Sclaudio 	nbr->last_rx_options = dd_hdr.opts;
350204df0f8Sclaudio 	nbr->last_rx_bits = dd_hdr.bits;
351204df0f8Sclaudio }
352204df0f8Sclaudio 
353204df0f8Sclaudio void
354204df0f8Sclaudio db_sum_list_add(struct nbr *nbr, struct lsa_hdr *lsa)
355204df0f8Sclaudio {
356204df0f8Sclaudio 	struct lsa_entry	*le;
357204df0f8Sclaudio 
358204df0f8Sclaudio 	if ((le = calloc(1, sizeof(*le))) == NULL)
359204df0f8Sclaudio 		fatal("db_sum_list_add");
360204df0f8Sclaudio 
361204df0f8Sclaudio 	TAILQ_INSERT_TAIL(&nbr->db_sum_list, le, entry);
362204df0f8Sclaudio 	le->le_lsa = lsa;
363204df0f8Sclaudio }
364204df0f8Sclaudio 
365204df0f8Sclaudio void
366204df0f8Sclaudio db_sum_list_next(struct nbr *nbr)
367204df0f8Sclaudio {
368204df0f8Sclaudio 	struct lsa_entry	*le;
369204df0f8Sclaudio 
370204df0f8Sclaudio 	while ((le = TAILQ_FIRST(&nbr->db_sum_list)) != nbr->dd_end) {
371204df0f8Sclaudio 		TAILQ_REMOVE(&nbr->db_sum_list, le, entry);
372204df0f8Sclaudio 		free(le->le_lsa);
373204df0f8Sclaudio 		free(le);
374204df0f8Sclaudio 	}
375204df0f8Sclaudio }
376204df0f8Sclaudio 
377204df0f8Sclaudio void
378204df0f8Sclaudio db_sum_list_clr(struct nbr *nbr)
379204df0f8Sclaudio {
380204df0f8Sclaudio 	nbr->dd_end = NULL;
381204df0f8Sclaudio 	db_sum_list_next(nbr);
382204df0f8Sclaudio }
383204df0f8Sclaudio 
384204df0f8Sclaudio /* timers */
385204df0f8Sclaudio void
386204df0f8Sclaudio db_tx_timer(int fd, short event, void *arg)
387204df0f8Sclaudio {
388204df0f8Sclaudio 	struct nbr *nbr = arg;
389204df0f8Sclaudio 	struct timeval tv;
390204df0f8Sclaudio 
391204df0f8Sclaudio 	switch (nbr->state) {
392204df0f8Sclaudio 	case NBR_STA_DOWN:
393204df0f8Sclaudio 	case NBR_STA_ATTEMPT:
394204df0f8Sclaudio 	case NBR_STA_INIT:
395204df0f8Sclaudio 	case NBR_STA_2_WAY:
396204df0f8Sclaudio 	case NBR_STA_SNAP:
397204df0f8Sclaudio 		return ;
398204df0f8Sclaudio 	case NBR_STA_XSTRT:
399204df0f8Sclaudio 	case NBR_STA_XCHNG:
400d7363de5Sclaudio 	case NBR_STA_LOAD:
401204df0f8Sclaudio 	case NBR_STA_FULL:
402204df0f8Sclaudio 		send_db_description(nbr);
403204df0f8Sclaudio 		break;
404204df0f8Sclaudio 	default:
4059cc19ef1Ssthen 		log_debug("db_tx_timer: neighbor ID %s (%s): "
4069cc19ef1Ssthen 		    "unknown neighbor state",
4079cc19ef1Ssthen 		    inet_ntoa(nbr->id), nbr->iface->name);
408204df0f8Sclaudio 		break;
409204df0f8Sclaudio 	}
410204df0f8Sclaudio 
411204df0f8Sclaudio 	/* reschedule db_tx_timer but only in master mode */
4124d267a96Sclaudio 	if (nbr->dd_master) {
413204df0f8Sclaudio 		timerclear(&tv);
414204df0f8Sclaudio 		tv.tv_sec = nbr->iface->rxmt_interval;
4153aede346Sclaudio 		if (evtimer_add(&nbr->db_tx_timer, &tv) == -1)
4163aede346Sclaudio 			fatal("db_tx_timer");
417204df0f8Sclaudio 	}
418204df0f8Sclaudio }
419204df0f8Sclaudio 
4203aede346Sclaudio void
421204df0f8Sclaudio start_db_tx_timer(struct nbr *nbr)
422204df0f8Sclaudio {
423204df0f8Sclaudio 	struct timeval	tv;
424204df0f8Sclaudio 
425204df0f8Sclaudio 	if (nbr == nbr->iface->self)
4263aede346Sclaudio 		return;
427204df0f8Sclaudio 
428204df0f8Sclaudio 	timerclear(&tv);
4293aede346Sclaudio 	if (evtimer_add(&nbr->db_tx_timer, &tv) == -1)
4303aede346Sclaudio 		fatal("start_db_tx_timer");
431204df0f8Sclaudio }
432204df0f8Sclaudio 
4333aede346Sclaudio void
434204df0f8Sclaudio stop_db_tx_timer(struct nbr *nbr)
435204df0f8Sclaudio {
436204df0f8Sclaudio 	if (nbr == nbr->iface->self)
4373aede346Sclaudio 		return;
438204df0f8Sclaudio 
4393aede346Sclaudio 	if (evtimer_del(&nbr->db_tx_timer) == -1)
4403aede346Sclaudio 		fatal("stop_db_tx_timer");
441204df0f8Sclaudio }
442