lsalib.c 15.4 KB
Newer Older
1 2 3
/*
 *	BIRD -- OSPF
 *
4
 *	(c) 1999--2004 Ondrej Filip <feela@network.cz>
5 6
 *	(c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
 *	(c) 2009--2014 CZ.NIC z.s.p.o.
7 8 9 10 11 12
 *
 *	Can be freely distributed and used under the terms of the GNU GPL.
 */

#include "ospf.h"

Ondřej Filip's avatar
Ondřej Filip committed
13

14
#ifndef CPU_BIG_ENDIAN
15
void
16
lsa_hton_hdr(struct ospf_lsa_header *h, struct ospf_lsa_header *n)
17
{
Ondřej Filip's avatar
Ondřej Filip committed
18
  n->age = htons(h->age);
19
  n->type_raw = htons(h->type_raw);
Ondřej Filip's avatar
Ondřej Filip committed
20 21 22 23 24
  n->id = htonl(h->id);
  n->rt = htonl(h->rt);
  n->sn = htonl(h->sn);
  n->checksum = htons(h->checksum);
  n->length = htons(h->length);
25
}
26 27

void
28
lsa_ntoh_hdr(struct ospf_lsa_header *n, struct ospf_lsa_header *h)
29
{
Ondřej Filip's avatar
Ondřej Filip committed
30
  h->age = ntohs(n->age);
31
  h->type_raw = ntohs(n->type_raw);
Ondřej Filip's avatar
Ondřej Filip committed
32 33 34 35 36
  h->id = ntohl(n->id);
  h->rt = ntohl(n->rt);
  h->sn = ntohl(n->sn);
  h->checksum = ntohs(n->checksum);
  h->length = ntohs(n->length);
37
}
38 39

void
40
lsa_hton_body(void *h, void *n, u16 len)
41
{
42 43
  u32 *hid = h;
  u32 *nid = n;
44
  uint i;
45

46 47 48
  for (i = 0; i < (len / sizeof(u32)); i++)
    nid[i] = htonl(hid[i]);
}
49 50

void
51
lsa_ntoh_body(void *n, void *h, u16 len)
52
{
53 54
  u32 *nid = n;
  u32 *hid = h;
55
  uint i;
56

57 58 59
  for (i = 0; i < (len / sizeof(u32)); i++)
    hid[i] = ntohl(nid[i]);
}
60
#endif /* little endian */
61

62 63 64 65


int
lsa_flooding_allowed(u32 type, u32 domain, struct ospf_iface *ifa)
66
{
67 68 69
  /* Handle inactive vlinks */
  if (ifa->state == OSPF_IS_DOWN)
    return 0;
70

71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
  /* 4.5.2 (Case 2) */
  switch (LSA_SCOPE(type))
  {
  case LSA_SCOPE_LINK:
    return ifa->iface_id == domain;

  case LSA_SCOPE_AREA:
    return ifa->oa->areaid == domain;

  case LSA_SCOPE_AS:
    if (ifa->type == OSPF_IT_VLINK)
      return 0;
    if (!oa_is_ext(ifa->oa))
      return 0;
    return 1;

  default:
    log(L_ERR "OSPF: LSA with invalid scope");
    return 0;
  }
}


static int
unknown_lsa_type(u32 type)
{
  switch (type)
  {
  case LSA_T_RT:
  case LSA_T_NET:
  case LSA_T_SUM_NET:
  case LSA_T_SUM_RT:
  case LSA_T_EXT:
  case LSA_T_NSSA:
  case LSA_T_LINK:
  case LSA_T_PREFIX:
    return 0;

  default:
    return 1;
  }
}

#define LSA_V2_TMAX 8
static const u16 lsa_v2_types[LSA_V2_TMAX] =
  {0, LSA_T_RT, LSA_T_NET, LSA_T_SUM_NET, LSA_T_SUM_RT, LSA_T_EXT, 0, LSA_T_NSSA};

