xref: /openbsd-src/usr.sbin/ospfd/lsreq.c (revision 4f4fe40bc9d06de09f4af934b87299ab1ee3cc66)
1*4f4fe40bSflorian /*	$OpenBSD: lsreq.c,v 1.25 2024/08/21 15:18:00 florian Exp $ */
2204df0f8Sclaudio 
3204df0f8Sclaudio /*
4367f601bSnorby  * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
5204df0f8Sclaudio  *
6204df0f8Sclaudio  * Permission to use, copy, modify, and distribute this software for any
7204df0f8Sclaudio  * purpose with or without fee is hereby granted, provided that the above
8204df0f8Sclaudio  * copyright notice and this permission notice appear in all copies.
9204df0f8Sclaudio  *
10204df0f8Sclaudio  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11204df0f8Sclaudio  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12204df0f8Sclaudio  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13204df0f8Sclaudio  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14204df0f8Sclaudio  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15204df0f8Sclaudio  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16204df0f8Sclaudio  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17204df0f8Sclaudio  */
18204df0f8Sclaudio 
19204df0f8Sclaudio #include <sys/types.h>
20204df0f8Sclaudio #include <sys/socket.h>
21204df0f8Sclaudio #include <netinet/in.h>
22204df0f8Sclaudio #include <arpa/inet.h>
23204df0f8Sclaudio #include <stdlib.h>
24204df0f8Sclaudio 
25204df0f8Sclaudio #include "ospfd.h"
26204df0f8Sclaudio #include "ospf.h"
27204df0f8Sclaudio #include "log.h"
28204df0f8Sclaudio #include "ospfe.h"
29204df0f8Sclaudio 
30204df0f8Sclaudio /* link state request packet handling */
31204df0f8Sclaudio int
32204df0f8Sclaudio send_ls_req(struct nbr *nbr)
33204df0f8Sclaudio {
34204df0f8Sclaudio 	struct sockaddr_in	 dst;
350491ce75Sclaudio 	struct ls_req_hdr	 ls_req_hdr;
36204df0f8Sclaudio 	struct lsa_entry	*le, *nle;
37e39620e5Snicm 	struct ibuf		*buf;
38204df0f8Sclaudio 
39e39620e5Snicm 	if ((buf = ibuf_open(nbr->iface->mtu - sizeof(struct ip))) == NULL)
40204df0f8Sclaudio 		fatal("send_ls_req");
41204df0f8Sclaudio 
42204df0f8Sclaudio 	/* set destination */
43204df0f8Sclaudio 	dst.sin_family = AF_INET;
44204df0f8Sclaudio 	dst.sin_len = sizeof(struct sockaddr_in);
45204df0f8Sclaudio 
46204df0f8Sclaudio 	switch (nbr->iface->type) {
47204df0f8Sclaudio 	case IF_TYPE_POINTOPOINT:
48*4f4fe40bSflorian 		inet_pton(AF_INET, AllSPFRouters, &dst.sin_addr);
49204df0f8Sclaudio 		break;
50204df0f8Sclaudio 	case IF_TYPE_BROADCAST:
51204df0f8Sclaudio 	case IF_TYPE_NBMA:
52204df0f8Sclaudio 	case IF_TYPE_POINTOMULTIPOINT:
53204df0f8Sclaudio 	case IF_TYPE_VIRTUALLINK:
54204df0f8Sclaudio 		dst.sin_addr.s_addr = nbr->addr.s_addr;
55204df0f8Sclaudio 		break;
56204df0f8Sclaudio 	default:
57204df0f8Sclaudio 		fatalx("send_ls_req: unknown interface type");
58204df0f8Sclaudio 	}
59204df0f8Sclaudio 
60204df0f8Sclaudio 	/* OSPF header */
610491ce75Sclaudio 	if (gen_ospf_hdr(buf, nbr->iface, PACKET_TYPE_LS_REQUEST))
620491ce75Sclaudio 		goto fail;
63204df0f8Sclaudio 
640491ce75Sclaudio 	/* LSA header(s), keep space for a possible md5 sum */
65204df0f8Sclaudio 	for (le = TAILQ_FIRST(&nbr->ls_req_list); le != NULL &&
66e39620e5Snicm 	    ibuf_left(buf) >= sizeof(struct ls_req_hdr) + MD5_DIGEST_LENGTH;
679627de93Sclaudio 	    le = nle) {
68204df0f8Sclaudio 		nbr->ls_req = nle = TAILQ_NEXT(le, entry);
690491ce75Sclaudio 		ls_req_hdr.type = htonl(le->le_lsa->type);
700491ce75Sclaudio 		ls_req_hdr.ls_id = le->le_lsa->ls_id;
710491ce75Sclaudio 		ls_req_hdr.adv_rtr = le->le_lsa->adv_rtr;
72e39620e5Snicm 		if (ibuf_add(buf, &ls_req_hdr, sizeof(ls_req_hdr)))
730491ce75Sclaudio 			goto fail;
74204df0f8Sclaudio 	}
75204df0f8Sclaudio 
76204df0f8Sclaudio 	/* update authentication and calculate checksum */
770491ce75Sclaudio 	if (auth_gen(buf, nbr->iface))
780491ce75Sclaudio 		goto fail;
79204df0f8Sclaudio 
8025a742ccSremi 	if (send_packet(nbr->iface, buf, &dst) == -1)
8125a742ccSremi 		goto fail;
820491ce75Sclaudio 
83e39620e5Snicm 	ibuf_free(buf);
8425a742ccSremi 	return (0);
850491ce75Sclaudio fail:
8625a742ccSremi 	log_warn("%s", __func__);
87e39620e5Snicm 	ibuf_free(buf);
880491ce75Sclaudio 	return (-1);
89204df0f8Sclaudio }
90204df0f8Sclaudio 
91204df0f8Sclaudio void
92204df0f8Sclaudio recv_ls_req(struct nbr *nbr, char *buf, u_int16_t len)
93204df0f8Sclaudio {
94204df0f8Sclaudio 	switch (nbr->state) {
95204df0f8Sclaudio 	case NBR_STA_DOWN:
96204df0f8Sclaudio 	case NBR_STA_ATTEMPT:
97204df0f8Sclaudio 	case NBR_STA_INIT:
98204df0f8Sclaudio 	case NBR_STA_2_WAY:
99204df0f8Sclaudio 	case NBR_STA_XSTRT:
100204df0f8Sclaudio 	case NBR_STA_SNAP:
101204df0f8Sclaudio 		log_debug("recv_ls_req: packet ignored in state %s, "
1029cc19ef1Ssthen 		    "neighbor ID %s (%s)", nbr_state_name(nbr->state),
1039cc19ef1Ssthen 		    inet_ntoa(nbr->id), nbr->iface->name);
104204df0f8Sclaudio 		break;
105204df0f8Sclaudio 	case NBR_STA_XCHNG:
106204df0f8Sclaudio 	case NBR_STA_LOAD:
107204df0f8Sclaudio 	case NBR_STA_FULL:
1086efdfed8Sclaudio 		ospfe_imsg_compose_rde(IMSG_LS_REQ, nbr->peerid, 0, buf, len);
109204df0f8Sclaudio 		break;
110204df0f8Sclaudio 	default:
111204df0f8Sclaudio 		fatalx("recv_ls_req: unknown neighbor state");
112204df0f8Sclaudio 	}
113204df0f8Sclaudio }
114204df0f8Sclaudio 
115204df0f8Sclaudio /* link state request list */
116204df0f8Sclaudio void
117204df0f8Sclaudio ls_req_list_add(struct nbr *nbr, struct lsa_hdr *lsa)
118204df0f8Sclaudio {
119204df0f8Sclaudio 	struct lsa_entry	*le;
120204df0f8Sclaudio 
121204df0f8Sclaudio 	if (lsa == NULL)
122204df0f8Sclaudio 		fatalx("ls_req_list_add: no LSA header");
123204df0f8Sclaudio 
124204df0f8Sclaudio 	if ((le = calloc(1, sizeof(*le))) == NULL)
125204df0f8Sclaudio 		fatal("ls_req_list_add");
126204df0f8Sclaudio 
127204df0f8Sclaudio 	TAILQ_INSERT_TAIL(&nbr->ls_req_list, le, entry);
128204df0f8Sclaudio 	le->le_lsa = lsa;
129204df0f8Sclaudio 	nbr->ls_req_cnt++;
130204df0f8Sclaudio }
131204df0f8Sclaudio 
132204df0f8Sclaudio struct lsa_entry *
133204df0f8Sclaudio ls_req_list_get(struct nbr *nbr, struct lsa_hdr *lsa_hdr)
134204df0f8Sclaudio {
135204df0f8Sclaudio 	struct lsa_entry	*le;
136204df0f8Sclaudio 
137204df0f8Sclaudio 	TAILQ_FOREACH(le, &nbr->ls_req_list, entry) {
138204df0f8Sclaudio 		if ((lsa_hdr->type == le->le_lsa->type) &&
139204df0f8Sclaudio 		    (lsa_hdr->ls_id == le->le_lsa->ls_id) &&
140204df0f8Sclaudio 		    (lsa_hdr->adv_rtr == le->le_lsa->adv_rtr))
141204df0f8Sclaudio 			return (le);
142204df0f8Sclaudio 	}
143204df0f8Sclaudio 	return (NULL);
144204df0f8Sclaudio }
145204df0f8Sclaudio 
146204df0f8Sclaudio void
147204df0f8Sclaudio ls_req_list_free(struct nbr *nbr, struct lsa_entry *le)
148204df0f8Sclaudio {
149204df0f8Sclaudio 	if (nbr->ls_req == le) {
150204df0f8Sclaudio 		nbr->ls_req = TAILQ_NEXT(le, entry);
151204df0f8Sclaudio 	}
152204df0f8Sclaudio 
153204df0f8Sclaudio 	TAILQ_REMOVE(&nbr->ls_req_list, le, entry);
154204df0f8Sclaudio 	free(le->le_lsa);
155204df0f8Sclaudio 	free(le);
156204df0f8Sclaudio 	nbr->ls_req_cnt--;
157204df0f8Sclaudio 
158204df0f8Sclaudio 	/* received all requested LSA(s), send a new LS req */
159204df0f8Sclaudio 	if (nbr->ls_req != NULL &&
160204df0f8Sclaudio 	    nbr->ls_req == TAILQ_FIRST(&nbr->ls_req_list)) {
161204df0f8Sclaudio 		start_ls_req_tx_timer(nbr);
162204df0f8Sclaudio 	}
163204df0f8Sclaudio 
164b24d9cd1Smarkus 	/* we might not have received all DDs and are still in XCHNG */
165b24d9cd1Smarkus 	if (ls_req_list_empty(nbr) && nbr->dd_pending == 0 &&
166b24d9cd1Smarkus 	    nbr->state != NBR_STA_XCHNG)
167204df0f8Sclaudio 		nbr_fsm(nbr, NBR_EVT_LOAD_DONE);
168204df0f8Sclaudio }
169204df0f8Sclaudio 
170204df0f8Sclaudio void
171204df0f8Sclaudio ls_req_list_clr(struct nbr *nbr)
172204df0f8Sclaudio {
173204df0f8Sclaudio 	struct lsa_entry	*le;
174204df0f8Sclaudio 
175204df0f8Sclaudio 	while ((le = TAILQ_FIRST(&nbr->ls_req_list)) != NULL) {
176204df0f8Sclaudio 		TAILQ_REMOVE(&nbr->ls_req_list, le, entry);
177204df0f8Sclaudio 		free(le->le_lsa);
178204df0f8Sclaudio 		free(le);
179204df0f8Sclaudio 	}
180204df0f8Sclaudio 
181204df0f8Sclaudio 	nbr->ls_req_cnt = 0;
182204df0f8Sclaudio 	nbr->ls_req = NULL;
183204df0f8Sclaudio }
184204df0f8Sclaudio 
1855c6e55e9Snorby int
186204df0f8Sclaudio ls_req_list_empty(struct nbr *nbr)
187204df0f8Sclaudio {
188204df0f8Sclaudio 	return (TAILQ_EMPTY(&nbr->ls_req_list));
189204df0f8Sclaudio }
190204df0f8Sclaudio 
191204df0f8Sclaudio /* timers */
192204df0f8Sclaudio void
193204df0f8Sclaudio ls_req_tx_timer(int fd, short event, void *arg)
194204df0f8Sclaudio {
195204df0f8Sclaudio 	struct nbr	*nbr = arg;
196204df0f8Sclaudio 	struct timeval	 tv;
197204df0f8Sclaudio 
198204df0f8Sclaudio 	switch (nbr->state) {
199204df0f8Sclaudio 	case NBR_STA_DOWN:
200204df0f8Sclaudio 	case NBR_STA_ATTEMPT:
201204df0f8Sclaudio 	case NBR_STA_INIT:
202204df0f8Sclaudio 	case NBR_STA_2_WAY:
203204df0f8Sclaudio 	case NBR_STA_SNAP:
204204df0f8Sclaudio 	case NBR_STA_XSTRT:
205204df0f8Sclaudio 	case NBR_STA_XCHNG:
206204df0f8Sclaudio 		return;
207204df0f8Sclaudio 	case NBR_STA_LOAD:
208204df0f8Sclaudio 		send_ls_req(nbr);
209204df0f8Sclaudio 		break;
210204df0f8Sclaudio 	case NBR_STA_FULL:
211204df0f8Sclaudio 		return;
212204df0f8Sclaudio 	default:
213204df0f8Sclaudio 		log_debug("ls_req_tx_timer: unknown neighbor state, "
2149cc19ef1Ssthen 		    "neighbor ID %s (%s)", inet_ntoa(nbr->id),
2159cc19ef1Ssthen 		    nbr->iface->name);
216204df0f8Sclaudio 		break;
217204df0f8Sclaudio 	}
218204df0f8Sclaudio 
219204df0f8Sclaudio 	/* reschedule lsreq_tx_timer */
220204df0f8Sclaudio 	if (nbr->state == NBR_STA_LOAD) {
221204df0f8Sclaudio 		timerclear(&tv);
222204df0f8Sclaudio 		tv.tv_sec = nbr->iface->rxmt_interval;
2233aede346Sclaudio 		if (evtimer_add(&nbr->lsreq_tx_timer, &tv) == -1)
2243aede346Sclaudio 			fatal("ls_req_tx_timer");
225204df0f8Sclaudio 	}
226204df0f8Sclaudio }
227204df0f8Sclaudio 
2283aede346Sclaudio void
229204df0f8Sclaudio start_ls_req_tx_timer(struct nbr *nbr)
230204df0f8Sclaudio {
231204df0f8Sclaudio 	struct timeval tv;
232204df0f8Sclaudio 
233204df0f8Sclaudio 	if (nbr == nbr->iface->self)
2343aede346Sclaudio 		return;
235204df0f8Sclaudio 
236204df0f8Sclaudio 	timerclear(&tv);
2373aede346Sclaudio 	if (evtimer_add(&nbr->lsreq_tx_timer, &tv) == -1)
2383aede346Sclaudio 		fatal("start_ls_req_tx_timer");
239204df0f8Sclaudio }
240204df0f8Sclaudio 
2413aede346Sclaudio void
242204df0f8Sclaudio stop_ls_req_tx_timer(struct nbr *nbr)
243204df0f8Sclaudio {
244204df0f8Sclaudio 	if (nbr == nbr->iface->self)
2453aede346Sclaudio 		return;
246204df0f8Sclaudio 
2473aede346Sclaudio 	if (evtimer_del(&nbr->lsreq_tx_timer) == -1)
2483aede346Sclaudio 		fatal("stop_ls_req_tx_timer");
249204df0f8Sclaudio }
250