]> git.ipfire.org Git - thirdparty/bird.git/blame - proto/ospf/dbdes.c
OSPF: Fix handling of NSSA option flags
[thirdparty/bird.git] / proto / ospf / dbdes.c
CommitLineData
4364b47e
OF
1/*
2 * BIRD -- OSPF
3 *
f158bb71 4 * (c) 1999--2004 Ondrej Filip <feela@network.cz>
70945cb6
OZ
5 * (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
6 * (c) 2009--2014 CZ.NIC z.s.p.o.
4364b47e
OF
7 *
8 * Can be freely distributed and used under the terms of the GNU GPL.
9 */
10
11#include "ospf.h"
12
c3226991 13
70945cb6 14struct ospf_dbdes2_packet
c3226991 15{
70945cb6 16 struct ospf_packet hdr;
4727d1db 17 union ospf_auth2 auth;
70945cb6 18
c3226991
OZ
19 u16 iface_mtu;
20 u8 options;
70945cb6 21 u8 imms; /* I, M, MS bits */
c3226991 22 u32 ddseq;
c3226991 23
70945cb6
OZ
24 struct ospf_lsa_header lsas[];
25};
c3226991 26
70945cb6 27struct ospf_dbdes3_packet
c3226991 28{
70945cb6
OZ
29 struct ospf_packet hdr;
30
c3226991
OZ
31 u32 options;
32 u16 iface_mtu;
33 u8 padding;
70945cb6 34 u8 imms; /* I, M, MS bits */
c3226991 35 u32 ddseq;
70945cb6
OZ
36
37 struct ospf_lsa_header lsas[];
c3226991
OZ
38};
39
c3226991 40
4727d1db
OZ
41uint
42ospf_dbdes3_options(struct ospf_packet *pkt)
43{
44 struct ospf_dbdes3_packet *ps = (void *) pkt;
45 return ntohl(ps->options);
46}
47
70945cb6
OZ
48static inline uint
49ospf_dbdes_hdrlen(struct ospf_proto *p)
50{
51 return ospf_is_v2(p) ?
52 sizeof(struct ospf_dbdes2_packet) : sizeof(struct ospf_dbdes3_packet);
53}
54
70945cb6
OZ
55static void
56ospf_dbdes_body(struct ospf_proto *p, struct ospf_packet *pkt,
57 struct ospf_lsa_header **body, uint *count)
58{
59 uint plen = ntohs(pkt->length);
60 uint hlen = ospf_dbdes_hdrlen(p);
61
62 *body = ((void *) pkt) + hlen;
63 *count = (plen - hlen) / sizeof(struct ospf_lsa_header);
64}
742029eb 65
70945cb6
OZ
66static void
67ospf_dump_dbdes(struct ospf_proto *p, struct ospf_packet *pkt)
8298d780 68{
70945cb6
OZ
69 struct ospf_lsa_header *lsas;
70 uint i, lsa_count;
71 u32 pkt_ddseq;
72 u16 pkt_iface_mtu;
73 u8 pkt_imms;
8298d780 74
70945cb6
OZ
75 ASSERT(pkt->type == DBDES_P);
76 ospf_dump_common(p, pkt);
8298d780 77
70945cb6
OZ
78 if (ospf_is_v2(p))
79 {
80 struct ospf_dbdes2_packet *ps = (void *) pkt;
81 pkt_iface_mtu = ntohs(ps->iface_mtu);
82 pkt_imms = ps->imms;
83 pkt_ddseq = ntohl(ps->ddseq);
84 }
85 else /* OSPFv3 */
86 {
87 struct ospf_dbdes3_packet *ps = (void *) pkt;
88 pkt_iface_mtu = ntohs(ps->iface_mtu);
89 pkt_imms = ps->imms;
90 pkt_ddseq = ntohl(ps->ddseq);
91 }
8298d780 92
70945cb6
OZ
93 log(L_TRACE "%s: mtu %u", p->p.name, pkt_iface_mtu);
94 log(L_TRACE "%s: imms %s%s%s", p->p.name,
95 (pkt_imms & DBDES_I) ? "I " : "",
96 (pkt_imms & DBDES_M) ? "M " : "",
97 (pkt_imms & DBDES_MS) ? "MS" : "");
98 log(L_TRACE "%s: ddseq %u", p->p.name, pkt_ddseq);
8298d780 99
70945cb6
OZ
100 ospf_dbdes_body(p, pkt, &lsas, &lsa_count);
101 for (i = 0; i < lsa_count; i++)
102 ospf_dump_lsahdr(p, lsas + i);
8298d780
OZ
103}
104
105
70945cb6 106static void
f8fefde3 107ospf_prepare_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
70945cb6
OZ
108{
109 struct ospf_iface *ifa = n->ifa;
110 struct ospf_packet *pkt;
111 uint length;
112
113 u16 iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : ifa->iface->mtu;
114
f8fefde3 115 /* Update DBDES buffer */
70945cb6
OZ
116 if (n->ldd_bsize != ifa->tx_length)
117 {
118 mb_free(n->ldd_buffer);
119 n->ldd_buffer = mb_allocz(n->pool, ifa->tx_length);
120 n->ldd_bsize = ifa->tx_length;
121 }
122
123 pkt = n->ldd_buffer;
124 ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
125
126 if (ospf_is_v2(p))
127 {
128 struct ospf_dbdes2_packet *ps = (void *) pkt;
129 ps->iface_mtu = htons(iface_mtu);
1aec7112 130 ps->options = ifa->oa->options & DBDES2_OPT_MASK;
70945cb6
OZ
131 ps->imms = 0; /* Will be set later */
132 ps->ddseq = htonl(n->dds);
133 length = sizeof(struct ospf_dbdes2_packet);
134 }
135 else /* OSPFv3 */
136 {
137 struct ospf_dbdes3_packet *ps = (void *) pkt;
1aec7112
OZ
138 u32 options = ifa->oa->options | (ifa->autype == OSPF_AUTH_CRYPT ? OPT_AT : 0);
139 ps->options = htonl(options & DBDES3_OPT_MASK);
70945cb6
OZ
140 ps->iface_mtu = htons(iface_mtu);
141 ps->padding = 0;
142 ps->imms = 0; /* Will be set later */
143 ps->ddseq = htonl(n->dds);
144 length = sizeof(struct ospf_dbdes3_packet);
145 }
146
f8fefde3
OZ
147 /* Prepare DBDES body */
148 if (!(n->myimms & DBDES_I) && (n->myimms & DBDES_M))
70945cb6
OZ
149 {
150 struct ospf_lsa_header *lsas;
151 struct top_hash_entry *en;
152 uint i = 0, lsa_max;
153
154 ospf_dbdes_body(p, pkt, &lsas, &lsa_max);
155 en = (void *) s_get(&(n->dbsi));
156
157 while (i < lsa_max)
158 {
159 if (!SNODE_VALID(en))
160 {
161 n->myimms &= ~DBDES_M; /* Unset More bit */
162 break;
163 }
164
165 if ((en->lsa.age < LSA_MAXAGE) &&
5a50a989
OZ
166 lsa_flooding_allowed(en->lsa_type, en->domain, ifa) &&
167 lsa_is_acceptable(en->lsa_type, n, p))
70945cb6
OZ
168 {
169 lsa_hton_hdr(&(en->lsa), lsas + i);
170 i++;
171 }
172
173 en = SNODE_NEXT(en);
174 }
175
176 s_put(&(n->dbsi), SNODE en);
177
178 length += i * sizeof(struct ospf_lsa_header);
179 }
180
181 if (ospf_is_v2(p))
182 ((struct ospf_dbdes2_packet *) pkt)->imms = n->myimms;
183 else
184 ((struct ospf_dbdes3_packet *) pkt)->imms = n->myimms;
185
186 pkt->length = htons(length);
187}
188
189static void
190ospf_do_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
191{
192 struct ospf_iface *ifa = n->ifa;
193
194 OSPF_PACKET(ospf_dump_dbdes, n->ldd_buffer,
f8fefde3 195 "DBDES packet sent to nbr %R on %s", n->rid, ifa->ifname);
70945cb6
OZ
196 sk_set_tbuf(ifa->sk, n->ldd_buffer);
197 ospf_send_to(ifa, n->ip);
198 sk_set_tbuf(ifa->sk, NULL);
199}
200
eee9cefd 201/**
70945cb6 202 * ospf_send_dbdes - transmit database description packet
8e433d6a 203 * @p: OSPF protocol instance
eee9cefd
OF
204 * @n: neighbor
205 *
c3226991 206 * Sending of a database description packet is described in 10.8 of RFC 2328.
baa5dd6c
OF
207 * Reception of each packet is acknowledged in the sequence number of another.
208 * When I send a packet to a neighbor I keep a copy in a buffer. If the neighbor
209 * does not reply, I don't create a new packet but just send the content
210 * of the buffer.
eee9cefd 211 */
4364b47e 212void
f8fefde3 213ospf_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
4364b47e 214{
70945cb6 215 /* RFC 2328 10.8 */
4364b47e 216
f8fefde3
OZ
217 ASSERT((n->state == NEIGHBOR_EXSTART) || (n->state == NEIGHBOR_EXCHANGE));
218
1a2ad348 219 if (!n->ifa->oa->rt && !p->gr_recovery)
70945cb6 220 return;
054a3524 221
f8fefde3
OZ
222 ospf_prepare_dbdes(p, n);
223 ospf_do_send_dbdes(p, n);
f8fefde3 224}
12bed559 225
f8fefde3
OZ
226void
227ospf_rxmt_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
228{
229 ASSERT(n->state > NEIGHBOR_EXSTART);
e7ef86a5 230
f8fefde3
OZ
231 if (!n->ldd_buffer)
232 {
233 log(L_WARN "%s: No DBDES packet for retransmit", p->p.name);
234 ospf_neigh_sm(n, INM_SEQMIS);
235 return;
70945cb6 236 }
04c6319a 237
f8fefde3
OZ
238 /* Send last packet */
239 ospf_do_send_dbdes(p, n);
240}
48e5f32d 241
16605f2f
OZ
242void
243ospf_reset_ldd(struct ospf_proto *p UNUSED, struct ospf_neighbor *n)
244{
245 mb_free(n->ldd_buffer);
246 n->ldd_buffer = NULL;
247 n->ldd_bsize = 0;
248}
249
70945cb6
OZ
250static int
251ospf_process_dbdes(struct ospf_proto *p, struct ospf_packet *pkt, struct ospf_neighbor *n)
252{
253 struct ospf_iface *ifa = n->ifa;
f8fefde3
OZ
254 struct ospf_lsa_header *lsas, lsa;
255 struct top_hash_entry *en, *req;
256 const char *err_dsc = NULL;
257 u32 lsa_type, lsa_domain;
70945cb6
OZ
258 uint i, lsa_count;
259
260 ospf_dbdes_body(p, pkt, &lsas, &lsa_count);
261
262 for (i = 0; i < lsa_count; i++)
263 {
70945cb6
OZ
264 lsa_ntoh_hdr(lsas + i, &lsa);
265 lsa_get_type_domain(&lsa, ifa, &lsa_type, &lsa_domain);
b1f7229a 266
70945cb6 267 /* RFC 2328 10.6 and RFC 5340 4.2.2 */
b1f7229a 268
70945cb6 269 if (!lsa_type)
f8fefde3 270 DROP1("LSA of unknown type");
4364b47e 271
70945cb6 272 if (!oa_is_ext(ifa->oa) && (LSA_SCOPE(lsa_type) == LSA_SCOPE_AS))
f8fefde3 273 DROP1("LSA with AS scope in stub area");
4364b47e 274
70945cb6
OZ
275 /* Errata 3746 to RFC 2328 - rt-summary-LSAs forbidden in stub areas */
276 if (!oa_is_ext(ifa->oa) && (lsa_type == LSA_T_SUM_RT))
f8fefde3 277 DROP1("rt-summary-LSA in stub area");
910e557b 278
70945cb6
OZ
279 /* Not explicitly mentioned in RFC 5340 4.2.2 but makes sense */
280 if (LSA_SCOPE(lsa_type) == LSA_SCOPE_RES)
f8fefde3 281 DROP1("LSA with invalid scope");
910e557b 282
1a2ad348
OZ
283 /* RFC 3623 2.2 (2) special case - check for my router-LSA (GR recovery) */
284 if ((lsa_type == LSA_T_RT) && (lsa.rt == p->router_id))
285 n->got_my_rt_lsa = 1;
286
70945cb6
OZ
287 en = ospf_hash_find(p->gr, lsa_domain, lsa.id, lsa.rt, lsa_type);
288 if (!en || (lsa_comp(&lsa, &(en->lsa)) == CMP_NEWER))
289 {
6f8bbaa1 290 /* This should be splitted to ospf_lsa_lsrq_up() */
70945cb6 291 req = ospf_hash_get(n->lsrqh, lsa_domain, lsa.id, lsa.rt, lsa_type);
6d2b3211 292
70945cb6
OZ
293 if (!SNODE_VALID(req))
294 s_add_tail(&n->lsrql, SNODE req);
6d2b3211 295
6f8bbaa1
OZ
296 if (!SNODE_VALID(n->lsrqi))
297 n->lsrqi = req;
298
70945cb6 299 req->lsa = lsa;
a7a7372a 300 req->lsa_body = LSA_BODY_DUMMY;
6f8bbaa1 301
a6f79ca5
OZ
302 if (!tm_active(n->lsrq_timer))
303 tm_start(n->lsrq_timer, 0);
95eb1dba 304 }
6d2b3211 305 }
70945cb6
OZ
306
307 return 0;
308
f8fefde3
OZ
309drop:
310 LOG_LSA1("Bad LSA (Type: %04x, Id: %R, Rt: %R) in DBDES", lsa_type, lsa.id, lsa.rt);
311 LOG_LSA2(" received from nbr %R on %s - %s", n->rid, ifa->ifname, err_dsc);
312
70945cb6
OZ
313 ospf_neigh_sm(n, INM_SEQMIS);
314 return -1;
4364b47e
OF
315}
316
317void
70945cb6 318ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa,
c3226991 319 struct ospf_neighbor *n)
4364b47e 320{
70945cb6 321 struct ospf_proto *p = ifa->oa->po;
f8fefde3 322 const char *err_dsc = NULL;
70945cb6
OZ
323 u32 rcv_ddseq, rcv_options;
324 u16 rcv_iface_mtu;
325 u8 rcv_imms;
6f8bbaa1 326 uint plen, err_val = 0;
4364b47e 327
70945cb6
OZ
328 /* RFC 2328 10.6 */
329
330 plen = ntohs(pkt->length);
331 if (plen < ospf_dbdes_hdrlen(p))
6f8bbaa1
OZ
332 {
333 LOG_PKT("Bad DBDES packet from nbr %R on %s - %s (%u)", n->rid, ifa->ifname, "too short", plen);
334 return;
335 }
a6bc04d5 336
f8fefde3 337 OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet received from nbr %R on %s", n->rid, ifa->ifname);
b1f7229a 338
4bb9ce56 339 ospf_neigh_sm(n, INM_HELLOREC);
353f3261 340
70945cb6
OZ
341 if (ospf_is_v2(p))
342 {
343 struct ospf_dbdes2_packet *ps = (void *) pkt;
344 rcv_iface_mtu = ntohs(ps->iface_mtu);
345 rcv_options = ps->options;
346 rcv_imms = ps->imms;
347 rcv_ddseq = ntohl(ps->ddseq);
348 }
349 else /* OSPFv3 */
350 {
351 struct ospf_dbdes3_packet *ps = (void *) pkt;
352 rcv_options = ntohl(ps->options);
353 rcv_iface_mtu = ntohs(ps->iface_mtu);
354 rcv_imms = ps->imms;
355 rcv_ddseq = ntohl(ps->ddseq);
356 }
742029eb 357
267da813
OZ
358 /* Reject packets with non-matching MTU */
359 if ((ifa->type != OSPF_IT_VLINK) &&
360 (rcv_iface_mtu != ifa->iface->mtu) &&
361 (rcv_iface_mtu != 0) && (ifa->iface->mtu != 0))
362 {
363 LOG_PKT("MTU mismatch with nbr %R on %s (remote %d, local %d)",
364 n->rid, ifa->ifname, rcv_iface_mtu, ifa->iface->mtu);
365 return;
366 }
367
12bed559 368 switch (n->state)
4364b47e 369 {
12bed559
OF
370 case NEIGHBOR_DOWN:
371 case NEIGHBOR_ATTEMPT:
372 case NEIGHBOR_2WAY:
f8fefde3 373 OSPF_TRACE(D_PACKETS, "DBDES packet ignored - lesser state than ExStart");
12bed559 374 return;
70945cb6 375
12bed559
OF
376 case NEIGHBOR_INIT:
377 ospf_neigh_sm(n, INM_2WAYREC);
378 if (n->state != NEIGHBOR_EXSTART)
379 return;
d4cebc6b 380 /* fallthrough */
9f1500f5 381
70945cb6 382 case NEIGHBOR_EXSTART:
d3f4f92b 383 if (((rcv_imms & DBDES_IMMS) == DBDES_IMMS) &&
70945cb6
OZ
384 (n->rid > p->router_id) &&
385 (plen == ospf_dbdes_hdrlen(p)))
12bed559
OF
386 {
387 /* I'm slave! */
70945cb6
OZ
388 n->dds = rcv_ddseq;
389 n->ddr = rcv_ddseq;
390 n->options = rcv_options;
391 n->myimms &= ~DBDES_MS;
392 n->imms = rcv_imms;
a6f79ca5 393 tm_stop(n->dbdes_timer);
12bed559 394 ospf_neigh_sm(n, INM_NEGDONE);
f8fefde3 395 ospf_send_dbdes(p, n);
4364b47e 396 break;
12bed559 397 }
b1f7229a 398
70945cb6
OZ
399 if (!(rcv_imms & DBDES_I) &&
400 !(rcv_imms & DBDES_MS) &&
742029eb 401 (n->rid < p->router_id) &&
70945cb6 402 (n->dds == rcv_ddseq))
12bed559 403 {
b1f7229a 404 /* I'm master! */
70945cb6
OZ
405 n->options = rcv_options;
406 n->ddr = rcv_ddseq - 1; /* It will be set corectly a few lines down */
407 n->imms = rcv_imms;
b1f7229a 408 ospf_neigh_sm(n, INM_NEGDONE);
6f8bbaa1 409 /* Continue to the NEIGHBOR_EXCHANGE case */
12bed559 410 }
b1f7229a
OF
411 else
412 {
70945cb6 413 DBG("%s: Nothing happend to %I (imms=%d)\n", p->name, n->ip, rcv_imms);
12bed559 414 break;
b1f7229a 415 }
70945cb6 416
12bed559 417 case NEIGHBOR_EXCHANGE:
70945cb6
OZ
418 if ((rcv_imms == n->imms) &&
419 (rcv_options == n->options) &&
420 (rcv_ddseq == n->ddr))
f8fefde3 421 goto duplicate;
910e557b 422
f8fefde3
OZ
423 if ((rcv_imms & DBDES_MS) != (n->imms & DBDES_MS))
424 DROP("MS-bit mismatch", rcv_imms);
12bed559 425
f8fefde3
OZ
426 if (rcv_imms & DBDES_I)
427 DROP("I-bit mismatch", rcv_imms);
428
429 if (rcv_options != n->options)
430 DROP("options mismatch", rcv_options);
4364b47e 431
70945cb6
OZ
432 n->ddr = rcv_ddseq;
433 n->imms = rcv_imms;
434
435 if (n->myimms & DBDES_MS)
12bed559 436 {
f8fefde3
OZ
437 /* MASTER */
438
439 if (rcv_ddseq != n->dds)
440 DROP("DD sequence number mismatch", rcv_ddseq);
70945cb6 441
12bed559 442 n->dds++;
70945cb6
OZ
443
444 if (ospf_process_dbdes(p, pkt, n) < 0)
445 return;
446
447 if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M))
6f8bbaa1 448 {
a6f79ca5 449 tm_stop(n->dbdes_timer);
16605f2f 450 ospf_reset_ldd(p, n);
12bed559 451 ospf_neigh_sm(n, INM_EXDONE);
6f8bbaa1
OZ
452 break;
453 }
454
455 ospf_send_dbdes(p, n);
a6f79ca5 456 tm_start(n->dbdes_timer, n->ifa->rxmtint S);
12bed559
OF
457 }
458 else
459 {
f8fefde3
OZ
460 /* SLAVE */
461
462 if (rcv_ddseq != (n->dds + 1))
463 DROP("DD sequence number mismatch", rcv_ddseq);
12bed559 464
70945cb6
OZ
465 n->ddr = rcv_ddseq;
466 n->dds = rcv_ddseq;
467
468 if (ospf_process_dbdes(p, pkt, n) < 0)
469 return;
470
f8fefde3 471 ospf_send_dbdes(p, n);
6f8bbaa1
OZ
472
473 if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M))
16605f2f
OZ
474 {
475 /* Use dbdes timer to postpone freeing of Last DBDES packet buffer */
476 tm_start(n->dbdes_timer, n->ifa->deadint S);
6f8bbaa1 477 ospf_neigh_sm(n, INM_EXDONE);
16605f2f 478 }
70945cb6 479 }
12bed559 480 break;
70945cb6 481
12bed559
OF
482 case NEIGHBOR_LOADING:
483 case NEIGHBOR_FULL:
70945cb6
OZ
484 if ((rcv_imms == n->imms) &&
485 (rcv_options == n->options) &&
486 (rcv_ddseq == n->ddr))
f8fefde3
OZ
487 goto duplicate;
488
f8fefde3 489 DROP("too late for DD exchange", n->state);
70945cb6 490
189dab54 491 default:
f8fefde3 492 bug("Undefined interface state");
12bed559 493 }
f8fefde3
OZ
494 return;
495
496duplicate:
497 OSPF_TRACE(D_PACKETS, "DBDES packet is duplicate");
498
499 /* Slave should retransmit DBDES packet */
500 if (!(n->myimms & DBDES_MS))
501 ospf_rxmt_dbdes(p, n);
502 return;
503
504drop:
505 LOG_PKT("Bad DBDES packet from nbr %R on %s - %s (%u)",
506 n->rid, ifa->ifname, err_dsc, err_val);
507
6f8bbaa1 508 ospf_neigh_sm(n, INM_SEQMIS);
f8fefde3 509 return;
12bed559 510}