void
lsa_get_type_domain_(u32 itype, struct ospf_iface *ifa, u32 *otype, u32 *domain)
{
  if (ospf_is_v2(ifa->oa->po))
  {
    itype = itype & LSA_T_V2_MASK;
    itype = (itype < LSA_V2_TMAX) ? lsa_v2_types[itype] : 0;
  }
  else
  {
    /* For unkown LSAs without U-bit change scope to LSA_SCOPE_LINK */
    if (unknown_lsa_type(itype) && !(itype & LSA_UBIT))
      itype = itype & ~LSA_SCOPE_MASK;
  }

  *otype = itype;

  switch (LSA_SCOPE(itype))
  {
  case LSA_SCOPE_LINK:
    *domain = ifa->iface_id;
    return;

  case LSA_SCOPE_AREA:
    *domain = ifa->oa->areaid;
    return;

  case LSA_SCOPE_AS:
  default:
    *domain = 0;
    return;
  }
}



Ondřej Zajíček's avatar
Ondřej Zajíček committed
154
/*
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
void
buf_dump(const char *hdr, const byte *buf, int blen)
{
  char b2[1024];
  char *bp;
  int first = 1;
  int i;

  const char *lhdr = hdr;

  bp = b2;
  for(i = 0; i < blen; i++)
    {
      if ((i > 0) && ((i % 16) == 0))
	{
	      *bp = 0;
	      log(L_WARN "%s\t%s", lhdr, b2);
	      lhdr = "";
	      bp = b2;
	}

      bp += snprintf(bp, 1022, "%02x ", buf[i]);

    }

  *bp = 0;
  log(L_WARN "%s\t%s", lhdr, b2);
}
Ondřej Zajíček's avatar
Ondřej Zajíček committed
183
*/
184

185 186 187 188 189 190 191 192
#define MODX 4102		/* larges signed value without overflow */

/* Fletcher Checksum -- Refer to RFC1008. */
#define MODX                 4102
#define LSA_CHECKSUM_OFFSET    15

/* FIXME This is VERY uneficient, I have huge endianity problems */
void
Ondřej Filip's avatar
Ondřej Filip committed
193
lsasum_calculate(struct ospf_lsa_header *h, void *body)
194
{
195
  u16 length = h->length;
Ondřej Filip's avatar
Ondřej Filip committed
196

197
  //  log(L_WARN "Checksum %R %R %d start (len %d)", h->id, h->rt, h->type, length);
198 199
  lsa_hton_hdr(h, h);
  lsa_hton_body1(body, length - sizeof(struct ospf_lsa_header));
200

201
  /*
202 203 204 205
  char buf[1024];
  memcpy(buf, h, sizeof(struct ospf_lsa_header));
  memcpy(buf + sizeof(struct ospf_lsa_header), body, length - sizeof(struct ospf_lsa_header));
  buf_dump("CALC", buf, length);
206
  */
207

208
  (void) lsasum_check(h, body, 1);
Ondřej Filip's avatar
Ondřej Filip committed
209

210
  //  log(L_WARN "Checksum result %4x", h->checksum);
211

212 213
  lsa_ntoh_hdr(h, h);
  lsa_ntoh_body1(body, length - sizeof(struct ospf_lsa_header));
214 215 216
}

/*
217 218 219 220 221 222 223 224 225 226 227 228
 * Calculates the Fletcher checksum of an OSPF LSA.
 *
 * If 'update' is non-zero, the checkbytes (X and Y in RFC905) are calculated
 * and the checksum field in the header is updated. The return value is the
 * checksum as placed in the header (in network byte order).
 *
 * If 'update' is zero, only C0 and C1 are calculated and the header is kept
 * intact. The return value is a combination of C0 and C1; if the return value
 * is exactly zero the checksum is considered valid, any non-zero value is
 * invalid.
 *
 * Note that this function expects the input LSA to be in network byte order.
229 230
 */
