xref: /openbsd-src/usr.sbin/ospf6d/lsreq.c (revision bf2cf3053df3551d6121df7fcab39bf211c112b2)
1*bf2cf305Sclaudio /*	$OpenBSD: lsreq.c,v 1.15 2023/07/03 09:51:38 claudio 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>
22df59d22fSclaudio #include <netinet/ip6.h>
23a1a4e97bSnorby #include <arpa/inet.h>
24a1a4e97bSnorby #include <stdlib.h>
25a1a4e97bSnorby 
26a1a4e97bSnorby #include "ospf6d.h"
27a1a4e97bSnorby #include "ospf6.h"
28a1a4e97bSnorby #include "log.h"
29a1a4e97bSnorby #include "ospfe.h"
30a1a4e97bSnorby 
31a1a4e97bSnorby /* link state request packet handling */
32a1a4e97bSnorby int
send_ls_req(struct nbr * nbr)33a1a4e97bSnorby send_ls_req(struct nbr *nbr)
34a1a4e97bSnorby {
3552bf80cbSclaudio 	struct in6_addr		 dst;
36a1a4e97bSnorby 	struct ls_req_hdr	 ls_req_hdr;
37a1a4e97bSnorby 	struct lsa_entry	*le, *nle;
38e39620e5Snicm 	struct ibuf		*buf;
39a1a4e97bSnorby 
40df59d22fSclaudio 	if ((buf = ibuf_open(nbr->iface->mtu - sizeof(struct ip6_hdr))) == NULL)
41a1a4e97bSnorby 		fatal("send_ls_req");
42a1a4e97bSnorby 
43a1a4e97bSnorby 	switch (nbr->iface->type) {
44a1a4e97bSnorby 	case IF_TYPE_POINTOPOINT:
4552bf80cbSclaudio 		inet_pton(AF_INET6, AllSPFRouters, &dst);
46a1a4e97bSnorby 		break;
47a1a4e97bSnorby 	case IF_TYPE_BROADCAST:
48a1a4e97bSnorby 	case IF_TYPE_NBMA:
49a1a4e97bSnorby 	case IF_TYPE_POINTOMULTIPOINT:
50a1a4e97bSnorby 	case IF_TYPE_VIRTUALLINK:
5152bf80cbSclaudio 		dst = nbr->addr;
52a1a4e97bSnorby 		break;
53a1a4e97bSnorby 	default:
54a1a4e97bSnorby 		fatalx("send_ls_req: unknown interface type");
55a1a4e97bSnorby 	}
56a1a4e97bSnorby 
57a1a4e97bSnorby 	/* OSPF header */
58a1a4e97bSnorby 	if (gen_ospf_hdr(buf, nbr->iface, PACKET_TYPE_LS_REQUEST))
59a1a4e97bSnorby 		goto fail;
60a1a4e97bSnorby 
610edf49a6Sbluhm 	/* LSA header(s) */
62*bf2cf305Sclaudio 	for (le = TAILQ_FIRST(&nbr->ls_req_list);
63*bf2cf305Sclaudio 	    le != NULL && sizeof(ls_req_hdr) < ibuf_left(buf);
64*bf2cf305Sclaudio 	    le = nle) {
65a1a4e97bSnorby 		nbr->ls_req = nle = TAILQ_NEXT(le, entry);
6617817b50Sclaudio 		ls_req_hdr.zero = 0;
6717817b50Sclaudio 		ls_req_hdr.type = le->le_lsa->type;
68a1a4e97bSnorby 		ls_req_hdr.ls_id = le->le_lsa->ls_id;
69a1a4e97bSnorby 		ls_req_hdr.adv_rtr = le->le_lsa->adv_rtr;
70e39620e5Snicm 		if (ibuf_add(buf, &ls_req_hdr, sizeof(ls_req_hdr)))
71a1a4e97bSnorby 			goto fail;
72a1a4e97bSnorby 	}
73a1a4e97bSnorby 
74a1a4e97bSnorby 	/* calculate checksum */
75a1a4e97bSnorby 	if (upd_ospf_hdr(buf, nbr->iface))
76a1a4e97bSnorby 		goto fail;
77a1a4e97bSnorby 
780a137951Sdenis 	if (send_packet(nbr->iface, buf, &dst) == -1)
790a137951Sdenis 		goto fail;
80a1a4e97bSnorby 
81e39620e5Snicm 	ibuf_free(buf);
820a137951Sdenis 	return (0);
83a1a4e97bSnorby fail:
84a1a4e97bSnorby 	log_warn("send_ls_req");
85e39620e5Snicm 	ibuf_free(buf);
86a1a4e97bSnorby 	return (-1);
87a1a4e97bSnorby }
88a1a4e97bSnorby 
89a1a4e97bSnorby void
recv_ls_req(struct nbr * nbr,char * buf,u_int16_t len)90a1a4e97bSnorby recv_ls_req(struct nbr *nbr, char *buf, u_int16_t len)
91a1a4e97bSnorby {
92a1a4e97bSnorby 	switch (nbr->state) {
93a1a4e97bSnorby 	case NBR_STA_DOWN:
94a1a4e97bSnorby 	case NBR_STA_ATTEMPT:
95a1a4e97bSnorby 	case NBR_STA_INIT:
96a1a4e97bSnorby 	case NBR_STA_2_WAY:
97a1a4e97bSnorby 	case NBR_STA_XSTRT:
98a1a4e97bSnorby 	case NBR_STA_SNAP:
99a1a4e97bSnorby 		log_debug("recv_ls_req: packet ignored in state %s, "
1009cc19ef1Ssthen 		    "neighbor ID %s (%s)", nbr_state_name(nbr->state),
1019cc19ef1Ssthen 		    inet_ntoa(nbr->id), nbr->iface->name);
102a1a4e97bSnorby 		break;
103a1a4e97bSnorby 	case NBR_STA_XCHNG:
104a1a4e97bSnorby 	case NBR_STA_LOAD:
105a1a4e97bSnorby 	case NBR_STA_FULL:
106980c654eSclaudio 		ospfe_imsg_compose_rde(IMSG_LS_REQ, nbr->peerid, 0, buf, len);
107a1a4e97bSnorby 		break;
108a1a4e97bSnorby 	default:
109a1a4e97bSnorby 		fatalx("recv_ls_req: unknown neighbor state");
110a1a4e97bSnorby 	}
111a1a4e97bSnorby }
112a1a4e97bSnorby 
113a1a4e97bSnorby /* link state request list */
114a1a4e97bSnorby void
ls_req_list_add(struct nbr * nbr,struct lsa_hdr * lsa)115a1a4e97bSnorby ls_req_list_add(struct nbr *nbr, struct lsa_hdr *lsa)
116a1a4e97bSnorby {
117a1a4e97bSnorby 	struct lsa_entry	*le;
118a1a4e97bSnorby 
119a1a4e97bSnorby 	if (lsa == NULL)
120a1a4e97bSnorby 		fatalx("ls_req_list_add: no LSA header");
121a1a4e97bSnorby 
122a1a4e97bSnorby 	if ((le = calloc(1, sizeof(*le))) == NULL)
123a1a4e97bSnorby 		fatal("ls_req_list_add");
124a1a4e97bSnorby 
125a1a4e97bSnorby 	TAILQ_INSERT_TAIL(&nbr->ls_req_list, le, entry);
126a1a4e97bSnorby 	le->le_lsa = lsa;
127a1a4e97bSnorby 	nbr->ls_req_cnt++;
128a1a4e97bSnorby }
129a1a4e97bSnorby 
130a1a4e97bSnorby struct lsa_entry *
ls_req_list_get(struct nbr * nbr,struct lsa_hdr * lsa_hdr)131a1a4e97bSnorby ls_req_list_get(struct nbr *nbr, struct lsa_hdr *lsa_hdr)
132a1a4e97bSnorby {
133a1a4e97bSnorby 	struct lsa_entry	*le;
134a1a4e97bSnorby 
135a1a4e97bSnorby 	TAILQ_FOREACH(le, &nbr->ls_req_list, entry) {
136a1a4e97bSnorby 		if ((lsa_hdr->type == le->le_lsa->type) &&
137a1a4e97bSnorby 		    (lsa_hdr->ls_id == le->le_lsa->ls_id) &&
138a1a4e97bSnorby 		    (lsa_hdr->adv_rtr == le->le_lsa->adv_rtr))
139a1a4e97bSnorby 			return (le);
140a1a4e97bSnorby 	}
141a1a4e97bSnorby 	return (NULL);
142a1a4e97bSnorby }
143a1a4e97bSnorby 
144a1a4e97bSnorby void
ls_req_list_free(struct nbr * nbr,struct lsa_entry * le)145a1a4e97bSnorby ls_req_list_free(struct nbr *nbr, struct lsa_entry *le)
146a1a4e97bSnorby {
147a1a4e97bSnorby 	if (nbr->ls_req == le) {
148a1a4e97bSnorby 		nbr->ls_req = TAILQ_NEXT(le, entry);
149a1a4e97bSnorby 	}
150a1a4e97bSnorby 
151a1a4e97bSnorby 	TAILQ_REMOVE(&nbr->ls_req_list, le, entry);
152a1a4e97bSnorby 	free(le->le_lsa);
153a1a4e97bSnorby 	free(le);
154a1a4e97bSnorby 	nbr->ls_req_cnt--;
155a1a4e97bSnorby 
156a1a4e97bSnorby 	/* received all requested LSA(s), send a new LS req */
157a1a4e97bSnorby 	if (nbr->ls_req != NULL &&
158a1a4e97bSnorby 	    nbr->ls_req == TAILQ_FIRST(&nbr->ls_req_list)) {
159a1a4e97bSnorby 		start_ls_req_tx_timer(nbr);
160a1a4e97bSnorby 	}
161a1a4e97bSnorby 
1620a05e8afSsthen 	/* we might not have received all DDs and are still in XCHNG */
1630a05e8afSsthen 	if (ls_req_list_empty(nbr) && nbr->dd_pending == 0 &&
1640a05e8afSsthen 	    nbr->state != NBR_STA_XCHNG)
165a1a4e97bSnorby 		nbr_fsm(nbr, NBR_EVT_LOAD_DONE);
166a1a4e97bSnorby }
167a1a4e97bSnorby 
168a1a4e97bSnorby void
ls_req_list_clr(struct nbr * nbr)169a1a4e97bSnorby ls_req_list_clr(struct nbr *nbr)
170a1a4e97bSnorby {
171a1a4e97bSnorby 	struct lsa_entry	*le;
172a1a4e97bSnorby 
173a1a4e97bSnorby 	while ((le = TAILQ_FIRST(&nbr->ls_req_list)) != NULL) {
174a1a4e97bSnorby 		TAILQ_REMOVE(&nbr->ls_req_list, le, entry);
175a1a4e97bSnorby 		free(le->le_lsa);
176a1a4e97bSnorby 		free(le);
177a1a4e97bSnorby 	}
178a1a4e97bSnorby 
179a1a4e97bSnorby 	nbr->ls_req_cnt = 0;
180a1a4e97bSnorby 	nbr->ls_req = NULL;
181a1a4e97bSnorby }
182a1a4e97bSnorby 
183a1a4e97bSnorby int
ls_req_list_empty(struct nbr * nbr)184a1a4e97bSnorby ls_req_list_empty(struct nbr *nbr)
185a1a4e97bSnorby {
186a1a4e97bSnorby 	return (TAILQ_EMPTY(&nbr->ls_req_list));
187a1a4e97bSnorby }
188a1a4e97bSnorby 
189a1a4e97bSnorby /* timers */
190a1a4e97bSnorby void
ls_req_tx_timer(int fd,short event,void * arg)191a1a4e97bSnorby ls_req_tx_timer(int fd, short event, void *arg)
192a1a4e97bSnorby {
193a1a4e97bSnorby 	struct nbr	*nbr = arg;
194a1a4e97bSnorby 	struct timeval	 tv;
195a1a4e97bSnorby 
196a1a4e97bSnorby 	switch (nbr->state) {
197a1a4e97bSnorby 	case NBR_STA_DOWN:
198a1a4e97bSnorby 	case NBR_STA_ATTEMPT:
199a1a4e97bSnorby 	case NBR_STA_INIT:
200a1a4e97bSnorby 	case NBR_STA_2_WAY:
201a1a4e97bSnorby 	case NBR_STA_SNAP:
202a1a4e97bSnorby 	case NBR_STA_XSTRT:
203a1a4e97bSnorby 	case NBR_STA_XCHNG:
204a1a4e97bSnorby 		return;
205a1a4e97bSnorby 	case NBR_STA_LOAD:
206a1a4e97bSnorby 		send_ls_req(nbr);
207a1a4e97bSnorby 		break;
208a1a4e97bSnorby 	case NBR_STA_FULL:
209a1a4e97bSnorby 		return;
210a1a4e97bSnorby 	default:
211a1a4e97bSnorby 		log_debug("ls_req_tx_timer: unknown neighbor state, "
2129cc19ef1Ssthen 		    "neighbor ID %s (%s)", inet_ntoa(nbr->id),
2139cc19ef1Ssthen 		    nbr->iface->name);
214a1a4e97bSnorby 		break;
215a1a4e97bSnorby 	}
216a1a4e97bSnorby 
217a1a4e97bSnorby 	/* reschedule lsreq_tx_timer */
218a1a4e97bSnorby 	if (nbr->state == NBR_STA_LOAD) {
219a1a4e97bSnorby 		timerclear(&tv);
220a1a4e97bSnorby 		tv.tv_sec = nbr->iface->rxmt_interval;
221a1a4e97bSnorby 		if (evtimer_add(&nbr->lsreq_tx_timer, &tv) == -1)
222a1a4e97bSnorby 			fatal("ls_req_tx_timer");
223a1a4e97bSnorby 	}
224a1a4e97bSnorby }
225a1a4e97bSnorby 
226a1a4e97bSnorby void
start_ls_req_tx_timer(struct nbr * nbr)227a1a4e97bSnorby start_ls_req_tx_timer(struct nbr *nbr)
228a1a4e97bSnorby {
229a1a4e97bSnorby 	struct timeval tv;
230a1a4e97bSnorby 
231a1a4e97bSnorby 	if (nbr == nbr->iface->self)
232a1a4e97bSnorby 		return;
233a1a4e97bSnorby 
234a1a4e97bSnorby 	timerclear(&tv);
235a1a4e97bSnorby 	if (evtimer_add(&nbr->lsreq_tx_timer, &tv) == -1)
236a1a4e97bSnorby 		fatal("start_ls_req_tx_timer");
237a1a4e97bSnorby }
238a1a4e97bSnorby 
239a1a4e97bSnorby void
stop_ls_req_tx_timer(struct nbr * nbr)240a1a4e97bSnorby stop_ls_req_tx_timer(struct nbr *nbr)
241a1a4e97bSnorby {
242a1a4e97bSnorby 	if (nbr == nbr->iface->self)
243a1a4e97bSnorby 		return;
244a1a4e97bSnorby 
245a1a4e97bSnorby 	if (evtimer_del(&nbr->lsreq_tx_timer) == -1)
246a1a4e97bSnorby 		fatal("stop_ls_req_tx_timer");
247a1a4e97bSnorby }
248