1 /* $OpenBSD: database.c,v 1.23 2023/06/21 07:45:47 claudio Exp $ */
2
3 /*
4 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
5 * Copyright (c) 2004, 2005, 2007 Esben Norby <norby@openbsd.org>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <netinet/ip6.h>
24 #include <arpa/inet.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28
29 #include "ospf6d.h"
30 #include "ospf6.h"
31 #include "log.h"
32 #include "ospfe.h"
33
34 void db_sum_list_next(struct nbr *);
35
36 /* database description packet handling */
37 int
send_db_description(struct nbr * nbr)38 send_db_description(struct nbr *nbr)
39 {
40 struct in6_addr dst;
41 struct db_dscrp_hdr dd_hdr;
42 struct lsa_entry *le, *nle;
43 struct ibuf *buf;
44 u_int8_t bits = 0;
45
46 if ((buf = ibuf_open(nbr->iface->mtu - sizeof(struct ip6_hdr))) == NULL)
47 fatal("send_db_description");
48
49 /* OSPF header */
50 if (gen_ospf_hdr(buf, nbr->iface, PACKET_TYPE_DD))
51 goto fail;
52
53 /* reserve space for database description header */
54 if (ibuf_add_zero(buf, sizeof(dd_hdr)) == -1)
55 goto fail;
56
57 switch (nbr->state) {
58 case NBR_STA_DOWN:
59 case NBR_STA_ATTEMPT:
60 case NBR_STA_INIT:
61 case NBR_STA_2_WAY:
62 case NBR_STA_SNAP:
63 log_debug("send_db_description: neighbor ID %s (%s): "
64 "cannot send packet in state %s", inet_ntoa(nbr->id),
65 nbr->iface->name, nbr_state_name(nbr->state));
66 goto fail;
67 case NBR_STA_XSTRT:
68 bits |= OSPF_DBD_MS | OSPF_DBD_M | OSPF_DBD_I;
69 nbr->dd_more = 1;
70 break;
71 case NBR_STA_XCHNG:
72 if (nbr->dd_master)
73 bits |= OSPF_DBD_MS;
74 else
75 bits &= ~OSPF_DBD_MS;
76
77 if (TAILQ_EMPTY(&nbr->db_sum_list)) {
78 bits &= ~OSPF_DBD_M;
79 nbr->dd_more = 0;
80 } else {
81 bits |= OSPF_DBD_M;
82 nbr->dd_more = 1;
83 }
84
85 bits &= ~OSPF_DBD_I;
86
87 /* build LSA list */
88 for (le = TAILQ_FIRST(&nbr->db_sum_list); le != NULL &&
89 ibuf_left(buf) >= sizeof(struct lsa_hdr); le = nle) {
90 nbr->dd_end = nle = TAILQ_NEXT(le, entry);
91 if (ibuf_add(buf, le->le_lsa, sizeof(struct lsa_hdr)))
92 goto fail;
93 }
94 break;
95 case NBR_STA_LOAD:
96 case NBR_STA_FULL:
97 if (nbr->dd_master)
98 bits |= OSPF_DBD_MS;
99 else
100 bits &= ~OSPF_DBD_MS;
101 bits &= ~OSPF_DBD_M;
102 bits &= ~OSPF_DBD_I;
103
104 nbr->dd_more = 0;
105 break;
106 default:
107 fatalx("send_db_description: unknown neighbor state");
108 }
109
110 bzero(&dd_hdr, sizeof(dd_hdr));
111
112 switch (nbr->iface->type) {
113 case IF_TYPE_POINTOPOINT:
114 inet_pton(AF_INET6, AllSPFRouters, &dst);
115 dd_hdr.iface_mtu = htons(nbr->iface->mtu);
116 break;
117 case IF_TYPE_BROADCAST:
118 dst = nbr->addr;
119 dd_hdr.iface_mtu = htons(nbr->iface->mtu);
120 break;
121 case IF_TYPE_NBMA:
122 case IF_TYPE_POINTOMULTIPOINT:
123 /* XXX not supported */
124 break;
125 case IF_TYPE_VIRTUALLINK:
126 dst = nbr->iface->dst;
127 dd_hdr.iface_mtu = 0;
128 break;
129 default:
130 fatalx("send_db_description: unknown interface type");
131 }
132
133 dd_hdr.opts = htonl(area_ospf_options(nbr->iface->area));
134 dd_hdr.bits = bits;
135 dd_hdr.dd_seq_num = htonl(nbr->dd_seq_num);
136
137 if (ibuf_set(buf, sizeof(struct ospf_hdr), &dd_hdr,
138 sizeof(dd_hdr)) == -1)
139 goto fail;
140
141 /* calculate checksum */
142 if (upd_ospf_hdr(buf, nbr->iface))
143 goto fail;
144
145 /* transmit packet */
146 if (send_packet(nbr->iface, buf, &dst) == -1)
147 goto fail;
148
149 ibuf_free(buf);
150 return (0);
151 fail:
152 log_warn("send_db_description");
153 ibuf_free(buf);
154 return (-1);
155 }
156
157 void
recv_db_description(struct nbr * nbr,char * buf,u_int16_t len)158 recv_db_description(struct nbr *nbr, char *buf, u_int16_t len)
159 {
160 struct db_dscrp_hdr dd_hdr;
161 int dupe = 0;
162
163 if (len < sizeof(dd_hdr)) {
164 log_warnx("recv_db_description: neighbor ID %s (%s): "
165 "bad packet size", inet_ntoa(nbr->id), nbr->iface->name);
166 return;
167 }
168 memcpy(&dd_hdr, buf, sizeof(dd_hdr));
169 buf += sizeof(dd_hdr);
170 len -= sizeof(dd_hdr);
171
172 /* db description packet sanity checks */
173 if (ntohs(dd_hdr.iface_mtu) > nbr->iface->mtu) {
174 log_warnx("recv_db_description: neighbor ID %s (%s): "
175 "invalid MTU %d expected %d", inet_ntoa(nbr->id),
176 nbr->iface->name, ntohs(dd_hdr.iface_mtu),
177 nbr->iface->mtu);
178 return;
179 }
180
181 if (nbr->last_rx_options == dd_hdr.opts &&
182 nbr->last_rx_bits == dd_hdr.bits &&
183 ntohl(dd_hdr.dd_seq_num) == nbr->dd_seq_num - nbr->dd_master ?
184 1 : 0) {
185 log_debug("recv_db_description: dupe from "
186 "neighbor ID %s (%s)", inet_ntoa(nbr->id),
187 nbr->iface->name);
188 dupe = 1;
189 }
190
191 switch (nbr->state) {
192 case NBR_STA_DOWN:
193 case NBR_STA_ATTEMPT:
194 case NBR_STA_2_WAY:
195 case NBR_STA_SNAP:
196 log_debug("recv_db_description: neighbor ID %s (%s): "
197 "packet ignored in state %s", inet_ntoa(nbr->id),
198 nbr->iface->name, nbr_state_name(nbr->state));
199 return;
200 case NBR_STA_INIT:
201 /* evaluate dr and bdr after issuing a 2-Way event */
202 nbr_fsm(nbr, NBR_EVT_2_WAY_RCVD);
203 if_fsm(nbr->iface, IF_EVT_NBR_CHNG);
204 if (nbr->state != NBR_STA_XSTRT)
205 return;
206 /* FALLTHROUGH */
207 case NBR_STA_XSTRT:
208 if (dupe)
209 return;
210 /*
211 * check bits: either I,M,MS or only M
212 */
213 if (dd_hdr.bits == (OSPF_DBD_I | OSPF_DBD_M | OSPF_DBD_MS)) {
214 /* if nbr Router ID is larger than own -> slave */
215 if ((ntohl(nbr->id.s_addr)) >
216 ntohl(ospfe_router_id())) {
217 /* slave */
218 nbr->dd_master = 0;
219 nbr->dd_seq_num = ntohl(dd_hdr.dd_seq_num);
220
221 /* event negotiation done */
222 nbr_fsm(nbr, NBR_EVT_NEG_DONE);
223 }
224 } else if (!(dd_hdr.bits & (OSPF_DBD_I | OSPF_DBD_MS))) {
225 /* M only case: we are master */
226 if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num) {
227 log_warnx("recv_db_description: "
228 "neighbor ID %s (%s): "
229 "invalid seq num, mine %x his %x",
230 inet_ntoa(nbr->id), nbr->iface->name,
231 nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
232 return;
233 }
234 nbr->dd_seq_num++;
235
236 /* event negotiation done */
237 nbr_fsm(nbr, NBR_EVT_NEG_DONE);
238
239 /* this packet may already have data so pass it on */
240 if (len > 0) {
241 nbr->dd_pending++;
242 ospfe_imsg_compose_rde(IMSG_DD, nbr->peerid,
243 0, buf, len);
244 }
245 } else {
246 /* ignore packet */
247 log_debug("recv_db_description: neighbor ID %s (%s): "
248 "packet ignored in state %s (bad flags)",
249 inet_ntoa(nbr->id), nbr->iface->name,
250 nbr_state_name(nbr->state));
251 }
252 break;
253 case NBR_STA_XCHNG:
254 case NBR_STA_LOAD:
255 case NBR_STA_FULL:
256 if (dd_hdr.bits & OSPF_DBD_I ||
257 !(dd_hdr.bits & OSPF_DBD_MS) == !nbr->dd_master) {
258 log_warnx("recv_db_description: neighbor ID %s (%s): "
259 "seq num mismatch, bad flags", inet_ntoa(nbr->id),
260 nbr->iface->name);
261 nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
262 return;
263 }
264
265 if (nbr->last_rx_options != dd_hdr.opts) {
266 log_warnx("recv_db_description: neighbor ID %s (%s): "
267 "seq num mismatch, bad options",
268 inet_ntoa(nbr->id), nbr->iface->name);
269 nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
270 return;
271 }
272
273 if (dupe) {
274 if (!nbr->dd_master)
275 /* retransmit */
276 start_db_tx_timer(nbr);
277 return;
278 }
279
280 if (nbr->state != NBR_STA_XCHNG) {
281 log_warnx("recv_db_description: neighbor ID %s (%s): "
282 "invalid seq num, mine %x his %x",
283 inet_ntoa(nbr->id), nbr->iface->name,
284 nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
285 nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
286 return;
287 }
288
289 /* sanity check dd seq number */
290 if (nbr->dd_master) {
291 /* master */
292 if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num) {
293 log_warnx("recv_db_description: "
294 "neighbor ID %s (%s): "
295 "invalid seq num, mine %x his %x, master",
296 inet_ntoa(nbr->id), nbr->iface->name,
297 nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
298 nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
299 return;
300 }
301 nbr->dd_seq_num++;
302 } else {
303 /* slave */
304 if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num + 1) {
305 log_warnx("recv_db_description: "
306 "neighbor ID %s (%s): "
307 "invalid seq num, mine %x his %x, slave",
308 inet_ntoa(nbr->id), nbr->iface->name,
309 nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
310 nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
311 return;
312 }
313 nbr->dd_seq_num = ntohl(dd_hdr.dd_seq_num);
314 }
315
316 /* forward to RDE and let it decide which LSAs to request */
317 if (len > 0) {
318 nbr->dd_pending++;
319 ospfe_imsg_compose_rde(IMSG_DD, nbr->peerid, 0,
320 buf, len);
321 }
322
323 /* next packet */
324 db_sum_list_next(nbr);
325 start_db_tx_timer(nbr);
326
327 if (!(dd_hdr.bits & OSPF_DBD_M) &&
328 TAILQ_EMPTY(&nbr->db_sum_list))
329 if (!nbr->dd_master || !nbr->dd_more)
330 nbr_fsm(nbr, NBR_EVT_XCHNG_DONE);
331 break;
332 default:
333 fatalx("recv_db_description: unknown neighbor state");
334 }
335
336 nbr->last_rx_options = dd_hdr.opts;
337 nbr->last_rx_bits = dd_hdr.bits;
338 }
339
340 void
db_sum_list_add(struct nbr * nbr,struct lsa_hdr * lsa)341 db_sum_list_add(struct nbr *nbr, struct lsa_hdr *lsa)
342 {
343 struct lsa_entry *le;
344
345 if ((le = calloc(1, sizeof(*le))) == NULL)
346 fatal("db_sum_list_add");
347
348 TAILQ_INSERT_TAIL(&nbr->db_sum_list, le, entry);
349 le->le_lsa = lsa;
350 }
351
352 void
db_sum_list_next(struct nbr * nbr)353 db_sum_list_next(struct nbr *nbr)
354 {
355 struct lsa_entry *le;
356
357 while ((le = TAILQ_FIRST(&nbr->db_sum_list)) != nbr->dd_end) {
358 TAILQ_REMOVE(&nbr->db_sum_list, le, entry);
359 free(le->le_lsa);
360 free(le);
361 }
362 }
363
364 void
db_sum_list_clr(struct nbr * nbr)365 db_sum_list_clr(struct nbr *nbr)
366 {
367 nbr->dd_end = NULL;
368 db_sum_list_next(nbr);
369 }
370
371 /* timers */
372 void
db_tx_timer(int fd,short event,void * arg)373 db_tx_timer(int fd, short event, void *arg)
374 {
375 struct nbr *nbr = arg;
376 struct timeval tv;
377
378 switch (nbr->state) {
379 case NBR_STA_DOWN:
380 case NBR_STA_ATTEMPT:
381 case NBR_STA_INIT:
382 case NBR_STA_2_WAY:
383 case NBR_STA_SNAP:
384 return ;
385 case NBR_STA_XSTRT:
386 case NBR_STA_XCHNG:
387 case NBR_STA_LOAD:
388 case NBR_STA_FULL:
389 send_db_description(nbr);
390 break;
391 default:
392 log_debug("db_tx_timer: neighbor ID %s (%s): "
393 "unknown neighbor state",
394 inet_ntoa(nbr->id), nbr->iface->name);
395 break;
396 }
397
398 /* reschedule db_tx_timer but only in master mode */
399 if (nbr->dd_master) {
400 timerclear(&tv);
401 tv.tv_sec = nbr->iface->rxmt_interval;
402 if (evtimer_add(&nbr->db_tx_timer, &tv) == -1)
403 fatal("db_tx_timer");
404 }
405 }
406
407 void
start_db_tx_timer(struct nbr * nbr)408 start_db_tx_timer(struct nbr *nbr)
409 {
410 struct timeval tv;
411
412 if (nbr == nbr->iface->self)
413 return;
414
415 timerclear(&tv);
416 if (evtimer_add(&nbr->db_tx_timer, &tv) == -1)
417 fatal("start_db_tx_timer");
418 }
419
420 void
stop_db_tx_timer(struct nbr * nbr)421 stop_db_tx_timer(struct nbr *nbr)
422 {
423 if (nbr == nbr->iface->self)
424 return;
425
426 if (evtimer_del(&nbr->db_tx_timer) == -1)
427 fatal("stop_db_tx_timer");
428 }
429