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