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