xref: /openbsd-src/usr.sbin/ospfd/lsack.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: lsack.c,v 1.20 2011/03/25 08:52:21 claudio Exp $ */
2 
3 /*
4  * Copyright (c) 2004, 2005 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 "ospfd.h"
30 #include "ospf.h"
31 #include "log.h"
32 #include "ospfe.h"
33 
34 int		 send_ls_ack(struct iface *, struct in_addr, struct ibuf *);
35 struct ibuf	*prepare_ls_ack(struct iface *);
36 void		 start_ls_ack_tx_timer_now(struct iface *);
37 
38 /* link state acknowledgement packet handling */
39 struct ibuf *
40 prepare_ls_ack(struct iface *iface)
41 {
42 	struct ibuf	*buf;
43 
44 	if ((buf = ibuf_open(iface->mtu - sizeof(struct ip))) == NULL) {
45 		log_warn("prepare_ls_ack");
46 		return (NULL);
47 	}
48 
49 	/* OSPF header */
50 	if (gen_ospf_hdr(buf, iface, PACKET_TYPE_LS_ACK)) {
51 		log_warn("prepare_ls_ack");
52 		ibuf_free(buf);
53 		return (NULL);
54 	}
55 
56 	return (buf);
57 }
58 
59 int
60 send_ls_ack(struct iface *iface, struct in_addr addr, struct ibuf *buf)
61 {
62 	struct sockaddr_in	dst;
63 	int			ret;
64 
65 	/* update authentication and calculate checksum */
66 	if (auth_gen(buf, iface)) {
67 		log_warn("send_ls_ack");
68 		return (-1);
69 	}
70 
71 	dst.sin_family = AF_INET;
72 	dst.sin_len = sizeof(struct sockaddr_in);
73 	dst.sin_addr.s_addr = addr.s_addr;
74 
75 	ret = send_packet(iface, buf, &dst);
76 	return (ret);
77 }
78 
79 int
80 send_direct_ack(struct iface *iface, struct in_addr addr, void *d, size_t len)
81 {
82 	struct ibuf	*buf;
83 	int		 ret;
84 
85 	if ((buf = prepare_ls_ack(iface)) == NULL)
86 		return (-1);
87 
88 	/* LS ack(s) */
89 	if (ibuf_add(buf, d, len)) {
90 		log_warn("send_direct_ack");
91 		ibuf_free(buf);
92 		return (-1);
93 	}
94 
95 	ret = send_ls_ack(iface, addr, buf);
96 	ibuf_free(buf);
97 	return (ret);
98 }
99 
100 void
101 recv_ls_ack(struct nbr *nbr, char *buf, u_int16_t len)
102 {
103 	struct lsa_hdr	 lsa_hdr;
104 
105 	switch (nbr->state) {
106 	case NBR_STA_DOWN:
107 	case NBR_STA_ATTEMPT:
108 	case NBR_STA_INIT:
109 	case NBR_STA_2_WAY:
110 	case NBR_STA_XSTRT:
111 	case NBR_STA_SNAP:
112 		log_debug("recv_ls_ack: packet ignored in state %s, "
113 		    "neighbor ID %s", nbr_state_name(nbr->state),
114 		    inet_ntoa(nbr->id));
115 		break;
116 	case NBR_STA_XCHNG:
117 	case NBR_STA_LOAD:
118 	case NBR_STA_FULL:
119 		while (len >= sizeof(lsa_hdr)) {
120 			memcpy(&lsa_hdr, buf, sizeof(lsa_hdr));
121 
122 			if (lsa_hdr_check(nbr, &lsa_hdr)) {
123 				/* try both list in case of DROTHER */
124 				if (nbr->iface->state & IF_STA_DROTHER)
125 					(void)ls_retrans_list_del(
126 					    nbr->iface->self, &lsa_hdr);
127 				(void)ls_retrans_list_del(nbr, &lsa_hdr);
128 			}
129 
130 			buf += sizeof(lsa_hdr);
131 			len -= sizeof(lsa_hdr);
132 		}
133 		if (len > 0) {
134 			log_warnx("recv_ls_ack: bad packet size, "
135 			    "neighbor ID %s", inet_ntoa(nbr->id));
136 			return;
137 		}
138 		break;
139 	default:
140 		fatalx("recv_ls_ack: unknown neighbor state");
141 	}
142 }
143 
144 int
145 lsa_hdr_check(struct nbr *nbr, struct lsa_hdr *lsa_hdr)
146 {
147 	/* invalid age */
148 	if ((ntohs(lsa_hdr->age) < 1) || (ntohs(lsa_hdr->age) > MAX_AGE)) {
149 		log_debug("lsa_hdr_check: invalid age, neighbor ID %s",
150 		     inet_ntoa(nbr->id));
151 		return (0);
152 	}
153 
154 	/* invalid type */
155 	switch (lsa_hdr->type) {
156 	case LSA_TYPE_ROUTER:
157 	case LSA_TYPE_NETWORK:
158 	case LSA_TYPE_SUM_NETWORK:
159 	case LSA_TYPE_SUM_ROUTER:
160 	case LSA_TYPE_EXTERNAL:
161 		break;
162 	default:
163 		log_debug("lsa_hdr_check: invalid LSA type %d, neighbor ID %s",
164 		    lsa_hdr->type, inet_ntoa(nbr->id));
165 		return (0);
166 	}
167 
168 	/* invalid sequence number */
169 	if (ntohl(lsa_hdr->seq_num) == RESV_SEQ_NUM) {
170 		log_debug("ls_hdr_check: invalid seq num, neighbor ID %s",
171 			inet_ntoa(nbr->id));
172 		return (0);
173 	}
174 
175 	return (1);
176 }
177 
178 /* link state ack list */
179 void
180 ls_ack_list_add(struct iface *iface, struct lsa_hdr *lsa)
181 {
182 	struct lsa_entry	*le;
183 
184 	if (lsa == NULL)
185 		fatalx("ls_ack_list_add: no LSA header");
186 
187 	if ((le = calloc(1, sizeof(*le))) == NULL)
188 		fatal("ls_ack_list_add");
189 
190 	if (ls_ack_list_empty(iface))
191 		start_ls_ack_tx_timer(iface);
192 
193 	TAILQ_INSERT_TAIL(&iface->ls_ack_list, le, entry);
194 	le->le_lsa = lsa;
195 	iface->ls_ack_cnt++;
196 
197 	/* reschedule now if we have enough for a reasonably sized packet */
198 	if (iface->ls_ack_cnt > IP_MSS / sizeof(struct lsa_hdr))
199 		start_ls_ack_tx_timer_now(iface);
200 }
201 
202 void
203 ls_ack_list_free(struct iface *iface, struct lsa_entry *le)
204 {
205 	TAILQ_REMOVE(&iface->ls_ack_list, le, entry);
206 	free(le->le_lsa);
207 	free(le);
208 
209 	iface->ls_ack_cnt--;
210 }
211 
212 void
213 ls_ack_list_clr(struct iface *iface)
214 {
215 	struct lsa_entry	*le;
216 
217 	while ((le = TAILQ_FIRST(&iface->ls_ack_list)) != NULL) {
218 		TAILQ_REMOVE(&iface->ls_ack_list, le, entry);
219 		free(le->le_lsa);
220 		free(le);
221 	}
222 	iface->ls_ack_cnt = 0;
223 }
224 
225 int
226 ls_ack_list_empty(struct iface *iface)
227 {
228 	return (TAILQ_EMPTY(&iface->ls_ack_list));
229 }
230 
231 /* timers */
232 /* ARGSUSED */
233 void
234 ls_ack_tx_timer(int fd, short event, void *arg)
235 {
236 	struct in_addr		 addr;
237 	struct iface		*iface = arg;
238 	struct lsa_entry	*le, *nle;
239 	struct nbr		*nbr;
240 	struct ibuf		*buf;
241 	int			 cnt;
242 
243 	while (!ls_ack_list_empty(iface)) {
244 		if ((buf = prepare_ls_ack(iface)) == NULL)
245 			fatal("ls_ack_tx_timer");
246 		cnt = 0;
247 
248 		for (le = TAILQ_FIRST(&iface->ls_ack_list); le != NULL;
249 		    le = nle) {
250 			nle = TAILQ_NEXT(le, entry);
251 			if (ibuf_left(buf) < sizeof(struct lsa_hdr) +
252 			    MD5_DIGEST_LENGTH)
253 				break;
254 			if (ibuf_add(buf, le->le_lsa, sizeof(struct lsa_hdr)))
255 				break;
256 			ls_ack_list_free(iface, le);
257 			cnt++;
258 		}
259 		if (cnt == 0) {
260 			log_warnx("ls_ack_tx_timer: lost in space");
261 			ibuf_free(buf);
262 			return;
263 		}
264 
265 		/* send LS ack(s) but first set correct destination */
266 		switch (iface->type) {
267 		case IF_TYPE_POINTOPOINT:
268 			inet_aton(AllSPFRouters, &addr);
269 			send_ls_ack(iface, addr, buf);
270 			break;
271 		case IF_TYPE_BROADCAST:
272 			if (iface->state & IF_STA_DRORBDR)
273 				inet_aton(AllSPFRouters, &addr);
274 			else
275 				inet_aton(AllDRouters, &addr);
276 			send_ls_ack(iface, addr, buf);
277 			break;
278 		case IF_TYPE_NBMA:
279 		case IF_TYPE_POINTOMULTIPOINT:
280 		case IF_TYPE_VIRTUALLINK:
281 			LIST_FOREACH(nbr, &iface->nbr_list, entry) {
282 				if (nbr == iface->self)
283 					continue;
284 				if (!(nbr->state & NBR_STA_FLOOD))
285 					continue;
286 				send_ls_ack(iface, nbr->addr, buf);
287 			}
288 			break;
289 		default:
290 			fatalx("lsa_ack_tx_timer: unknown interface type");
291 		}
292 		ibuf_free(buf);
293 	}
294 }
295 
296 void
297 start_ls_ack_tx_timer(struct iface *iface)
298 {
299 	struct timeval tv;
300 
301 	timerclear(&tv);
302 	tv.tv_sec = iface->rxmt_interval / 2;
303 
304 	if (evtimer_add(&iface->lsack_tx_timer, &tv) == -1)
305 		fatal("start_ls_ack_tx_timer");
306 }
307 
308 void
309 start_ls_ack_tx_timer_now(struct iface *iface)
310 {
311 	struct timeval tv;
312 
313 	timerclear(&tv);
314 	if (evtimer_add(&iface->lsack_tx_timer, &tv) == -1)
315 		fatal("start_ls_ack_tx_timer_now");
316 }
317 
318 void
319 stop_ls_ack_tx_timer(struct iface *iface)
320 {
321 	if (evtimer_del(&iface->lsack_tx_timer) == -1)
322 		fatal("stop_ls_ack_tx_timer");
323 }
324