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