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