xref: /openbsd/usr.sbin/ospf6d/lsack.c (revision 8932bfb7)
1 /*	$OpenBSD: lsack.c,v 1.5 2010/05/26 13:56:08 nicm Exp $ */
2 
3 /*
4  * Copyright (c) 2004, 2005, 2007 Esben Norby <norby@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <netinet/in.h>
22 #include <netinet/in_systm.h>
23 #include <netinet/ip.h>
24 #include <arpa/inet.h>
25 
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include "ospf6d.h"
30 #include "ospf6.h"
31 #include "log.h"
32 #include "ospfe.h"
33 
34 void	 start_ls_ack_tx_timer_now(struct iface *);
35 
36 /* link state acknowledgement packet handling */
37 int
38 send_ls_ack(struct iface *iface, struct in6_addr addr, void *data, size_t len)
39 {
40 	struct ibuf	*buf;
41 	int		 ret;
42 
43 	/* XXX IBUF_READ_SIZE */
44 	if ((buf = ibuf_dynamic(PKG_DEF_SIZE, IBUF_READ_SIZE)) == NULL)
45 		fatal("send_ls_ack");
46 
47 	/* OSPF header */
48 	if (gen_ospf_hdr(buf, iface, PACKET_TYPE_LS_ACK))
49 		goto fail;
50 
51 	/* LS ack(s) */
52 	if (ibuf_add(buf, data, len))
53 		goto fail;
54 
55 	/* calculate checksum */
56 	if (upd_ospf_hdr(buf, iface))
57 		goto fail;
58 
59 	ret = send_packet(iface, buf->buf, buf->wpos, &addr);
60 
61 	ibuf_free(buf);
62 	return (ret);
63 fail:
64 	log_warn("send_ls_ack");
65 	ibuf_free(buf);
66 	return (-1);
67 }
68 
69 void
70 recv_ls_ack(struct nbr *nbr, char *buf, u_int16_t len)
71 {
72 	struct lsa_hdr	 lsa_hdr;
73 
74 	switch (nbr->state) {
75 	case NBR_STA_DOWN:
76 	case NBR_STA_ATTEMPT:
77 	case NBR_STA_INIT:
78 	case NBR_STA_2_WAY:
79 	case NBR_STA_XSTRT:
80 	case NBR_STA_SNAP:
81 		log_debug("recv_ls_ack: packet ignored in state %s, "
82 		    "neighbor ID %s", nbr_state_name(nbr->state),
83 		    inet_ntoa(nbr->id));
84 		break;
85 	case NBR_STA_XCHNG:
86 	case NBR_STA_LOAD:
87 	case NBR_STA_FULL:
88 		while (len >= sizeof(lsa_hdr)) {
89 			memcpy(&lsa_hdr, buf, sizeof(lsa_hdr));
90 
91 			if (lsa_hdr_check(nbr, &lsa_hdr)) {
92 				/* try both list in case of DROTHER */
93 				if (nbr->iface->state & IF_STA_DROTHER)
94 					(void)ls_retrans_list_del(
95 					    nbr->iface->self, &lsa_hdr);
96 				(void)ls_retrans_list_del(nbr, &lsa_hdr);
97 			}
98 
99 			buf += sizeof(lsa_hdr);
100 			len -= sizeof(lsa_hdr);
101 		}
102 		if (len > 0) {
103 			log_warnx("recv_ls_ack: bad packet size, "
104 			    "neighbor ID %s", inet_ntoa(nbr->id));
105 			return;
106 		}
107 		break;
108 	default:
109 		fatalx("recv_ls_ack: unknown neighbor state");
110 	}
111 }
112 
113 int
114 lsa_hdr_check(struct nbr *nbr, struct lsa_hdr *lsa_hdr)
115 {
116 	/* invalid age */
117 	if ((ntohs(lsa_hdr->age) < 1) || (ntohs(lsa_hdr->age) > MAX_AGE)) {
118 		log_debug("lsa_hdr_check: invalid age, neighbor ID %s",
119 		     inet_ntoa(nbr->id));
120 		return (0);
121 	}
122 
123 	/* invalid type */
124 	switch (ntohs(lsa_hdr->type)) {
125 	case LSA_TYPE_LINK:
126 	case LSA_TYPE_ROUTER:
127 	case LSA_TYPE_NETWORK:
128 	case LSA_TYPE_INTER_A_PREFIX:
129 	case LSA_TYPE_INTER_A_ROUTER:
130 	case LSA_TYPE_INTRA_A_PREFIX:
131 	case LSA_TYPE_EXTERNAL:
132 		break;
133 	default:
134 		log_debug("lsa_hdr_check: invalid LSA type %d, neighbor ID %s",
135 		    lsa_hdr->type, inet_ntoa(nbr->id));
136 		return (0);
137 	}
138 
139 	/* invalid sequence number */
140 	if (ntohl(lsa_hdr->seq_num) == RESV_SEQ_NUM) {
141 		log_debug("ls_hdr_check: invalid seq num, neighbor ID %s",
142 			inet_ntoa(nbr->id));
143 		return (0);
144 	}
145 
146 	return (1);
147 }
148 
149 /* link state ack list */
150 void
151 ls_ack_list_add(struct iface *iface, struct lsa_hdr *lsa)
152 {
153 	struct lsa_entry	*le;
154 
155 	if (lsa == NULL)
156 		fatalx("ls_ack_list_add: no LSA header");
157 
158 	if ((le = calloc(1, sizeof(*le))) == NULL)
159 		fatal("ls_ack_list_add");
160 
161 	if (ls_ack_list_empty(iface))
162 		start_ls_ack_tx_timer(iface);
163 
164 	TAILQ_INSERT_TAIL(&iface->ls_ack_list, le, entry);
165 	le->le_lsa = lsa;
166 	iface->ls_ack_cnt++;
167 
168 	/* reschedule now if we have enough for a full packet */
169 	if (iface->ls_ack_cnt >
170 	    ((iface->mtu - PACKET_HDR) / sizeof(struct lsa_hdr))) {
171 		start_ls_ack_tx_timer_now(iface);
172 	}
173 }
174 
175 void
176 ls_ack_list_free(struct iface *iface, struct lsa_entry *le)
177 {
178 	TAILQ_REMOVE(&iface->ls_ack_list, le, entry);
179 	free(le->le_lsa);
180 	free(le);
181 
182 	iface->ls_ack_cnt--;
183 }
184 
185 void
186 ls_ack_list_clr(struct iface *iface)
187 {
188 	struct lsa_entry	*le;
189 
190 	while ((le = TAILQ_FIRST(&iface->ls_ack_list)) != NULL) {
191 		TAILQ_REMOVE(&iface->ls_ack_list, le, entry);
192 		free(le->le_lsa);
193 		free(le);
194 	}
195 	iface->ls_ack_cnt = 0;
196 }
197 
198 int
199 ls_ack_list_empty(struct iface *iface)
200 {
201 	return (TAILQ_EMPTY(&iface->ls_ack_list));
202 }
203 
204 /* timers */
205 /* ARGSUSED */
206 void
207 ls_ack_tx_timer(int fd, short event, void *arg)
208 {
209 	struct in6_addr		 addr;
210 	struct iface		*iface = arg;
211 	struct lsa_hdr		*lsa_hdr;
212 	struct lsa_entry	*le, *nle;
213 	struct nbr		*nbr;
214 	char			*buf;
215 	char			*ptr;
216 	int			 cnt = 0;
217 
218 	if ((buf = calloc(1, READ_BUF_SIZE)) == NULL)
219 		fatal("ls_ack_tx_timer");
220 
221 	while (!ls_ack_list_empty(iface)) {
222 		ptr = buf;
223 		cnt = 0;
224 		for (le = TAILQ_FIRST(&iface->ls_ack_list); le != NULL &&
225 		    (ptr - buf < iface->mtu - PACKET_HDR); le = nle) {
226 			nle = TAILQ_NEXT(le, entry);
227 			memcpy(ptr, le->le_lsa, sizeof(struct lsa_hdr));
228 			ptr += sizeof(*lsa_hdr);
229 			ls_ack_list_free(iface, le);
230 			cnt++;
231 		}
232 
233 		/* send LS ack(s) but first set correct destination */
234 		switch (iface->type) {
235 		case IF_TYPE_POINTOPOINT:
236 			inet_pton(AF_INET6, AllSPFRouters, &addr);
237 			send_ls_ack(iface, addr, buf, ptr - buf);
238 			break;
239 		case IF_TYPE_BROADCAST:
240 			if (iface->state & IF_STA_DRORBDR)
241 				inet_pton(AF_INET6, AllSPFRouters, &addr);
242 			else
243 				inet_pton(AF_INET6, AllDRouters, &addr);
244 
245 			send_ls_ack(iface, addr, buf, ptr - buf);
246 			break;
247 		case IF_TYPE_NBMA:
248 		case IF_TYPE_POINTOMULTIPOINT:
249 		case IF_TYPE_VIRTUALLINK:
250 			LIST_FOREACH(nbr, &iface->nbr_list, entry) {
251 				if (nbr == iface->self)
252 					continue;
253 				if (!(nbr->state & NBR_STA_FLOOD))
254 					continue;
255 				send_ls_ack(iface, nbr->addr, buf, ptr - buf);
256 			}
257 			break;
258 		default:
259 			fatalx("lsa_ack_tx_timer: unknown interface type");
260 		}
261 	}
262 
263 	free(buf);
264 }
265 
266 void
267 start_ls_ack_tx_timer(struct iface *iface)
268 {
269 	struct timeval tv;
270 
271 	timerclear(&tv);
272 	tv.tv_sec = iface->rxmt_interval / 2;
273 
274 	if (evtimer_add(&iface->lsack_tx_timer, &tv) == -1)
275 		fatal("start_ls_ack_tx_timer");
276 }
277 
278 void
279 start_ls_ack_tx_timer_now(struct iface *iface)
280 {
281 	struct timeval tv;
282 
283 	timerclear(&tv);
284 	if (evtimer_add(&iface->lsack_tx_timer, &tv) == -1)
285 		fatal("start_ls_ack_tx_timer_now");
286 }
287 
288 void
289 stop_ls_ack_tx_timer(struct iface *iface)
290 {
291 	if (evtimer_del(&iface->lsack_tx_timer) == -1)
292 		fatal("stop_ls_ack_tx_timer");
293 }
294