u16
231
lsasum_check(struct ospf_lsa_header *h, void *body, int update)
232 233 234 235
{
  u8 *sp, *ep, *p, *q, *b;
  int c0 = 0, c1 = 0;
  int x, y;
236
  u16 length;
237

238
  b = body;
239
  sp = (char *) h;
240
  sp += 2; /* Skip Age field */
Ondřej Filip's avatar
Ondřej Filip committed
241
  length = ntohs(h->length) - 2;
242
  if (update) h->checksum = 0;
243 244

  for (ep = sp + length; sp < ep; sp = q)
Ondřej Filip's avatar
Ondřej Filip committed
245
  {				/* Actually MODX is very large, do we need the for-cyclus? */
246
    q = sp + MODX;
Ondřej Filip's avatar
Ondřej Filip committed
247 248
    if (q > ep)
      q = ep;
249
    for (p = sp; p < q; p++)
250
    {
251
      /*
252 253 254 255 256
       * I count with bytes from header and than from body
       * but if there is no body, it's appended to header
       * (probably checksum in update receiving) and I go on
       * after header
       */
Ondřej Filip's avatar
Ondřej Filip committed
257
      if ((b == NULL) || (p < (u8 *) (h + 1)))
258
      {
Ondřej Filip's avatar
Ondřej Filip committed
259
	c0 += *p;
260 261 262
      }
      else
      {
263
	c0 += *(b + (p - (u8 *) (h + 1)));
264 265 266
      }

      c1 += c0;
267
    }
268 269 270
    c0 %= 255;
    c1 %= 255;
  }
271

272 273 274 275 276 277 278 279
  if (!update) {
    /*
     * When testing the checksum, we don't need to calculate x and y. The
     * checksum passes if c0 and c1 are both 0.
     */
    return (c0 << 8) | (c1 & 0xff);
  }

280
  x = (int)((length - LSA_CHECKSUM_OFFSET) * c0 - c1) % 255;
Ondřej Filip's avatar
Ondřej Filip committed
281 282
  if (x <= 0)
    x += 255;
283
  y = 510 - c0 - x;
Ondřej Filip's avatar
Ondřej Filip committed
284 285
  if (y > 255)
    y -= 255;
286

Ondřej Filip's avatar
Ondřej Filip committed
287 288
  ((u8 *) & h->checksum)[0] = x;
  ((u8 *) & h->checksum)[1] = y;
289
  return h->checksum;
290 291
}

Ondřej Filip's avatar
Ondřej Filip committed
292 293
int
lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2)
294
			/* Return codes from point of view of l1 */
Ondřej Filip's avatar
Ondřej Filip committed
295
{
Ondřej Filip's avatar
Ondřej Filip committed
296
  u32 sn1, sn2;
297

Ondřej Filip's avatar
Ondřej Filip committed
298 299
  sn1 = l1->sn - LSA_INITSEQNO + 1;
  sn2 = l2->sn - LSA_INITSEQNO + 1;
300

Ondřej Filip's avatar
Ondřej Filip committed
301 302 303 304
  if (sn1 > sn2)
    return CMP_NEWER;
  if (sn1 < sn2)
    return CMP_OLDER;
Ondřej Filip's avatar
Ondřej Filip committed
305

Ondřej Filip's avatar
Ondřej Filip committed
306 307
  if (l1->checksum != l2->checksum)
    return l1->checksum < l2->checksum ? CMP_OLDER : CMP_NEWER;
Ondřej Filip's avatar
Ondřej Filip committed
308

Ondřej Filip's avatar
Ondřej Filip committed
309 310 311 312
  if ((l1->age == LSA_MAXAGE) && (l2->age != LSA_MAXAGE))
    return CMP_NEWER;
  if ((l2->age == LSA_MAXAGE) && (l1->age != LSA_MAXAGE))
    return CMP_OLDER;
Ondřej Filip's avatar
Ondřej Filip committed
313

Ondřej Filip's avatar
Ondřej Filip committed
314 315
  if (ABS(l1->age - l2->age) > LSA_MAXAGEDIFF)
    return l1->age < l2->age ? CMP_NEWER : CMP_OLDER;
Ondřej Filip's avatar
Ondřej Filip committed
316 317

  return CMP_SAME;
Ondřej Filip's avatar
Ondřej Filip committed
318 319
}

320

