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