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