321 322
static inline int
lsa_walk_rt2(struct ospf_lsa_rt_walk *rt)
323
{
324
  if (rt->buf >= rt->bufend)
325 326
    return 0;

327 328
  struct ospf_lsa_rt2_link *l = rt->buf;
  rt->buf += sizeof(struct ospf_lsa_rt2_link) + l->no_tos * sizeof(struct ospf_lsa_rt2_tos);
329

330 331 332 333 334 335
  rt->type = l->type;
  rt->metric = l->metric;
  rt->id = l->id;
  rt->data = l->data;
  return 1;
}
336

337 338 339 340
static inline int
lsa_walk_rt3(struct ospf_lsa_rt_walk *rt)
{
  while (rt->buf >= rt->bufend)
341
  {
342 343
    rt->en = ospf_hash_find_rt3_next(rt->en);
    if (!rt->en)
344
      return 0;
345 346 347 348

    rt->buf = rt->en->lsa_body;
    rt->bufend = rt->buf + rt->en->lsa.length - sizeof(struct ospf_lsa_header);
    rt->buf += sizeof(struct ospf_lsa_rt);
349
  }
350 351 352 353 354 355 356 357 358

  struct ospf_lsa_rt3_link *l = rt->buf;
  rt->buf += sizeof(struct ospf_lsa_rt3_link);

  rt->type = l->type;
  rt->metric = l->metric;
  rt->lif = l->lif;
  rt->nif = l->nif;
  rt->id = l->id;
359 360 361
  return 1;
}

362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452
void
lsa_walk_rt_init(struct ospf_proto *p, struct top_hash_entry *act, struct ospf_lsa_rt_walk *rt)
{
  rt->ospf2 = ospf_is_v2(p);
  rt->id = rt->data = rt->lif = rt->nif = 0;

  if (rt->ospf2)
    rt->en = act;
  else
    rt->en = ospf_hash_find_rt3_first(p->gr, act->domain, act->lsa.rt);

  rt->buf = rt->en->lsa_body;
  rt->bufend = rt->buf + rt->en->lsa.length - sizeof(struct ospf_lsa_header);
  rt->buf += sizeof(struct ospf_lsa_rt);
}

int
lsa_walk_rt(struct ospf_lsa_rt_walk *rt)
{
  return rt->ospf2 ? lsa_walk_rt2(rt) : lsa_walk_rt3(rt);
}


void
lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, ip_addr *ip, int *pxlen, u8 *pxopts, u32 *metric)
{
  if (ospf2)
  {
    struct ospf_lsa_sum2 *ls = en->lsa_body;
    *ip = ipa_from_u32(en->lsa.id & ls->netmask);
    *pxlen = u32_masklen(ls->netmask);
    *pxopts = 0;
    *metric = ls->metric & LSA_METRIC_MASK;
  }
  else
  {
    struct ospf_lsa_sum3_net *ls = en->lsa_body;
    u16 rest;
    lsa_get_ipv6_prefix(ls->prefix, ip, pxlen, pxopts, &rest);
    *metric = ls->metric & LSA_METRIC_MASK;
  }
}

void
lsa_parse_sum_rt(struct top_hash_entry *en, int ospf2, u32 *drid, u32 *metric, u32 *options)
{
  if (ospf2)
  {
    struct ospf_lsa_sum2 *ls = en->lsa_body;
    *drid = en->lsa.id;
    *metric = ls->metric & LSA_METRIC_MASK;
    *options = 0;
  }
  else
  {
    struct ospf_lsa_sum3_rt *ls = en->lsa_body;
    *drid = ls->drid;
    *metric = ls->metric & LSA_METRIC_MASK;
    *options = ls->options & LSA_OPTIONS_MASK;
  }
}

