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