lsalib.c 14.7 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"

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 66 67 68 69 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


int
lsa_flooding_allowed(u32 type, u32 domain, struct ospf_iface *ifa)
{   
  /* Handle inactive vlinks */
  if (ifa->state == OSPF_IS_DOWN)
    return 0;
 
  /* 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
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);
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
}

/*
 * Note, that this function expects that LSA is in big endianity
 * It also returns value in big endian
 */
u16
221
lsasum_check(struct ospf_lsa_header *h, void *body)
222 223 224 225
{
  u8 *sp, *ep, *p, *q, *b;
  int c0 = 0, c1 = 0;
  int x, y;
226
  u16 length;
227

228
  b = body;
229
  sp = (char *) h;
230
  sp += 2; /* Skip Age field */
Ondřej Filip's avatar
Ondřej Filip committed
231
  length = ntohs(h->length) - 2;
232
  h->checksum = 0;
233 234

  for (ep = sp + length; sp < ep; sp = q)
Ondřej Filip's avatar
Ondřej Filip committed
235
  {				/* Actually MODX is very large, do we need the for-cyclus? */
236
    q = sp + MODX;
Ondřej Filip's avatar
Ondřej Filip committed
237 238
    if (q > ep)
      q = ep;
239
    for (p = sp; p < q; p++)
240
    {
241 242 243 244 245 246
      /* 
       * 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
247
      if ((b == NULL) || (p < (u8 *) (h + 1)))
248
      {
Ondřej Filip's avatar
Ondřej Filip committed
249
	c0 += *p;
250 251 252
      }
      else
      {
253
	c0 += *(b + (p - (u8 *) (h + 1)));
254 255 256
      }

      c1 += c0;
257
    }
258 259 260
    c0 %= 255;
    c1 %= 255;
  }
261

262
  x = (int)((length - LSA_CHECKSUM_OFFSET) * c0 - c1) % 255;
Ondřej Filip's avatar
Ondřej Filip committed
263 264
  if (x <= 0)
    x += 255;
265
  y = 510 - c0 - x;
Ondřej Filip's avatar
Ondřej Filip committed
266 267
  if (y > 255)
    y -= 255;
268

Ondřej Filip's avatar
Ondřej Filip committed
269 270
  ((u8 *) & h->checksum)[0] = x;
  ((u8 *) & h->checksum)[1] = y;
271
  return h->checksum;
272 273
}

274 275
int
lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2)
276
			/* Return codes from point of view of l1 */
277
{
Ondřej Filip's avatar
Ondřej Filip committed
278
  u32 sn1, sn2;
279

Ondřej Filip's avatar
Ondřej Filip committed
280 281
  sn1 = l1->sn - LSA_INITSEQNO + 1;
  sn2 = l2->sn - LSA_INITSEQNO + 1;
282

Ondřej Filip's avatar
Ondřej Filip committed
283 284 285 286
  if (sn1 > sn2)
    return CMP_NEWER;
  if (sn1 < sn2)
    return CMP_OLDER;
Ondřej Filip's avatar
Ondřej Filip committed
287

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

Ondřej Filip's avatar
Ondřej Filip committed
291 292 293 294
  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
295

Ondřej Filip's avatar
Ondřej Filip committed
296 297
  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
298 299

  return CMP_SAME;
300 301
}

302

303 304
static inline int
lsa_walk_rt2(struct ospf_lsa_rt_walk *rt)
305
{
306
  if (rt->buf >= rt->bufend)
307 308
    return 0;

309 310
  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);
311

312 313 314 315 316 317
  rt->type = l->type;
  rt->metric = l->metric;
  rt->id = l->id;
  rt->data = l->data;
  return 1;
}
318

319 320 321 322
static inline int
lsa_walk_rt3(struct ospf_lsa_rt_walk *rt)
{
  while (rt->buf >= rt->bufend)
323
  {
324 325
    rt->en = ospf_hash_find_rt3_next(rt->en);
    if (!rt->en)
326
      return 0;
327 328 329 330

    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);
331
  }
332 333 334 335 336 337 338 339 340

  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;
341 342 343
  return 1;
}

344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 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
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);
    else 
      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)

445
static int
446
lsa_validate_rt2(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body)
447
{
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
  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)
473 474 475 476 477 478 479
    return 0;

  return 1;
}


static int
480
lsa_validate_rt3(struct ospf_lsa_header *lsa, struct ospf_lsa_rt *body)
481
{
482
  if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_rt)))
483 484
    return 0;

485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
  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)))
509 510 511 512 513 514
    return 0;

  return 1;
}

static int
515
lsa_validate_sum2(struct ospf_lsa_header *lsa, struct ospf_lsa_sum2 *body)
516
{
517
  if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum2)))
518 519 520
    return 0;

  /* First field should have TOS = 0, we ignore other TOS fields */
521
  if ((body->metric & LSA_SUM2_TOS) != 0)
522 523 524 525 526 527 528 529 530 531 532 533
    return 0;

  return 1;
}

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

static int
534
lsa_validate_sum3_net(struct ospf_lsa_header *lsa, struct ospf_lsa_sum3_net *body)
535
{
536
  if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_sum3_net) + 4))
537 538 539 540 541 542
    return 0;

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

543
  if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_sum3_net) + 
544 545 546 547 548 549
		      IPV6_PREFIX_SPACE(pxl)))
    return 0;

  return 1;
}

550 551 552 553 554 555 556 557
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;
}
558 559

static int
560
lsa_validate_ext2(struct ospf_lsa_header *lsa, struct ospf_lsa_ext2 *body)
561
{
562 563 564 565 566
  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)
567 568 569 570 571 572
    return 0;

  return 1;
}

static int
573
lsa_validate_ext3(struct ospf_lsa_header *lsa, struct ospf_lsa_ext3 *body)
574
{
575
  if (lsa->length < (HDRLEN + sizeof(struct ospf_lsa_ext3) + 4))
576 577 578 579 580 581 582
    return 0;

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

  int len = IPV6_PREFIX_SPACE(pxl);
583
  if (body->metric & LSA_EXT3_FBIT) // forwardinf address
584
    len += 16;
585
  if (body->metric & LSA_EXT3_TBIT) // route tag
586 587 588 589
    len += 4;
  if (*body->rest & 0xFFFF) // referenced LS type field
    len += 4;

590
  if (lsa->length != (HDRLEN + sizeof(struct ospf_lsa_ext3) + len))
591 592 593 594 595 596
    return 0;

  return 1;
}

static int
597
lsa_validate_pxlist(struct ospf_lsa_header *lsa, u32 pxcount, uint offset, u8 *pbuf)
598
{
599
  uint bound = lsa->length - HDRLEN - 4;
600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648
  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;
  
      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
649
lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body)
650
{
651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672
  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)
673 674
    {
    case LSA_T_RT:
675
      return lsa_validate_rt3(lsa, body);
676 677 678
    case LSA_T_NET:
      return lsa_validate_net(lsa, body);
    case LSA_T_SUM_NET:
679
      return lsa_validate_sum3_net(lsa, body);
680
    case LSA_T_SUM_RT:
681
      return lsa_validate_sum3_rt(lsa, body);
682
    case LSA_T_EXT:
683
    case LSA_T_NSSA:
684
      return lsa_validate_ext3(lsa, body);
685 686 687 688 689
    case LSA_T_LINK:
      return lsa_validate_link(lsa, body);
    case LSA_T_PREFIX:
      return lsa_validate_prefix(lsa, body);
    default:
690
      return 1;	/* Unknown LSAs are OK in OSPFv3 */
691
    }
692
  }
693
}