void
lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *rt)
{
  if (ospf2)
  {
    struct ospf_lsa_ext2 *ext = en->lsa_body;
    rt->ip = ipa_from_u32(en->lsa.id & ext->netmask);
    rt->pxlen = u32_masklen(ext->netmask);
    rt->pxopts = 0;
    rt->metric = ext->metric & LSA_METRIC_MASK;
    rt->ebit = ext->metric & LSA_EXT2_EBIT;

    rt->fbit = ext->fwaddr;
    rt->fwaddr = ipa_from_u32(ext->fwaddr);

    rt->tag = ext->tag;
    rt->propagate = lsa_get_options(&en->lsa) & OPT_P;
  }
  else
  {
    struct ospf_lsa_ext3 *ext = en->lsa_body;
    u16 rest;
    u32 *buf = lsa_get_ipv6_prefix(ext->rest, &rt->ip, &rt->pxlen, &rt->pxopts, &rest);
    rt->metric = ext->metric & LSA_METRIC_MASK;
    rt->ebit = ext->metric & LSA_EXT3_EBIT;

    rt->fbit = ext->metric & LSA_EXT3_FBIT;
    if (rt->fbit)
      buf = lsa_get_ipv6_addr(buf, &rt->fwaddr);
453
    else
454 455 456 457 458 459 460 461 462
      rt->fwaddr = IPA_NONE;

    rt->tag = (ext->metric & LSA_EXT3_TBIT) ? *buf++ : 0;
    rt->propagate = rt->pxopts & OPT_PX_P;
  }
}

#define HDRLEN sizeof(struct ospf_lsa_header)

463
static int
464
lsa_validate_rt2(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body)
465
{
466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
  if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_rt)))
    return 0;

  uint i = 0;
  void *buf = body;
  void *bufend = buf + lsa->length - HDRLEN;
  buf += sizeof(struct ospf_lsa_rt);

  while (buf < bufend)
  {
    struct ospf_lsa_rt2_link *l = buf;
    buf += sizeof(struct ospf_lsa_rt2_link) + l->no_tos * sizeof(struct ospf_lsa_rt2_tos);
    i++;

    if (buf > bufend)
      return 0;

    if (!((l->type == LSART_PTP) ||
	  (l->type == LSART_NET) ||
	  (l->type == LSART_STUB) ||
	  (l->type == LSART_VLNK)))
      return 0;
  }

  if ((body->options & LSA_RT2_LINKS) != i)
491 492 493 494 495 496 497
    return 0;

  return 1;
}


static int
498
lsa_validate_rt3(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body)
499
{
500
  if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_rt)))
501 502
    return 0;

503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526
  void *buf = body;
  void *bufend = buf + lsa->length - HDRLEN;
  buf += sizeof(struct ospf_lsa_rt);

  while (buf < bufend)
  {
    struct ospf_lsa_rt3_link *l = buf;
    buf += sizeof(struct ospf_lsa_rt3_link);

    if (buf > bufend)
      return 0;

    if (!((l->type == LSART_PTP) ||
	  (l->type == LSART_NET) ||
	  (l->type == LSART_VLNK)))
      return 0;
  }
  return 1;
}

static int
lsa_validate_net(struct ospf_lsa_header *lsa, struct ospf_lsa_net *body UNUSED)
{
  if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_net)))
527 528 529 530 531 532
    return 0;

  return 1;
}

static int
533
lsa_validate_sum2(struct ospf_lsa_header *lsa, struct ospf_lsa_sum2 *body)
534
{
535
  if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum2)))
536 537 538
    return 0;

  /* First field should have TOS = 0, we ignore other TOS fields */
539
  if ((body->metric & LSA_SUM2_TOS) != 0)
540 541 542 543 544 545 546 547 548 549 550 551
    return 0;

  return 1;
}

static inline int
pxlen(u32 *buf)
{
  return *buf >> 24;
}

static int
552
lsa_validate_sum3_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_net *body)
553
{
554
  if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum3_net) + 4))
555 556 557 558 559 560
    return 0;

  u8 pxl = pxlen(body->prefix);
  if (pxl > MAX_PREFIX_LENGTH)
    return 0;

561
  if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum3_net) +
562 563 564 565 566 567
		      IPV6_PREFIX_SPACE(pxl)))
    return 0;

  return 1;
}

568 569 570 571 572 573 574 575
static int
lsa_validate_sum3_rt(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_rt *body)
{
  if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum3_rt)))
    return 0;

  return 1;
}
576 577

