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