xref: /openbsd-src/usr.sbin/ospf6d/lsack.c (revision 5b133f3f277e80f096764111e64f3a1284acb179)
1*5b133f3fSguenther /*	$OpenBSD: lsack.c,v 1.10 2023/03/08 04:43:14 guenther Exp $ */
2a1a4e97bSnorby 
3a1a4e97bSnorby /*
4a1a4e97bSnorby  * Copyright (c) 2004, 2005, 2007 Esben Norby <norby@openbsd.org>
5a1a4e97bSnorby  *
6a1a4e97bSnorby  * Permission to use, copy, modify, and distribute this software for any
7a1a4e97bSnorby  * purpose with or without fee is hereby granted, provided that the above
8a1a4e97bSnorby  * copyright notice and this permission notice appear in all copies.
9a1a4e97bSnorby  *
10a1a4e97bSnorby  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11a1a4e97bSnorby  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12a1a4e97bSnorby  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13a1a4e97bSnorby  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14a1a4e97bSnorby  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15a1a4e97bSnorby  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16a1a4e97bSnorby  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17a1a4e97bSnorby  */
18a1a4e97bSnorby 
19a1a4e97bSnorby #include <sys/types.h>
20a1a4e97bSnorby #include <sys/socket.h>
21a1a4e97bSnorby #include <netinet/in.h>
220a137951Sdenis #include <netinet/ip6.h>
23a1a4e97bSnorby #include <arpa/inet.h>
24a1a4e97bSnorby 
25a1a4e97bSnorby #include <stdlib.h>
26a1a4e97bSnorby #include <string.h>
27a1a4e97bSnorby 
28a1a4e97bSnorby #include "ospf6d.h"
29a1a4e97bSnorby #include "ospf6.h"
30a1a4e97bSnorby #include "log.h"
31a1a4e97bSnorby #include "ospfe.h"
32a1a4e97bSnorby 
330a137951Sdenis int		 send_ls_ack(struct iface *, struct in6_addr, struct ibuf *);
340a137951Sdenis struct ibuf	*prepare_ls_ack(struct iface *);
35a1a4e97bSnorby void		 start_ls_ack_tx_timer_now(struct iface *);
36a1a4e97bSnorby 
37a1a4e97bSnorby /* link state acknowledgement packet handling */
380a137951Sdenis struct ibuf *
prepare_ls_ack(struct iface * iface)390a137951Sdenis prepare_ls_ack(struct iface *iface)
400a137951Sdenis {
410a137951Sdenis 	struct ibuf	*buf;
420a137951Sdenis 
430a137951Sdenis 	if ((buf = ibuf_open(iface->mtu - sizeof(struct ip6_hdr))) == NULL) {
440a137951Sdenis 		log_warn("prepare_ls_ack");
450a137951Sdenis 		return (NULL);
460a137951Sdenis 	}
470a137951Sdenis 
480a137951Sdenis 	/* OSPF header */
490a137951Sdenis 	if (gen_ospf_hdr(buf, iface, PACKET_TYPE_LS_ACK)) {
500a137951Sdenis 		log_warn("prepare_ls_ack");
510a137951Sdenis 		ibuf_free(buf);
520a137951Sdenis 		return (NULL);
530a137951Sdenis 	}
540a137951Sdenis 
550a137951Sdenis 	return (buf);
560a137951Sdenis }
570a137951Sdenis 
58a1a4e97bSnorby int
send_ls_ack(struct iface * iface,struct in6_addr addr,struct ibuf * buf)590a137951Sdenis send_ls_ack(struct iface *iface, struct in6_addr addr, struct ibuf *buf)
600a137951Sdenis {
610a137951Sdenis 	/* calculate checksum */
620a137951Sdenis 	if (upd_ospf_hdr(buf, iface)) {
630a137951Sdenis 		log_warn("send_ls_ack");
640a137951Sdenis 		return (-1);
650a137951Sdenis 	}
660a137951Sdenis 
670a137951Sdenis 	if (send_packet(iface, buf, &addr) == -1) {
680a137951Sdenis 		log_warn("send_ls_ack");
690a137951Sdenis 		return (-1);
700a137951Sdenis 	}
710a137951Sdenis 	return (0);
720a137951Sdenis }
730a137951Sdenis 
740a137951Sdenis int
send_direct_ack(struct iface * iface,struct in6_addr addr,void * d,size_t len)750a137951Sdenis send_direct_ack(struct iface *iface, struct in6_addr addr, void *d, size_t len)
76a1a4e97bSnorby {
77e39620e5Snicm 	struct ibuf	*buf;
78a1a4e97bSnorby 	int		 ret;
79a1a4e97bSnorby 
800a137951Sdenis 	if ((buf = prepare_ls_ack(iface)) == NULL)
810a137951Sdenis 		return (-1);
82a1a4e97bSnorby 
83a1a4e97bSnorby 	/* LS ack(s) */
840a137951Sdenis 	if (ibuf_add(buf, d, len)) {
850a137951Sdenis 		log_warn("send_direct_ack");
86e39620e5Snicm 		ibuf_free(buf);
87a1a4e97bSnorby 		return (-1);
88a1a4e97bSnorby 	}
89a1a4e97bSnorby 
900a137951Sdenis 	ret = send_ls_ack(iface, addr, buf);
910a137951Sdenis 	ibuf_free(buf);
920a137951Sdenis 	return (ret);
930a137951Sdenis }
940a137951Sdenis 
95a1a4e97bSnorby void
recv_ls_ack(struct nbr * nbr,char * buf,u_int16_t len)96a1a4e97bSnorby recv_ls_ack(struct nbr *nbr, char *buf, u_int16_t len)
97a1a4e97bSnorby {
98a1a4e97bSnorby 	struct lsa_hdr	 lsa_hdr;
99a1a4e97bSnorby 
100a1a4e97bSnorby 	switch (nbr->state) {
101a1a4e97bSnorby 	case NBR_STA_DOWN:
102a1a4e97bSnorby 	case NBR_STA_ATTEMPT:
103a1a4e97bSnorby 	case NBR_STA_INIT:
104a1a4e97bSnorby 	case NBR_STA_2_WAY:
105a1a4e97bSnorby 	case NBR_STA_XSTRT:
106a1a4e97bSnorby 	case NBR_STA_SNAP:
107a1a4e97bSnorby 		log_debug("recv_ls_ack: packet ignored in state %s, "
1089cc19ef1Ssthen 		    "neighbor ID %s (%s)", nbr_state_name(nbr->state),
1099cc19ef1Ssthen 		    inet_ntoa(nbr->id), nbr->iface->name);
110a1a4e97bSnorby 		break;
111a1a4e97bSnorby 	case NBR_STA_XCHNG:
112a1a4e97bSnorby 	case NBR_STA_LOAD:
113a1a4e97bSnorby 	case NBR_STA_FULL:
114a1a4e97bSnorby 		while (len >= sizeof(lsa_hdr)) {
115a1a4e97bSnorby 			memcpy(&lsa_hdr, buf, sizeof(lsa_hdr));
116a1a4e97bSnorby 
117a1a4e97bSnorby 			if (lsa_hdr_check(nbr, &lsa_hdr)) {
118a1a4e97bSnorby 				/* try both list in case of DROTHER */
119a1a4e97bSnorby 				if (nbr->iface->state & IF_STA_DROTHER)
120a1a4e97bSnorby 					(void)ls_retrans_list_del(
121a1a4e97bSnorby 					    nbr->iface->self, &lsa_hdr);
122a1a4e97bSnorby 				(void)ls_retrans_list_del(nbr, &lsa_hdr);
123a1a4e97bSnorby 			}
124a1a4e97bSnorby 
125a1a4e97bSnorby 			buf += sizeof(lsa_hdr);
126a1a4e97bSnorby 			len -= sizeof(lsa_hdr);
127a1a4e97bSnorby 		}
128a1a4e97bSnorby 		if (len > 0) {
129a1a4e97bSnorby 			log_warnx("recv_ls_ack: bad packet size, "
1309cc19ef1Ssthen 			    "neighbor ID %s (%s)", inet_ntoa(nbr->id),
1319cc19ef1Ssthen 			    nbr->iface->name);
132a1a4e97bSnorby 			return;
133a1a4e97bSnorby 		}
134a1a4e97bSnorby 		break;
135a1a4e97bSnorby 	default:
136a1a4e97bSnorby 		fatalx("recv_ls_ack: unknown neighbor state");
137a1a4e97bSnorby 	}
138a1a4e97bSnorby }
139a1a4e97bSnorby 
140a1a4e97bSnorby int
lsa_hdr_check(struct nbr * nbr,struct lsa_hdr * lsa_hdr)141a1a4e97bSnorby lsa_hdr_check(struct nbr *nbr, struct lsa_hdr *lsa_hdr)
142a1a4e97bSnorby {
143a1a4e97bSnorby 	/* invalid age */
144a1a4e97bSnorby 	if ((ntohs(lsa_hdr->age) < 1) || (ntohs(lsa_hdr->age) > MAX_AGE)) {
1459cc19ef1Ssthen 		log_debug("lsa_hdr_check: invalid age, neighbor ID %s (%s)",
1469cc19ef1Ssthen 		     inet_ntoa(nbr->id), nbr->iface->name);
147a1a4e97bSnorby 		return (0);
148a1a4e97bSnorby 	}
149a1a4e97bSnorby 
150a1a4e97bSnorby 	/* invalid type */
15125e30039Snorby 	switch (ntohs(lsa_hdr->type)) {
15219f3adaeSnorby 	case LSA_TYPE_LINK:
153a1a4e97bSnorby 	case LSA_TYPE_ROUTER:
154a1a4e97bSnorby 	case LSA_TYPE_NETWORK:
15519f3adaeSnorby 	case LSA_TYPE_INTER_A_PREFIX:
15619f3adaeSnorby 	case LSA_TYPE_INTER_A_ROUTER:
15719f3adaeSnorby 	case LSA_TYPE_INTRA_A_PREFIX:
158a1a4e97bSnorby 	case LSA_TYPE_EXTERNAL:
159a1a4e97bSnorby 		break;
160a1a4e97bSnorby 	default:
1619cc19ef1Ssthen 		log_debug("lsa_hdr_check: invalid LSA type %d, "
1629cc19ef1Ssthen 		    "neighbor ID %s (%s)",
1639cc19ef1Ssthen 		    lsa_hdr->type, inet_ntoa(nbr->id), nbr->iface->name);
164a1a4e97bSnorby 		return (0);
165a1a4e97bSnorby 	}
166a1a4e97bSnorby 
167a1a4e97bSnorby 	/* invalid sequence number */
168a1a4e97bSnorby 	if (ntohl(lsa_hdr->seq_num) == RESV_SEQ_NUM) {
1699cc19ef1Ssthen 		log_debug("ls_hdr_check: invalid seq num, "
1709cc19ef1Ssthen 		    "neighbor ID %s (%s)", inet_ntoa(nbr->id),
1719cc19ef1Ssthen 		    nbr->iface->name);
172a1a4e97bSnorby 		return (0);
173a1a4e97bSnorby 	}
174a1a4e97bSnorby 
175a1a4e97bSnorby 	return (1);
176a1a4e97bSnorby }
177a1a4e97bSnorby 
178a1a4e97bSnorby /* link state ack list */
179a1a4e97bSnorby void
ls_ack_list_add(struct iface * iface,struct lsa_hdr * lsa)180a1a4e97bSnorby ls_ack_list_add(struct iface *iface, struct lsa_hdr *lsa)
181a1a4e97bSnorby {
182a1a4e97bSnorby 	struct lsa_entry	*le;
183a1a4e97bSnorby 
184a1a4e97bSnorby 	if (lsa == NULL)
185a1a4e97bSnorby 		fatalx("ls_ack_list_add: no LSA header");
186a1a4e97bSnorby 
187a1a4e97bSnorby 	if ((le = calloc(1, sizeof(*le))) == NULL)
188a1a4e97bSnorby 		fatal("ls_ack_list_add");
189a1a4e97bSnorby 
190a1a4e97bSnorby 	if (ls_ack_list_empty(iface))
191a1a4e97bSnorby 		start_ls_ack_tx_timer(iface);
192a1a4e97bSnorby 
193a1a4e97bSnorby 	TAILQ_INSERT_TAIL(&iface->ls_ack_list, le, entry);
194a1a4e97bSnorby 	le->le_lsa = lsa;
195a1a4e97bSnorby 	iface->ls_ack_cnt++;
196a1a4e97bSnorby 
197a1a4e97bSnorby 	/* reschedule now if we have enough for a full packet */
198a1a4e97bSnorby 	if (iface->ls_ack_cnt >
199a1a4e97bSnorby 	    ((iface->mtu - PACKET_HDR) / sizeof(struct lsa_hdr))) {
200a1a4e97bSnorby 		start_ls_ack_tx_timer_now(iface);
201a1a4e97bSnorby 	}
202a1a4e97bSnorby }
203a1a4e97bSnorby 
204a1a4e97bSnorby void
ls_ack_list_free(struct iface * iface,struct lsa_entry * le)205a1a4e97bSnorby ls_ack_list_free(struct iface *iface, struct lsa_entry *le)
206a1a4e97bSnorby {
207a1a4e97bSnorby 	TAILQ_REMOVE(&iface->ls_ack_list, le, entry);
208a1a4e97bSnorby 	free(le->le_lsa);
209a1a4e97bSnorby 	free(le);
210a1a4e97bSnorby 
211a1a4e97bSnorby 	iface->ls_ack_cnt--;
212a1a4e97bSnorby }
213a1a4e97bSnorby 
214a1a4e97bSnorby void
ls_ack_list_clr(struct iface * iface)215a1a4e97bSnorby ls_ack_list_clr(struct iface *iface)
216a1a4e97bSnorby {
217a1a4e97bSnorby 	struct lsa_entry	*le;
218a1a4e97bSnorby 
219a1a4e97bSnorby 	while ((le = TAILQ_FIRST(&iface->ls_ack_list)) != NULL) {
220a1a4e97bSnorby 		TAILQ_REMOVE(&iface->ls_ack_list, le, entry);
221a1a4e97bSnorby 		free(le->le_lsa);
222a1a4e97bSnorby 		free(le);
223a1a4e97bSnorby 	}
224a1a4e97bSnorby 	iface->ls_ack_cnt = 0;
225a1a4e97bSnorby }
226a1a4e97bSnorby 
227a1a4e97bSnorby int
ls_ack_list_empty(struct iface * iface)228a1a4e97bSnorby ls_ack_list_empty(struct iface *iface)
229a1a4e97bSnorby {
230a1a4e97bSnorby 	return (TAILQ_EMPTY(&iface->ls_ack_list));
231a1a4e97bSnorby }
232a1a4e97bSnorby 
233a1a4e97bSnorby /* timers */
234a1a4e97bSnorby void
ls_ack_tx_timer(int fd,short event,void * arg)235a1a4e97bSnorby ls_ack_tx_timer(int fd, short event, void *arg)
236a1a4e97bSnorby {
237a1a4e97bSnorby 	struct in6_addr		 addr;
238a1a4e97bSnorby 	struct iface		*iface = arg;
239a1a4e97bSnorby 	struct lsa_entry	*le, *nle;
240a1a4e97bSnorby 	struct nbr		*nbr;
2410a137951Sdenis 	struct ibuf		*buf;
2420a137951Sdenis 	int			 cnt;
243a1a4e97bSnorby 
244a1a4e97bSnorby 	while (!ls_ack_list_empty(iface)) {
2450a137951Sdenis 		if ((buf = prepare_ls_ack(iface)) == NULL)
2460a137951Sdenis 			fatal("ls_ack_tx_timer");
247a1a4e97bSnorby 		cnt = 0;
2480a137951Sdenis 
2490a137951Sdenis 		for (le = TAILQ_FIRST(&iface->ls_ack_list); le != NULL;
2500a137951Sdenis 		    le = nle) {
251a1a4e97bSnorby 			nle = TAILQ_NEXT(le, entry);
2520a137951Sdenis 			if (ibuf_left(buf) < sizeof(struct lsa_hdr))
2530a137951Sdenis 				break;
2540a137951Sdenis 			if (ibuf_add(buf, le->le_lsa, sizeof(struct lsa_hdr)))
2550a137951Sdenis 				break;
256a1a4e97bSnorby 			ls_ack_list_free(iface, le);
257a1a4e97bSnorby 			cnt++;
258a1a4e97bSnorby 		}
2590a137951Sdenis 		if (cnt == 0) {
2600a137951Sdenis 			log_warnx("ls_ack_tx_timer: lost in space");
2610a137951Sdenis 			ibuf_free(buf);
2620a137951Sdenis 			return;
2630a137951Sdenis 		}
264a1a4e97bSnorby 
265a1a4e97bSnorby 		/* send LS ack(s) but first set correct destination */
266a1a4e97bSnorby 		switch (iface->type) {
267a1a4e97bSnorby 		case IF_TYPE_POINTOPOINT:
268a1a4e97bSnorby 			inet_pton(AF_INET6, AllSPFRouters, &addr);
2690a137951Sdenis 			send_ls_ack(iface, addr, buf);
270a1a4e97bSnorby 			break;
271a1a4e97bSnorby 		case IF_TYPE_BROADCAST:
272a1a4e97bSnorby 			if (iface->state & IF_STA_DRORBDR)
273a1a4e97bSnorby 				inet_pton(AF_INET6, AllSPFRouters, &addr);
274a1a4e97bSnorby 			else
275a1a4e97bSnorby 				inet_pton(AF_INET6, AllDRouters, &addr);
2760a137951Sdenis 			send_ls_ack(iface, addr, buf);
277a1a4e97bSnorby 			break;
278a1a4e97bSnorby 		case IF_TYPE_NBMA:
279a1a4e97bSnorby 		case IF_TYPE_POINTOMULTIPOINT:
280a1a4e97bSnorby 		case IF_TYPE_VIRTUALLINK:
281a1a4e97bSnorby 			LIST_FOREACH(nbr, &iface->nbr_list, entry) {
282a1a4e97bSnorby 				if (nbr == iface->self)
283a1a4e97bSnorby 					continue;
284a1a4e97bSnorby 				if (!(nbr->state & NBR_STA_FLOOD))
285a1a4e97bSnorby 					continue;
2860a137951Sdenis 				send_ls_ack(iface, nbr->addr, buf);
287a1a4e97bSnorby 			}
288a1a4e97bSnorby 			break;
289a1a4e97bSnorby 		default:
290a1a4e97bSnorby 			fatalx("lsa_ack_tx_timer: unknown interface type");
291a1a4e97bSnorby 		}
2920a137951Sdenis 		ibuf_free(buf);
293a1a4e97bSnorby 	}
294a1a4e97bSnorby }
295a1a4e97bSnorby 
296a1a4e97bSnorby void
start_ls_ack_tx_timer(struct iface * iface)297a1a4e97bSnorby start_ls_ack_tx_timer(struct iface *iface)
298a1a4e97bSnorby {
299a1a4e97bSnorby 	struct timeval tv;
300a1a4e97bSnorby 
301a1a4e97bSnorby 	timerclear(&tv);
302a1a4e97bSnorby 	tv.tv_sec = iface->rxmt_interval / 2;
303a1a4e97bSnorby 
304a1a4e97bSnorby 	if (evtimer_add(&iface->lsack_tx_timer, &tv) == -1)
305a1a4e97bSnorby 		fatal("start_ls_ack_tx_timer");
306a1a4e97bSnorby }
307a1a4e97bSnorby 
308a1a4e97bSnorby void
start_ls_ack_tx_timer_now(struct iface * iface)309a1a4e97bSnorby start_ls_ack_tx_timer_now(struct iface *iface)
310a1a4e97bSnorby {
311a1a4e97bSnorby 	struct timeval tv;
312a1a4e97bSnorby 
313a1a4e97bSnorby 	timerclear(&tv);
314a1a4e97bSnorby 	if (evtimer_add(&iface->lsack_tx_timer, &tv) == -1)
315a1a4e97bSnorby 		fatal("start_ls_ack_tx_timer_now");
316a1a4e97bSnorby }
317a1a4e97bSnorby 
318a1a4e97bSnorby void
stop_ls_ack_tx_timer(struct iface * iface)319a1a4e97bSnorby stop_ls_ack_tx_timer(struct iface *iface)
320a1a4e97bSnorby {
321a1a4e97bSnorby 	if (evtimer_del(&iface->lsack_tx_timer) == -1)
322a1a4e97bSnorby 		fatal("stop_ls_ack_tx_timer");
323a1a4e97bSnorby }
324