static int
578
lsa_validate_ext2(struct ospf_lsa_header *lsa, struct ospf_lsa_ext2 *body)
579
{
580 581 582 583 584
  if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext2)))
    return 0;

  /* First field should have TOS = 0, we ignore other TOS fields */
  if ((body->metric & LSA_EXT2_TOS) != 0)
585 586 587 588 589 590
    return 0;

  return 1;
}

static int
591
lsa_validate_ext3(struct ospf_lsa_header *lsa, struct ospf_lsa_ext3 *body)
592
{
593
  if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext3) + 4))
594 595 596 597 598 599 600
    return 0;

  u8 pxl = pxlen(body->rest);
  if (pxl > MAX_PREFIX_LENGTH)
    return 0;

  int len = IPV6_PREFIX_SPACE(pxl);
601
  if (body->metric & LSA_EXT3_FBIT) // forwardinf address
602
    len += 16;
603
  if (body->metric & LSA_EXT3_TBIT) // route tag
604 605 606 607
    len += 4;
  if (*body->rest & 0xFFFF) // referenced LS type field
    len += 4;

608
  if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_ext3) + len))
609 610 611 612 613 614
    return 0;

  return 1;
}

static int
615
lsa_validate_pxlist(struct ospf_lsa_header *lsa, u32 pxcount, uint offset, u8 *pbuf)
616
{
617
  uint bound = lsa->length - HDRLEN - 4;
618 619 620 621 622 623 624 625 626 627
  u32 i;

  for (i = 0; i < pxcount; i++)
    {
      if (offset > bound)
	return 0;

      u8 pxl = pxlen((u32 *) (pbuf + offset));
      if (pxl > MAX_PREFIX_LENGTH)
	return 0;
628

629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666
      offset += IPV6_PREFIX_SPACE(pxl);
    }

  if (lsa->length != (HDRLEN + offset))
    return 0;

  return 1;
}

static int
lsa_validate_link(struct ospf_lsa_header *lsa, struct ospf_lsa_link *body)
{
  if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_link)))
    return 0;

  return lsa_validate_pxlist(lsa, body->pxcount, sizeof(struct ospf_lsa_link), (u8 *) body);
}

static int
lsa_validate_prefix(struct ospf_lsa_header *lsa, struct ospf_lsa_prefix *body)
{
  if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_prefix)))
    return 0;

  return lsa_validate_pxlist(lsa, body->pxcount, sizeof(struct ospf_lsa_prefix), (u8 *) body);
}


/**
 * lsa_validate - check whether given LSA is valid
 * @lsa: LSA header
 * @body: pointer to LSA body
 *
 * Checks internal structure of given LSA body (minimal length,
 * consistency). Returns true if valid.
 */

int
667
lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body)
668
{
669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
  if (ospf2)
  {
    switch (lsa_type)
    {
    case LSA_T_RT:
      return lsa_validate_rt2(lsa, body);
    case LSA_T_NET:
      return lsa_validate_net(lsa, body);
    case LSA_T_SUM_NET:
      return lsa_validate_sum2(lsa, body);
    case LSA_T_SUM_RT:
      return lsa_validate_sum2(lsa, body);
    case LSA_T_EXT:
    case LSA_T_NSSA:
      return lsa_validate_ext2(lsa, body);
    default:
      return 0;	/* Should not happen, unknown LSAs are already rejected */
    }
  }
  else
  {
    switch (lsa_type)
691 692
    {
    case LSA_T_RT:
693
      return lsa_validate_rt3(lsa, body);
694 695 696
    case LSA_T_NET:
      return lsa_validate_net(lsa, body);
    case LSA_T_SUM_NET:
697
      return lsa_validate_sum3_net(lsa, body);
698
    case LSA_T_SUM_RT:
699
      return lsa_validate_sum3_rt(lsa, body);
700
    case LSA_T_EXT:
701
    case LSA_T_NSSA:
702
      return lsa_validate_ext3(lsa, body);
703 704 705 706 707
    case LSA_T_LINK:
      return lsa_validate_link(lsa, body);
    case LSA_T_PREFIX:
      return lsa_validate_prefix(lsa, body);
    default:
708
      return 1;	/* Unknown LSAs are OK in OSPFv3 */
709
    }
710
  }
711
}