xref: /openbsd-src/usr.sbin/ospf6d/lsack.c (revision 5a38ef86d0b61900239c7913d24a05e7b88a58f0)
1 /*	$OpenBSD: lsack.c,v 1.9 2021/11/03 21:40:03 sthen 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/ip6.h>
23 #include <arpa/inet.h>
24 
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "ospf6d.h"
29 #include "ospf6.h"
30 #include "log.h"
31 #include "ospfe.h"
32 
33 int		 send_ls_ack(struct iface *, struct in6_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 ip6_hdr))) == 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 in6_addr addr, struct ibuf *buf)
60 {
61 	/* calculate checksum */
62 	if (upd_ospf_hdr(buf, iface)) {
63 		log_warn("send_ls_ack");
64 		return (-1);
65 	}
66 
67 	if (send_packet(iface, buf, &addr) == -1) {
68 		log_warn("send_ls_ack");
69 		return (-1);
70 	}
71 	return (0);
72 }
73 
74 int
75 send_direct_ack(struct iface *iface, struct in6_addr addr, void *d, size_t len)
76 {
77 	struct ibuf	*buf;
78 	int		 ret;
79 
80 	if ((buf = prepare_ls_ack(iface)) == NULL)
81 		return (-1);
82 
83 	/* LS ack(s) */
84 	if (ibuf_add(buf, d, len)) {
85 		log_warn("send_direct_ack");
86 		ibuf_free(buf);
87 		return (-1);
88 	}
89 
90 	ret = send_ls_ack(iface, addr, buf);
91 	ibuf_free(buf);
92 	return (ret);
93 }
94 
95 void
96 recv_ls_ack(struct nbr *nbr, char *buf, u_int16_t len)
97 {
98 	struct lsa_hdr	 lsa_hdr;
99 
100 	switch (nbr->state) {
101 	case NBR_STA_DOWN:
102 	case NBR_STA_ATTEMPT:
103 	case NBR_STA_INIT:
104 	case NBR_STA_2_WAY:
105 	case NBR_STA_XSTRT:
106 	case NBR_STA_SNAP:
107 		log_debug("recv_ls_ack: packet ignored in state %s, "
108 		    "neighbor ID %s (%s)", nbr_state_name(nbr->state),
109 		    inet_ntoa(nbr->id), nbr->iface->name);
110 		break;
111 	case NBR_STA_XCHNG:
112 	case NBR_STA_LOAD:
113 	case NBR_STA_FULL:
114 		while (len >= sizeof(lsa_hdr)) {
115 			memcpy(&lsa_hdr, buf, sizeof(lsa_hdr));
116 
117 			if (lsa_hdr_check(nbr, &lsa_hdr)) {
118 				/* try both list in case of DROTHER */
119 				if (nbr->iface->state & IF_STA_DROTHER)
120 					(void)ls_retrans_list_del(
121 					    nbr->iface->self, &lsa_hdr);
122 				(void)ls_retrans_list_del(nbr, &lsa_hdr);
123 			}
124 
125 			buf += sizeof(lsa_hdr);
126 			len -= sizeof(lsa_hdr);
127 		}
128 		if (len > 0) {
129 			log_warnx("recv_ls_ack: bad packet size, "
130 			    "neighbor ID %s (%s)", inet_ntoa(nbr->id),
131 			    nbr->iface->name);
132 			return;
133 		}
134 		break;
135 	default:
136 		fatalx("recv_ls_ack: unknown neighbor state");
137 	}
138 }
139 
140 int
141 lsa_hdr_check(struct nbr *nbr, struct lsa_hdr *lsa_hdr)
142 {
143 	/* invalid age */
144 	if ((ntohs(lsa_hdr->age) < 1) || (ntohs(lsa_hdr->age) > MAX_AGE)) {
145 		log_debug("lsa_hdr_check: invalid age, neighbor ID %s (%s)",
146 		     inet_ntoa(nbr->id), nbr->iface->name);
147 		return (0);
148 	}
149 
150 	/* invalid type */
151 	switch (ntohs(lsa_hdr->type)) {
152 	case LSA_TYPE_LINK:
153 	case LSA_TYPE_ROUTER:
154 	case LSA_TYPE_NETWORK:
155 	case LSA_TYPE_INTER_A_PREFIX:
156 	case LSA_TYPE_INTER_A_ROUTER:
157 	case LSA_TYPE_INTRA_A_PREFIX:
158 	case LSA_TYPE_EXTERNAL:
159 		break;
160 	default:
161 		log_debug("lsa_hdr_check: invalid LSA type %d, "
162 		    "neighbor ID %s (%s)",
163 		    lsa_hdr->type, inet_ntoa(nbr->id), nbr->iface->name);
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, "
170 		    "neighbor ID %s (%s)", inet_ntoa(nbr->id),
171 		    nbr->iface->name);
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 full packet */
198 	if (iface->ls_ack_cnt >
199 	    ((iface->mtu - PACKET_HDR) / sizeof(struct lsa_hdr))) {
200 		start_ls_ack_tx_timer_now(iface);
201 	}
202 }
203 
204 void
205 ls_ack_list_free(struct iface *iface, struct lsa_entry *le)
206 {
207 	TAILQ_REMOVE(&iface->ls_ack_list, le, entry);
208 	free(le->le_lsa);
209 	free(le);
210 
211 	iface->ls_ack_cnt--;
212 }
213 
214 void
215 ls_ack_list_clr(struct iface *iface)
216 {
217 	struct lsa_entry	*le;
218 
219 	while ((le = TAILQ_FIRST(&iface->ls_ack_list)) != NULL) {
220 		TAILQ_REMOVE(&iface->ls_ack_list, le, entry);
221 		free(le->le_lsa);
222 		free(le);
223 	}
224 	iface->ls_ack_cnt = 0;
225 }
226 
227 int
228 ls_ack_list_empty(struct iface *iface)
229 {
230 	return (TAILQ_EMPTY(&iface->ls_ack_list));
231 }
232 
233 /* timers */
234 /* ARGSUSED */
235 void
236 ls_ack_tx_timer(int fd, short event, void *arg)
237 {
238 	struct in6_addr		 addr;
239 	struct iface		*iface = arg;
240 	struct lsa_entry	*le, *nle;
241 	struct nbr		*nbr;
242 	struct ibuf		*buf;
243 	int			 cnt;
244 
245 	while (!ls_ack_list_empty(iface)) {
246 		if ((buf = prepare_ls_ack(iface)) == NULL)
247 			fatal("ls_ack_tx_timer");
248 		cnt = 0;
249 
250 		for (le = TAILQ_FIRST(&iface->ls_ack_list); le != NULL;
251 		    le = nle) {
252 			nle = TAILQ_NEXT(le, entry);
253 			if (ibuf_left(buf) < sizeof(struct lsa_hdr))
254 				break;
255 			if (ibuf_add(buf, le->le_lsa, sizeof(struct lsa_hdr)))
256 				break;
257 			ls_ack_list_free(iface, le);
258 			cnt++;
259 		}
260 		if (cnt == 0) {
261 			log_warnx("ls_ack_tx_timer: lost in space");
262 			ibuf_free(buf);
263 			return;
264 		}
265 
266 		/* send LS ack(s) but first set correct destination */
267 		switch (iface->type) {
268 		case IF_TYPE_POINTOPOINT:
269 			inet_pton(AF_INET6, AllSPFRouters, &addr);
270 			send_ls_ack(iface, addr, buf);
271 			break;
272 		case IF_TYPE_BROADCAST:
273 			if (iface->state & IF_STA_DRORBDR)
274 				inet_pton(AF_INET6, AllSPFRouters, &addr);
275 			else
276 				inet_pton(AF_INET6, AllDRouters, &addr);
277 			send_ls_ack(iface, addr, buf);
278 			break;
279 		case IF_TYPE_NBMA:
280 		case IF_TYPE_POINTOMULTIPOINT:
281 		case IF_TYPE_VIRTUALLINK:
282 			LIST_FOREACH(nbr, &iface->nbr_list, entry) {
283 				if (nbr == iface->self)
284 					continue;
285 				if (!(nbr->state & NBR_STA_FLOOD))
286 					continue;
287 				send_ls_ack(iface, nbr->addr, buf);
288 			}
289 			break;
290 		default:
291 			fatalx("lsa_ack_tx_timer: unknown interface type");
292 		}
293 		ibuf_free(buf);
294 	}
295 }
296 
297 void
298 start_ls_ack_tx_timer(struct iface *iface)
299 {
300 	struct timeval tv;
301 
302 	timerclear(&tv);
303 	tv.tv_sec = iface->rxmt_interval / 2;
304 
305 	if (evtimer_add(&iface->lsack_tx_timer, &tv) == -1)
306 		fatal("start_ls_ack_tx_timer");
307 }
308 
309 void
310 start_ls_ack_tx_timer_now(struct iface *iface)
311 {
312 	struct timeval tv;
313 
314 	timerclear(&tv);
315 	if (evtimer_add(&iface->lsack_tx_timer, &tv) == -1)
316 		fatal("start_ls_ack_tx_timer_now");
317 }
318 
319 void
320 stop_ls_ack_tx_timer(struct iface *iface)
321 {
322 	if (evtimer_del(&iface->lsack_tx_timer) == -1)
323 		fatal("stop_ls_ack_tx_timer");
324 }
325