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