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