]> git.ipfire.org Git - thirdparty/bird.git/blame - proto/ospf/lsalib.c
Merge branch 'master' into mq-filter-stack
[thirdparty/bird.git] / proto / ospf / lsalib.c
CommitLineData
f45fd316
OF
1/*
2 * BIRD -- OSPF
3 *
6f3203fa 4 * (c) 1999--2004 Ondrej Filip <feela@network.cz>
77edab64
OZ
5 * (c) 2009--2015 Ondrej Zajicek <santiago@crfreenet.org>
6 * (c) 2009--2015 CZ.NIC z.s.p.o.
f45fd316
OF
7 *
8 * Can be freely distributed and used under the terms of the GNU GPL.
9 */
10
11#include "ospf.h"
12
77edab64 13#include "lib/fletcher16.h"
c45f48fb 14
1a2ad348
OZ
15#define HDRLEN sizeof(struct ospf_lsa_header)
16
17
4e5fb4b6 18#ifndef CPU_BIG_ENDIAN
f45fd316 19void
70945cb6 20lsa_hton_hdr(struct ospf_lsa_header *h, struct ospf_lsa_header *n)
f45fd316 21{
2e10a170 22 n->age = htons(h->age);
70945cb6 23 n->type_raw = htons(h->type_raw);
2e10a170
OF
24 n->id = htonl(h->id);
25 n->rt = htonl(h->rt);
26 n->sn = htonl(h->sn);
27 n->checksum = htons(h->checksum);
28 n->length = htons(h->length);
c15e5690 29}
f45fd316
OF
30
31void
70945cb6 32lsa_ntoh_hdr(struct ospf_lsa_header *n, struct ospf_lsa_header *h)
f45fd316 33{
2e10a170 34 h->age = ntohs(n->age);
70945cb6 35 h->type_raw = ntohs(n->type_raw);
2e10a170
OF
36 h->id = ntohl(n->id);
37 h->rt = ntohl(n->rt);
38 h->sn = ntohl(n->sn);
39 h->checksum = ntohs(n->checksum);
40 h->length = ntohs(n->length);
c15e5690 41}
f45fd316
OF
42
43void
70945cb6 44lsa_hton_body(void *h, void *n, u16 len)
f45fd316 45{
c15e5690
OZ
46 u32 *hid = h;
47 u32 *nid = n;
70945cb6 48 uint i;
f45fd316 49
c15e5690
OZ
50 for (i = 0; i < (len / sizeof(u32)); i++)
51 nid[i] = htonl(hid[i]);
52}
f45fd316
OF
53
54void
70945cb6 55lsa_ntoh_body(void *n, void *h, u16 len)
f45fd316 56{
c15e5690
OZ
57 u32 *nid = n;
58 u32 *hid = h;
70945cb6 59 uint i;
f45fd316 60
c15e5690
OZ
61 for (i = 0; i < (len / sizeof(u32)); i++)
62 hid[i] = ntohl(nid[i]);
63}
4e5fb4b6 64#endif /* little endian */
f45fd316 65
70945cb6 66
70945cb6
OZ
67int
68lsa_flooding_allowed(u32 type, u32 domain, struct ospf_iface *ifa)
742029eb 69{
70945cb6
OZ
70 /* Handle inactive vlinks */
71 if (ifa->state == OSPF_IS_DOWN)
72 return 0;
742029eb 73
70945cb6
OZ
74 /* 4.5.2 (Case 2) */
75 switch (LSA_SCOPE(type))
76 {
77 case LSA_SCOPE_LINK:
78 return ifa->iface_id == domain;
79
80 case LSA_SCOPE_AREA:
81 return ifa->oa->areaid == domain;
82
83 case LSA_SCOPE_AS:
84 if (ifa->type == OSPF_IT_VLINK)
85 return 0;
86 if (!oa_is_ext(ifa->oa))
87 return 0;
88 return 1;
89
90 default:
91 log(L_ERR "OSPF: LSA with invalid scope");
92 return 0;
93 }
94}
95
5a50a989
OZ
96int
97lsa_is_acceptable(u32 type, struct ospf_neighbor *n, struct ospf_proto *p)
98{
99 if (ospf_is_v2(p))
100 {
101 if (type == LSA_T_NSSA)
102 return !!(n->options & OPT_N);
103
104 if (lsa_is_opaque(type))
105 return !!(n->options & OPT_O);
106
107 return 1;
108 }
109 else
110 {
111 /*
112 * There should be check whether receiving router understands that type
113 * of LSA (for LSA types with U-bit == 0). But as we do not support any
114 * optional LSA types, this is not needed yet.
115 */
116
117 return 1;
118 }
119}
70945cb6
OZ
120
121static int
122unknown_lsa_type(u32 type)
123{
124 switch (type)
125 {
126 case LSA_T_RT:
127 case LSA_T_NET:
128 case LSA_T_SUM_NET:
129 case LSA_T_SUM_RT:
130 case LSA_T_EXT:
131 case LSA_T_NSSA:
132 case LSA_T_LINK:
133 case LSA_T_PREFIX:
5a50a989
OZ
134 case LSA_T_RI_LINK:
135 case LSA_T_RI_AREA:
136 case LSA_T_RI_AS:
70945cb6
OZ
137 return 0;
138
139 default:
140 return 1;
141 }
142}
143
5a50a989
OZ
144/* Maps OSPFv2 types to OSPFv3 types */
145static const u16 lsa_v2_types[] = {
146 0, LSA_T_RT, LSA_T_NET, LSA_T_SUM_NET, LSA_T_SUM_RT, LSA_T_EXT, 0, LSA_T_NSSA,
147 0, LSA_T_OPAQUE_LINK, LSA_T_OPAQUE_AREA, LSA_T_OPAQUE_AS
148};
149
150/* Maps OSPFv2 opaque types to OSPFv3 function codes */
151static const u16 opaque_lsa_types[] = {
1a2ad348 152 [LSA_OT_GR] = LSA_T_GR,
5a50a989
OZ
153 [LSA_OT_RI] = LSA_T_RI_,
154};
155
156/* Maps (subset of) OSPFv3 function codes to OSPFv2 opaque types */
157static const u8 opaque_lsa_types_inv[] = {
1a2ad348 158 [LSA_T_GR] = LSA_OT_GR,
5a50a989
OZ
159 [LSA_T_RI_] = LSA_OT_RI,
160};
161
162#define LOOKUP(a, i) ({ uint _i = (i); (_i < ARRAY_SIZE(a)) ? a[_i] : 0; })
70945cb6
OZ
163
164void
5a50a989 165lsa_get_type_domain_(u32 type, u32 id, struct ospf_iface *ifa, u32 *otype, u32 *domain)
70945cb6
OZ
166{
167 if (ospf_is_v2(ifa->oa->po))
168 {
5a50a989
OZ
169 type = type & LSA_T_V2_MASK;
170 type = LOOKUP(lsa_v2_types, type);
171
172 uint code;
173 if (LSA_FUNCTION(type) == LSA_T_OPAQUE_)
174 if (code = LOOKUP(opaque_lsa_types, id >> 24))
1a2ad348 175 {
5a50a989 176 type = code | LSA_UBIT | LSA_SCOPE(type);
1a2ad348
OZ
177
178 /* Hack for Grace-LSA: It does not use U-bit for link-scoped LSAs */
179 if (type == (LSA_T_GR | LSA_UBIT))
180 type = LSA_T_GR;
181 }
70945cb6
OZ
182 }
183 else
184 {
185 /* For unkown LSAs without U-bit change scope to LSA_SCOPE_LINK */
5a50a989
OZ
186 if (unknown_lsa_type(type) && !(type & LSA_UBIT))
187 type = type & ~LSA_SCOPE_MASK;
70945cb6
OZ
188 }
189
5a50a989 190 *otype = type;
70945cb6 191
5a50a989 192 switch (LSA_SCOPE(type))
70945cb6
OZ
193 {
194 case LSA_SCOPE_LINK:
195 *domain = ifa->iface_id;
196 return;
197
198 case LSA_SCOPE_AREA:
199 *domain = ifa->oa->areaid;
200 return;
201
202 case LSA_SCOPE_AS:
203 default:
204 *domain = 0;
205 return;
206 }
207}
208
1a2ad348
OZ
209int
210lsa_is_opaque(u32 type)
211{
212 u32 fn = LSA_FUNCTION(type);
213 return LOOKUP(opaque_lsa_types_inv, fn) || (fn == LSA_T_OPAQUE_);
214}
215
5a50a989
OZ
216u32
217lsa_get_opaque_type(u32 type)
218{
219 return LOOKUP(opaque_lsa_types_inv, LSA_FUNCTION(type));
220}
221
70945cb6 222
061ab802 223void
77edab64 224lsa_generate_checksum(struct ospf_lsa_header *lsa, const u8 *body)
061ab802 225{
77edab64
OZ
226 struct fletcher16_context ctx;
227 struct ospf_lsa_header hdr;
228 u16 len = lsa->length;
061ab802 229
f9c799a0 230 /*
77edab64
OZ
231 * lsa and body are in the host order, we need to compute Fletcher-16 checksum
232 * for data in the network order. We also skip the initial age field.
233 */
394acced 234
77edab64
OZ
235 lsa_hton_hdr(lsa, &hdr);
236 hdr.checksum = 0;
2e10a170 237
77edab64
OZ
238 fletcher16_init(&ctx);
239 fletcher16_update(&ctx, (u8 *) &hdr + 2, sizeof(struct ospf_lsa_header) - 2);
240 fletcher16_update_n32(&ctx, body, len - sizeof(struct ospf_lsa_header));
241 lsa->checksum = fletcher16_final(&ctx, len, OFFSETOF(struct ospf_lsa_header, checksum));
394acced
OF
242}
243
394acced 244u16
77edab64 245lsa_verify_checksum(const void *lsa_n, int lsa_len)
499cb346 246{
77edab64 247 struct fletcher16_context ctx;
499cb346 248
77edab64 249 /* The whole LSA is at lsa_n in net order, we just skip initial age field */
30d09eb9 250
77edab64
OZ
251 fletcher16_init(&ctx);
252 fletcher16_update(&ctx, (u8 *) lsa_n + 2, lsa_len - 2);
499cb346 253
77edab64 254 return fletcher16_compute(&ctx) == 0;
499cb346
OF
255}
256
77edab64 257
db9fb727
OF
258int
259lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2)
394acced 260 /* Return codes from point of view of l1 */
db9fb727 261{
2e10a170 262 u32 sn1, sn2;
37282678 263
2e10a170
OF
264 sn1 = l1->sn - LSA_INITSEQNO + 1;
265 sn2 = l2->sn - LSA_INITSEQNO + 1;
37282678 266
2e10a170
OF
267 if (sn1 > sn2)
268 return CMP_NEWER;
269 if (sn1 < sn2)
270 return CMP_OLDER;
ef6f26b4 271
2e10a170
OF
272 if (l1->checksum != l2->checksum)
273 return l1->checksum < l2->checksum ? CMP_OLDER : CMP_NEWER;
ef6f26b4 274
2e10a170
OF
275 if ((l1->age == LSA_MAXAGE) && (l2->age != LSA_MAXAGE))
276 return CMP_NEWER;
277 if ((l2->age == LSA_MAXAGE) && (l1->age != LSA_MAXAGE))
278 return CMP_OLDER;
ef6f26b4 279
2e10a170
OF
280 if (ABS(l1->age - l2->age) > LSA_MAXAGEDIFF)
281 return l1->age < l2->age ? CMP_NEWER : CMP_OLDER;
ef6f26b4
OF
282
283 return CMP_SAME;
db9fb727
OF
284}
285
a6bc04d5 286
1a2ad348
OZ
287#define LSA_TLV_LENGTH(tlv) \
288 (sizeof(struct ospf_tlv) + BIRD_ALIGN((tlv)->length, 4))
289
290#define LSA_NEXT_TLV(tlv) \
291 ((struct ospf_tlv *) ((byte *) (tlv) + LSA_TLV_LENGTH(tlv)))
292
293#define LSA_WALK_TLVS(tlv,buf,len) \
294 for(struct ospf_tlv *tlv = (void *) (buf); \
295 (byte *) tlv < (byte *) (buf) + (len); \
296 tlv = LSA_NEXT_TLV(tlv))
297
298struct ospf_tlv *
299lsa_get_tlv(struct top_hash_entry *en, uint type)
300{
301 LSA_WALK_TLVS(tlv, en->lsa_body, en->lsa.length - HDRLEN)
302 if (tlv->type == type)
303 return tlv;
304
305 return NULL;
306}
307
308int
309lsa_validate_tlvs(byte *buf, uint len)
310{
311 byte *pos = buf;
312 byte *end = buf + len;
313
314 while (pos < end)
315 {
316 if ((pos + sizeof(struct ospf_tlv)) > end)
317 return 0;
318
319 struct ospf_tlv *tlv = (void *) pos;
320 uint len = LSA_TLV_LENGTH(tlv);
321
322 if ((pos + len) > end)
323 return 0;
324
325 pos += len;
326 }
327
328 return 1;
329}
330
331
70945cb6
OZ
332static inline int
333lsa_walk_rt2(struct ospf_lsa_rt_walk *rt)
a6bc04d5 334{
70945cb6 335 if (rt->buf >= rt->bufend)
a6bc04d5
OZ
336 return 0;
337
70945cb6
OZ
338 struct ospf_lsa_rt2_link *l = rt->buf;
339 rt->buf += sizeof(struct ospf_lsa_rt2_link) + l->no_tos * sizeof(struct ospf_lsa_rt2_tos);
a6bc04d5 340
70945cb6
OZ
341 rt->type = l->type;
342 rt->metric = l->metric;
343 rt->id = l->id;
344 rt->data = l->data;
345 return 1;
346}
a6bc04d5 347
70945cb6
OZ
348static inline int
349lsa_walk_rt3(struct ospf_lsa_rt_walk *rt)
350{
351 while (rt->buf >= rt->bufend)
a6bc04d5 352 {
70945cb6
OZ
353 rt->en = ospf_hash_find_rt3_next(rt->en);
354 if (!rt->en)
a6bc04d5 355 return 0;
70945cb6
OZ
356
357 rt->buf = rt->en->lsa_body;
358 rt->bufend = rt->buf + rt->en->lsa.length - sizeof(struct ospf_lsa_header);
359 rt->buf += sizeof(struct ospf_lsa_rt);
a6bc04d5 360 }
70945cb6
OZ
361
362 struct ospf_lsa_rt3_link *l = rt->buf;
363 rt->buf += sizeof(struct ospf_lsa_rt3_link);
364
365 rt->type = l->type;
366 rt->metric = l->metric;
367 rt->lif = l->lif;
368 rt->nif = l->nif;
369 rt->id = l->id;
a6bc04d5
OZ
370 return 1;
371}
372
70945cb6
OZ
373void
374lsa_walk_rt_init(struct ospf_proto *p, struct top_hash_entry *act, struct ospf_lsa_rt_walk *rt)
375{
376 rt->ospf2 = ospf_is_v2(p);
377 rt->id = rt->data = rt->lif = rt->nif = 0;
378
379 if (rt->ospf2)
380 rt->en = act;
381 else
382 rt->en = ospf_hash_find_rt3_first(p->gr, act->domain, act->lsa.rt);
383
384 rt->buf = rt->en->lsa_body;
385 rt->bufend = rt->buf + rt->en->lsa.length - sizeof(struct ospf_lsa_header);
386 rt->buf += sizeof(struct ospf_lsa_rt);
387}
388
389int
390lsa_walk_rt(struct ospf_lsa_rt_walk *rt)
391{
392 return rt->ospf2 ? lsa_walk_rt2(rt) : lsa_walk_rt3(rt);
393}
394
395
396void
d3f4f92b 397lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, int af, net_addr *net, u8 *pxopts, u32 *metric)
70945cb6
OZ
398{
399 if (ospf2)
400 {
4a3f5b36 401 uint opts = lsa_get_options(&en->lsa);
70945cb6 402 struct ospf_lsa_sum2 *ls = en->lsa_body;
fe9f1a6d 403 net_fill_ip4(net, ip4_from_u32(en->lsa.id & ls->netmask), u32_masklen(ls->netmask));
4a3f5b36 404 *pxopts = (opts & OPT_DN) ? OPT_PX_DN : 0;
70945cb6
OZ
405 *metric = ls->metric & LSA_METRIC_MASK;
406 }
407 else
408 {
409 struct ospf_lsa_sum3_net *ls = en->lsa_body;
d3f4f92b 410 ospf3_get_prefix(ls->prefix, af, net, pxopts, NULL);
70945cb6
OZ
411 *metric = ls->metric & LSA_METRIC_MASK;
412 }
413}
414
415void
416lsa_parse_sum_rt(struct top_hash_entry *en, int ospf2, u32 *drid, u32 *metric, u32 *options)
417{
418 if (ospf2)
419 {
420 struct ospf_lsa_sum2 *ls = en->lsa_body;
421 *drid = en->lsa.id;
422 *metric = ls->metric & LSA_METRIC_MASK;
423 *options = 0;
424 }
425 else
426 {
427 struct ospf_lsa_sum3_rt *ls = en->lsa_body;
428 *drid = ls->drid;
429 *metric = ls->metric & LSA_METRIC_MASK;
430 *options = ls->options & LSA_OPTIONS_MASK;
431 }
432}
433
434void
d3f4f92b 435lsa_parse_ext(struct top_hash_entry *en, int ospf2, int af, struct ospf_lsa_ext_local *rt)
70945cb6
OZ
436{
437 if (ospf2)
438 {
439 struct ospf_lsa_ext2 *ext = en->lsa_body;
fe9f1a6d
OZ
440 net_fill_ip4(&rt->net,
441 ip4_from_u32(en->lsa.id & ext->netmask),
442 u32_masklen(ext->netmask));
70945cb6
OZ
443 rt->pxopts = 0;
444 rt->metric = ext->metric & LSA_METRIC_MASK;
445 rt->ebit = ext->metric & LSA_EXT2_EBIT;
446
447 rt->fbit = ext->fwaddr;
448 rt->fwaddr = ipa_from_u32(ext->fwaddr);
449
450 rt->tag = ext->tag;
451 rt->propagate = lsa_get_options(&en->lsa) & OPT_P;
4a3f5b36 452 rt->downwards = lsa_get_options(&en->lsa) & OPT_DN;
70945cb6
OZ
453 }
454 else
455 {
456 struct ospf_lsa_ext3 *ext = en->lsa_body;
d3f4f92b 457 u32 *buf = ospf3_get_prefix(ext->rest, af, &rt->net, &rt->pxopts, NULL);
70945cb6
OZ
458 rt->metric = ext->metric & LSA_METRIC_MASK;
459 rt->ebit = ext->metric & LSA_EXT3_EBIT;
460
461 rt->fbit = ext->metric & LSA_EXT3_FBIT;
462 if (rt->fbit)
d3f4f92b 463 buf = ospf3_get_addr(buf, af, &rt->fwaddr);
742029eb 464 else
70945cb6
OZ
465 rt->fwaddr = IPA_NONE;
466
467 rt->tag = (ext->metric & LSA_EXT3_TBIT) ? *buf++ : 0;
468 rt->propagate = rt->pxopts & OPT_PX_P;
4a3f5b36 469 rt->downwards = rt->pxopts & OPT_PX_DN;
70945cb6
OZ
470 }
471}
472
70945cb6 473
a6bc04d5 474static int
70945cb6 475lsa_validate_rt2(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body)
a6bc04d5 476{
70945cb6
OZ
477 if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_rt)))
478 return 0;
479
480 uint i = 0;
481 void *buf = body;
482 void *bufend = buf + lsa->length - HDRLEN;
483 buf += sizeof(struct ospf_lsa_rt);
484
485 while (buf < bufend)
486 {
487 struct ospf_lsa_rt2_link *l = buf;
488 buf += sizeof(struct ospf_lsa_rt2_link) + l->no_tos * sizeof(struct ospf_lsa_rt2_tos);
489 i++;
490
491 if (buf > bufend)
492 return 0;
493
494 if (!((l->type == LSART_PTP) ||
495 (l->type == LSART_NET) ||
496 (l->type == LSART_STUB) ||
497 (l->type == LSART_VLNK)))
498 return 0;
499 }
500
501 if ((body->options & LSA_RT2_LINKS) != i)
a6bc04d5
OZ
502 return 0;
503
504 return 1;
505}
506
a6bc04d5
OZ
507
508static int
70945cb6 509lsa_validate_rt3(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body)
a6bc04d5 510{
70945cb6 511 if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_rt)))
a6bc04d5
OZ
512 return 0;
513
70945cb6
OZ
514 void *buf = body;
515 void *bufend = buf + lsa->length - HDRLEN;
516 buf += sizeof(struct ospf_lsa_rt);
517
518 while (buf < bufend)
519 {
520 struct ospf_lsa_rt3_link *l = buf;
521 buf += sizeof(struct ospf_lsa_rt3_link);
522
523 if (buf > bufend)
524 return 0;
525
526 if (!((l->type == LSART_PTP) ||
527 (l->type == LSART_NET) ||
528 (l->type == LSART_VLNK)))
529 return 0;
530 }
531 return 1;
532}
533
534static int
535lsa_validate_net(struct ospf_lsa_header *lsa, struct ospf_lsa_net *body UNUSED)
536{
537 if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_net)))
a6bc04d5
OZ
538 return 0;
539
540 return 1;
541}
a6bc04d5
OZ
542
543static int
70945cb6 544lsa_validate_sum2(struct ospf_lsa_header *lsa, struct ospf_lsa_sum2 *body)
a6bc04d5 545{
70945cb6 546 if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum2)))
a6bc04d5
OZ
547 return 0;
548
549 /* First field should have TOS = 0, we ignore other TOS fields */
70945cb6 550 if ((body->metric & LSA_SUM2_TOS) != 0)
a6bc04d5
OZ
551 return 0;
552
553 return 1;
554}
555
a6bc04d5
OZ
556static inline int
557pxlen(u32 *buf)
558{
559 return *buf >> 24;
560}
561
562static int
70945cb6 563lsa_validate_sum3_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_net *body)
a6bc04d5 564{
70945cb6 565 if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum3_net) + 4))
a6bc04d5
OZ
566 return 0;
567
568 u8 pxl = pxlen(body->prefix);
fe9f1a6d 569 if (pxl > IP6_MAX_PREFIX_LENGTH)
a6bc04d5
OZ
570 return 0;
571
742029eb 572 if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum3_net) +
a6bc04d5
OZ
573 IPV6_PREFIX_SPACE(pxl)))
574 return 0;
575
576 return 1;
577}
578
70945cb6 579static int
3e236955 580lsa_validate_sum3_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_rt *body UNUSED)
70945cb6
OZ
581{
582 if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum3_rt)))
583 return 0;
584
585 return 1;
586}
a6bc04d5
OZ
587
588static int
70945cb6 589lsa_validate_ext2(struct ospf_lsa_header *lsa, struct ospf_lsa_ext2 *body)
a6bc04d5 590{
70945cb6
OZ
591 if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext2)))
592 return 0;
593
594 /* First field should have TOS = 0, we ignore other TOS fields */
595 if ((body->metric & LSA_EXT2_TOS) != 0)
a6bc04d5
OZ
596 return 0;
597
598 return 1;
599}
600
601static int
70945cb6 602lsa_validate_ext3(struct ospf_lsa_header *lsa, struct ospf_lsa_ext3 *body)
a6bc04d5 603{
70945cb6 604 if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext3) + 4))
a6bc04d5
OZ
605 return 0;
606
607 u8 pxl = pxlen(body->rest);
fe9f1a6d 608 if (pxl > IP6_MAX_PREFIX_LENGTH)
a6bc04d5
OZ
609 return 0;
610
611 int len = IPV6_PREFIX_SPACE(pxl);
d7661fbe 612 if (body->metric & LSA_EXT3_FBIT) // forwarding address
a6bc04d5 613 len += 16;
70945cb6 614 if (body->metric & LSA_EXT3_TBIT) // route tag
a6bc04d5
OZ
615 len += 4;
616 if (*body->rest & 0xFFFF) // referenced LS type field
617 len += 4;
618
70945cb6 619 if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_ext3) + len))
a6bc04d5
OZ
620 return 0;
621
622 return 1;
623}
624
625static int
70945cb6 626lsa_validate_pxlist(struct ospf_lsa_header *lsa, u32 pxcount, uint offset, u8 *pbuf)
a6bc04d5 627{
70945cb6 628 uint bound = lsa->length - HDRLEN - 4;
a6bc04d5
OZ
629 u32 i;
630
631 for (i = 0; i < pxcount; i++)
632 {
633 if (offset > bound)
634 return 0;
635
636 u8 pxl = pxlen((u32 *) (pbuf + offset));
fe9f1a6d 637 if (pxl > IP6_MAX_PREFIX_LENGTH)
a6bc04d5 638 return 0;
742029eb 639
a6bc04d5
OZ
640 offset += IPV6_PREFIX_SPACE(pxl);
641 }
642
643 if (lsa->length != (HDRLEN + offset))
644 return 0;
645
646 return 1;
647}
648
649static int
650lsa_validate_link(struct ospf_lsa_header *lsa, struct ospf_lsa_link *body)
651{
652 if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_link)))
653 return 0;
654
655 return lsa_validate_pxlist(lsa, body->pxcount, sizeof(struct ospf_lsa_link), (u8 *) body);
656}
657
658static int
659lsa_validate_prefix(struct ospf_lsa_header *lsa, struct ospf_lsa_prefix *body)
660{
661 if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_prefix)))
662 return 0;
663
664 return lsa_validate_pxlist(lsa, body->pxcount, sizeof(struct ospf_lsa_prefix), (u8 *) body);
665}
666
1a2ad348
OZ
667static int
668lsa_validate_gr(struct ospf_lsa_header *lsa, void *body)
669{
670 return lsa_validate_tlvs(body, lsa->length - HDRLEN);
671}
672
5a50a989
OZ
673static int
674lsa_validate_ri(struct ospf_lsa_header *lsa UNUSED, struct ospf_lsa_net *body UNUSED)
675{
676 /*
677 * There should be proper validation. But we do not really process RI LSAs, so
678 * we can just accept them like another unknown opaque LSAs.
679 */
680
681 return 1;
682}
683
a6bc04d5
OZ
684
685/**
686 * lsa_validate - check whether given LSA is valid
687 * @lsa: LSA header
af678af0
OZ
688 * @lsa_type: internal LSA type (%LSA_T_xxx)
689 * @ospf2: %true for OSPFv2, %false for OSPFv3
a6bc04d5
OZ
690 * @body: pointer to LSA body
691 *
692 * Checks internal structure of given LSA body (minimal length,
693 * consistency). Returns true if valid.
694 */
a6bc04d5 695int
70945cb6 696lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body)
a6bc04d5 697{
70945cb6
OZ
698 if (ospf2)
699 {
700 switch (lsa_type)
701 {
702 case LSA_T_RT:
703 return lsa_validate_rt2(lsa, body);
704 case LSA_T_NET:
705 return lsa_validate_net(lsa, body);
706 case LSA_T_SUM_NET:
707 return lsa_validate_sum2(lsa, body);
708 case LSA_T_SUM_RT:
709 return lsa_validate_sum2(lsa, body);
710 case LSA_T_EXT:
711 case LSA_T_NSSA:
712 return lsa_validate_ext2(lsa, body);
1a2ad348
OZ
713 case LSA_T_GR:
714 return lsa_validate_gr(lsa, body);
5a50a989
OZ
715 case LSA_T_RI_LINK:
716 case LSA_T_RI_AREA:
717 case LSA_T_RI_AS:
718 return lsa_validate_ri(lsa, body);
719 case LSA_T_OPAQUE_LINK:
720 case LSA_T_OPAQUE_AREA:
721 case LSA_T_OPAQUE_AS:
722 return 1; /* Unknown Opaque LSAs */
70945cb6
OZ
723 default:
724 return 0; /* Should not happen, unknown LSAs are already rejected */
725 }
726 }
727 else
728 {
729 switch (lsa_type)
a6bc04d5
OZ
730 {
731 case LSA_T_RT:
70945cb6 732 return lsa_validate_rt3(lsa, body);
a6bc04d5
OZ
733 case LSA_T_NET:
734 return lsa_validate_net(lsa, body);
735 case LSA_T_SUM_NET:
70945cb6 736 return lsa_validate_sum3_net(lsa, body);
a6bc04d5 737 case LSA_T_SUM_RT:
70945cb6 738 return lsa_validate_sum3_rt(lsa, body);
a6bc04d5 739 case LSA_T_EXT:
41b612c3 740 case LSA_T_NSSA:
70945cb6 741 return lsa_validate_ext3(lsa, body);
a6bc04d5
OZ
742 case LSA_T_LINK:
743 return lsa_validate_link(lsa, body);
744 case LSA_T_PREFIX:
745 return lsa_validate_prefix(lsa, body);
1a2ad348
OZ
746 case LSA_T_GR:
747 return lsa_validate_gr(lsa, body);
5a50a989
OZ
748 case LSA_T_RI_LINK:
749 case LSA_T_RI_AREA:
750 case LSA_T_RI_AS:
751 return lsa_validate_ri(lsa, body);
a6bc04d5 752 default:
70945cb6 753 return 1; /* Unknown LSAs are OK in OSPFv3 */
a6bc04d5 754 }
85195f1a 755 }
d8852b36 756}