xref: /openbsd/usr.sbin/ospf6d/database.c (revision 4bdff4be)
1 /*	$OpenBSD: database.c,v 1.23 2023/06/21 07:45:47 claudio Exp $ */
2 
3 /*
4  * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
5  * Copyright (c) 2004, 2005, 2007 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/socket.h>
22 #include <netinet/in.h>
23 #include <netinet/ip6.h>
24 #include <arpa/inet.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 
29 #include "ospf6d.h"
30 #include "ospf6.h"
31 #include "log.h"
32 #include "ospfe.h"
33 
34 void	db_sum_list_next(struct nbr *);
35 
36 /* database description packet handling */
37 int
38 send_db_description(struct nbr *nbr)
39 {
40 	struct in6_addr		 dst;
41 	struct db_dscrp_hdr	 dd_hdr;
42 	struct lsa_entry	*le, *nle;
43 	struct ibuf		*buf;
44 	u_int8_t		 bits = 0;
45 
46 	if ((buf = ibuf_open(nbr->iface->mtu - sizeof(struct ip6_hdr))) == NULL)
47 		fatal("send_db_description");
48 
49 	/* OSPF header */
50 	if (gen_ospf_hdr(buf, nbr->iface, PACKET_TYPE_DD))
51 		goto fail;
52 
53 	/* reserve space for database description header */
54 	if (ibuf_add_zero(buf, sizeof(dd_hdr)) == -1)
55 		goto fail;
56 
57 	switch (nbr->state) {
58 	case NBR_STA_DOWN:
59 	case NBR_STA_ATTEMPT:
60 	case NBR_STA_INIT:
61 	case NBR_STA_2_WAY:
62 	case NBR_STA_SNAP:
63 		log_debug("send_db_description: neighbor ID %s (%s): "
64 		    "cannot send packet in state %s", inet_ntoa(nbr->id),
65 		    nbr->iface->name, nbr_state_name(nbr->state));
66 		goto fail;
67 	case NBR_STA_XSTRT:
68 		bits |= OSPF_DBD_MS | OSPF_DBD_M | OSPF_DBD_I;
69 		nbr->dd_more = 1;
70 		break;
71 	case NBR_STA_XCHNG:
72 		if (nbr->dd_master)
73 			bits |= OSPF_DBD_MS;
74 		else
75 			bits &= ~OSPF_DBD_MS;
76 
77 		if (TAILQ_EMPTY(&nbr->db_sum_list)) {
78 			bits &= ~OSPF_DBD_M;
79 			nbr->dd_more = 0;
80 		} else {
81 			bits |= OSPF_DBD_M;
82 			nbr->dd_more = 1;
83 		}
84 
85 		bits &= ~OSPF_DBD_I;
86 
87 		/* build LSA list */
88 		for (le = TAILQ_FIRST(&nbr->db_sum_list); le != NULL &&
89 		    ibuf_left(buf) >=  sizeof(struct lsa_hdr); le = nle) {
90 			nbr->dd_end = nle = TAILQ_NEXT(le, entry);
91 			if (ibuf_add(buf, le->le_lsa, sizeof(struct lsa_hdr)))
92 				goto fail;
93 		}
94 		break;
95 	case NBR_STA_LOAD:
96 	case NBR_STA_FULL:
97 		if (nbr->dd_master)
98 			bits |= OSPF_DBD_MS;
99 		else
100 			bits &= ~OSPF_DBD_MS;
101 		bits &= ~OSPF_DBD_M;
102 		bits &= ~OSPF_DBD_I;
103 
104 		nbr->dd_more = 0;
105 		break;
106 	default:
107 		fatalx("send_db_description: unknown neighbor state");
108 	}
109 
110 	bzero(&dd_hdr, sizeof(dd_hdr));
111 
112 	switch (nbr->iface->type) {
113 	case IF_TYPE_POINTOPOINT:
114 		inet_pton(AF_INET6, AllSPFRouters, &dst);
115 		dd_hdr.iface_mtu = htons(nbr->iface->mtu);
116 		break;
117 	case IF_TYPE_BROADCAST:
118 		dst = nbr->addr;
119 		dd_hdr.iface_mtu = htons(nbr->iface->mtu);
120 		break;
121 	case IF_TYPE_NBMA:
122 	case IF_TYPE_POINTOMULTIPOINT:
123 		/* XXX not supported */
124 		break;
125 	case IF_TYPE_VIRTUALLINK:
126 		dst = nbr->iface->dst;
127 		dd_hdr.iface_mtu = 0;
128 		break;
129 	default:
130 		fatalx("send_db_description: unknown interface type");
131 	}
132 
133 	dd_hdr.opts = htonl(area_ospf_options(nbr->iface->area));
134 	dd_hdr.bits = bits;
135 	dd_hdr.dd_seq_num = htonl(nbr->dd_seq_num);
136 
137 	if (ibuf_set(buf, sizeof(struct ospf_hdr), &dd_hdr,
138 	    sizeof(dd_hdr)) == -1)
139 		goto fail;
140 
141 	/* calculate checksum */
142 	if (upd_ospf_hdr(buf, nbr->iface))
143 		goto fail;
144 
145 	/* transmit packet */
146 	if (send_packet(nbr->iface, buf, &dst) == -1)
147 		goto fail;
148 
149 	ibuf_free(buf);
150 	return (0);
151 fail:
152 	log_warn("send_db_description");
153 	ibuf_free(buf);
154 	return (-1);
155 }
156 
157 void
158 recv_db_description(struct nbr *nbr, char *buf, u_int16_t len)
159 {
160 	struct db_dscrp_hdr	 dd_hdr;
161 	int			 dupe = 0;
162 
163 	if (len < sizeof(dd_hdr)) {
164 		log_warnx("recv_db_description: neighbor ID %s (%s): "
165 		    "bad packet size", inet_ntoa(nbr->id), nbr->iface->name);
166 		return;
167 	}
168 	memcpy(&dd_hdr, buf, sizeof(dd_hdr));
169 	buf += sizeof(dd_hdr);
170 	len -= sizeof(dd_hdr);
171 
172 	/* db description packet sanity checks */
173 	if (ntohs(dd_hdr.iface_mtu) > nbr->iface->mtu) {
174 		log_warnx("recv_db_description: neighbor ID %s (%s): "
175 		    "invalid MTU %d expected %d", inet_ntoa(nbr->id),
176 		    nbr->iface->name, ntohs(dd_hdr.iface_mtu),
177 		    nbr->iface->mtu);
178 		return;
179 	}
180 
181 	if (nbr->last_rx_options == dd_hdr.opts &&
182 	    nbr->last_rx_bits == dd_hdr.bits &&
183 	    ntohl(dd_hdr.dd_seq_num) == nbr->dd_seq_num - nbr->dd_master ?
184 	    1 : 0) {
185 		log_debug("recv_db_description: dupe from "
186 		    "neighbor ID %s (%s)", inet_ntoa(nbr->id),
187 		    nbr->iface->name);
188 		dupe = 1;
189 	}
190 
191 	switch (nbr->state) {
192 	case NBR_STA_DOWN:
193 	case NBR_STA_ATTEMPT:
194 	case NBR_STA_2_WAY:
195 	case NBR_STA_SNAP:
196 		log_debug("recv_db_description: neighbor ID %s (%s): "
197 		    "packet ignored in state %s", inet_ntoa(nbr->id),
198 		    nbr->iface->name, nbr_state_name(nbr->state));
199 		return;
200 	case NBR_STA_INIT:
201 		/* evaluate dr and bdr after issuing a 2-Way event */
202 		nbr_fsm(nbr, NBR_EVT_2_WAY_RCVD);
203 		if_fsm(nbr->iface, IF_EVT_NBR_CHNG);
204 		if (nbr->state != NBR_STA_XSTRT)
205 			return;
206 		/* FALLTHROUGH */
207 	case NBR_STA_XSTRT:
208 		if (dupe)
209 			return;
210 		/*
211 		 * check bits: either I,M,MS or only M
212 		 */
213 		if (dd_hdr.bits == (OSPF_DBD_I | OSPF_DBD_M | OSPF_DBD_MS)) {
214 			/* if nbr Router ID is larger than own -> slave */
215 			if ((ntohl(nbr->id.s_addr)) >
216 			    ntohl(ospfe_router_id())) {
217 				/* slave */
218 				nbr->dd_master = 0;
219 				nbr->dd_seq_num = ntohl(dd_hdr.dd_seq_num);
220 
221 				/* event negotiation done */
222 				nbr_fsm(nbr, NBR_EVT_NEG_DONE);
223 			}
224 		} else if (!(dd_hdr.bits & (OSPF_DBD_I | OSPF_DBD_MS))) {
225 			/* M only case: we are master */
226 			if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num) {
227 				log_warnx("recv_db_description: "
228 				    "neighbor ID %s (%s): "
229 				    "invalid seq num, mine %x his %x",
230 				    inet_ntoa(nbr->id), nbr->iface->name,
231 				    nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
232 				return;
233 			}
234 			nbr->dd_seq_num++;
235 
236 			/* event negotiation done */
237 			nbr_fsm(nbr, NBR_EVT_NEG_DONE);
238 
239 			/* this packet may already have data so pass it on */
240 			if (len > 0) {
241 				nbr->dd_pending++;
242 				ospfe_imsg_compose_rde(IMSG_DD, nbr->peerid,
243 				    0, buf, len);
244 			}
245 		} else {
246 			/* ignore packet */
247 			log_debug("recv_db_description: neighbor ID %s (%s): "
248 			    "packet ignored in state %s (bad flags)",
249 			    inet_ntoa(nbr->id), nbr->iface->name,
250 			    nbr_state_name(nbr->state));
251 		}
252 		break;
253 	case NBR_STA_XCHNG:
254 	case NBR_STA_LOAD:
255 	case NBR_STA_FULL:
256 		if (dd_hdr.bits & OSPF_DBD_I ||
257 		    !(dd_hdr.bits & OSPF_DBD_MS) == !nbr->dd_master) {
258 			log_warnx("recv_db_description: neighbor ID %s (%s): "
259 			    "seq num mismatch, bad flags", inet_ntoa(nbr->id),
260 			    nbr->iface->name);
261 			nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
262 			return;
263 		}
264 
265 		if (nbr->last_rx_options != dd_hdr.opts) {
266 			log_warnx("recv_db_description: neighbor ID %s (%s): "
267 			    "seq num mismatch, bad options",
268 			    inet_ntoa(nbr->id), nbr->iface->name);
269 			nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
270 			return;
271 		}
272 
273 		if (dupe) {
274 			if (!nbr->dd_master)
275 				/* retransmit */
276 				start_db_tx_timer(nbr);
277 			return;
278 		}
279 
280 		if (nbr->state != NBR_STA_XCHNG) {
281 			log_warnx("recv_db_description: neighbor ID %s (%s): "
282 			    "invalid seq num, mine %x his %x",
283 			    inet_ntoa(nbr->id), nbr->iface->name,
284 			    nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
285 			nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
286 			return;
287 		}
288 
289 		/* sanity check dd seq number */
290 		if (nbr->dd_master) {
291 			/* master */
292 			if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num) {
293 				log_warnx("recv_db_description: "
294 				    "neighbor ID %s (%s): "
295 				    "invalid seq num, mine %x his %x, master",
296 				    inet_ntoa(nbr->id), nbr->iface->name,
297 				    nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
298 				nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
299 				return;
300 			}
301 			nbr->dd_seq_num++;
302 		} else {
303 			/* slave */
304 			if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num + 1) {
305 				log_warnx("recv_db_description: "
306 				    "neighbor ID %s (%s): "
307 				    "invalid seq num, mine %x his %x, slave",
308 				    inet_ntoa(nbr->id), nbr->iface->name,
309 				    nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
310 				nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
311 				return;
312 			}
313 			nbr->dd_seq_num = ntohl(dd_hdr.dd_seq_num);
314 		}
315 
316 		/* forward to RDE and let it decide which LSAs to request */
317 		if (len > 0) {
318 			nbr->dd_pending++;
319 			ospfe_imsg_compose_rde(IMSG_DD, nbr->peerid, 0,
320 			    buf, len);
321 		}
322 
323 		/* next packet */
324 		db_sum_list_next(nbr);
325 		start_db_tx_timer(nbr);
326 
327 		if (!(dd_hdr.bits & OSPF_DBD_M) &&
328 		    TAILQ_EMPTY(&nbr->db_sum_list))
329 			if (!nbr->dd_master || !nbr->dd_more)
330 				nbr_fsm(nbr, NBR_EVT_XCHNG_DONE);
331 		break;
332 	default:
333 		fatalx("recv_db_description: unknown neighbor state");
334 	}
335 
336 	nbr->last_rx_options = dd_hdr.opts;
337 	nbr->last_rx_bits = dd_hdr.bits;
338 }
339 
340 void
341 db_sum_list_add(struct nbr *nbr, struct lsa_hdr *lsa)
342 {
343 	struct lsa_entry	*le;
344 
345 	if ((le = calloc(1, sizeof(*le))) == NULL)
346 		fatal("db_sum_list_add");
347 
348 	TAILQ_INSERT_TAIL(&nbr->db_sum_list, le, entry);
349 	le->le_lsa = lsa;
350 }
351 
352 void
353 db_sum_list_next(struct nbr *nbr)
354 {
355 	struct lsa_entry	*le;
356 
357 	while ((le = TAILQ_FIRST(&nbr->db_sum_list)) != nbr->dd_end) {
358 		TAILQ_REMOVE(&nbr->db_sum_list, le, entry);
359 		free(le->le_lsa);
360 		free(le);
361 	}
362 }
363 
364 void
365 db_sum_list_clr(struct nbr *nbr)
366 {
367 	nbr->dd_end = NULL;
368 	db_sum_list_next(nbr);
369 }
370 
371 /* timers */
372 void
373 db_tx_timer(int fd, short event, void *arg)
374 {
375 	struct nbr *nbr = arg;
376 	struct timeval tv;
377 
378 	switch (nbr->state) {
379 	case NBR_STA_DOWN:
380 	case NBR_STA_ATTEMPT:
381 	case NBR_STA_INIT:
382 	case NBR_STA_2_WAY:
383 	case NBR_STA_SNAP:
384 		return ;
385 	case NBR_STA_XSTRT:
386 	case NBR_STA_XCHNG:
387 	case NBR_STA_LOAD:
388 	case NBR_STA_FULL:
389 		send_db_description(nbr);
390 		break;
391 	default:
392 		log_debug("db_tx_timer: neighbor ID %s (%s): "
393 		    "unknown neighbor state",
394 		    inet_ntoa(nbr->id), nbr->iface->name);
395 		break;
396 	}
397 
398 	/* reschedule db_tx_timer but only in master mode */
399 	if (nbr->dd_master) {
400 		timerclear(&tv);
401 		tv.tv_sec = nbr->iface->rxmt_interval;
402 		if (evtimer_add(&nbr->db_tx_timer, &tv) == -1)
403 			fatal("db_tx_timer");
404 	}
405 }
406 
407 void
408 start_db_tx_timer(struct nbr *nbr)
409 {
410 	struct timeval	tv;
411 
412 	if (nbr == nbr->iface->self)
413 		return;
414 
415 	timerclear(&tv);
416 	if (evtimer_add(&nbr->db_tx_timer, &tv) == -1)
417 		fatal("start_db_tx_timer");
418 }
419 
420 void
421 stop_db_tx_timer(struct nbr *nbr)
422 {
423 	if (nbr == nbr->iface->self)
424 		return;
425 
426 	if (evtimer_del(&nbr->db_tx_timer) == -1)
427 		fatal("stop_db_tx_timer");
428 }
429