1 /* 2 * Copyright (c) 1998-2007 The TCPDUMP project 3 * Copyright (c) 2009 Florian Forster 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that: (1) source code 7 * distributions retain the above copyright notice and this paragraph 8 * in its entirety, and (2) distributions including binary code include 9 * the above copyright notice and this paragraph in its entirety in 10 * the documentation or other materials provided with the distribution. 11 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 12 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT 13 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 14 * FOR A PARTICULAR PURPOSE. 15 * 16 * Original code by Hannes Gredler <hannes@gredler.at> 17 * IPv6 additions by Florian Forster <octo at verplant.org> 18 */ 19 20 /* \summary: Optimized Link State Routing Protocol (OLSR) printer */ 21 22 /* specification: RFC 3626 */ 23 24 #include <sys/cdefs.h> 25 #ifndef lint 26 __RCSID("$NetBSD: print-olsr.c,v 1.4 2017/09/08 14:01:13 christos Exp $"); 27 #endif 28 29 #ifdef HAVE_CONFIG_H 30 #include "config.h" 31 #endif 32 33 #include <netdissect-stdinc.h> 34 35 #include "netdissect.h" 36 #include "addrtoname.h" 37 #include "extract.h" 38 39 /* 40 * RFC 3626 common header 41 * 42 * 0 1 2 3 43 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 44 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 45 * | Packet Length | Packet Sequence Number | 46 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 47 * | Message Type | Vtime | Message Size | 48 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 49 * | Originator Address | 50 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 51 * | Time To Live | Hop Count | Message Sequence Number | 52 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 53 * | | 54 * : MESSAGE : 55 * | | 56 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 57 * | Message Type | Vtime | Message Size | 58 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 59 * | Originator Address | 60 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 61 * | Time To Live | Hop Count | Message Sequence Number | 62 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 63 * | | 64 * : MESSAGE : 65 * | | 66 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 67 * : : 68 */ 69 70 struct olsr_common { 71 uint8_t packet_len[2]; 72 uint8_t packet_seq[2]; 73 }; 74 75 #define OLSR_HELLO_MSG 1 /* rfc3626 */ 76 #define OLSR_TC_MSG 2 /* rfc3626 */ 77 #define OLSR_MID_MSG 3 /* rfc3626 */ 78 #define OLSR_HNA_MSG 4 /* rfc3626 */ 79 #define OLSR_POWERINFO_MSG 128 80 #define OLSR_NAMESERVICE_MSG 130 81 #define OLSR_HELLO_LQ_MSG 201 /* LQ extensions olsr.org */ 82 #define OLSR_TC_LQ_MSG 202 /* LQ extensions olsr.org */ 83 84 static const struct tok olsr_msg_values[] = { 85 { OLSR_HELLO_MSG, "Hello" }, 86 { OLSR_TC_MSG, "TC" }, 87 { OLSR_MID_MSG, "MID" }, 88 { OLSR_HNA_MSG, "HNA" }, 89 { OLSR_POWERINFO_MSG, "Powerinfo" }, 90 { OLSR_NAMESERVICE_MSG, "Nameservice" }, 91 { OLSR_HELLO_LQ_MSG, "Hello-LQ" }, 92 { OLSR_TC_LQ_MSG, "TC-LQ" }, 93 { 0, NULL} 94 }; 95 96 struct olsr_msg4 { 97 uint8_t msg_type; 98 uint8_t vtime; 99 uint8_t msg_len[2]; 100 uint8_t originator[4]; 101 uint8_t ttl; 102 uint8_t hopcount; 103 uint8_t msg_seq[2]; 104 }; 105 106 struct olsr_msg6 { 107 uint8_t msg_type; 108 uint8_t vtime; 109 uint8_t msg_len[2]; 110 uint8_t originator[16]; 111 uint8_t ttl; 112 uint8_t hopcount; 113 uint8_t msg_seq[2]; 114 }; 115 116 struct olsr_hello { 117 uint8_t res[2]; 118 uint8_t htime; 119 uint8_t will; 120 }; 121 122 struct olsr_hello_link { 123 uint8_t link_code; 124 uint8_t res; 125 uint8_t len[2]; 126 }; 127 128 struct olsr_tc { 129 uint8_t ans_seq[2]; 130 uint8_t res[2]; 131 }; 132 133 struct olsr_hna4 { 134 uint8_t network[4]; 135 uint8_t mask[4]; 136 }; 137 138 struct olsr_hna6 { 139 uint8_t network[16]; 140 uint8_t mask[16]; 141 }; 142 143 144 /** gateway HNA flags */ 145 enum gateway_hna_flags { 146 GW_HNA_FLAG_LINKSPEED = 1 << 0, 147 GW_HNA_FLAG_IPV4 = 1 << 1, 148 GW_HNA_FLAG_IPV4_NAT = 1 << 2, 149 GW_HNA_FLAG_IPV6 = 1 << 3, 150 GW_HNA_FLAG_IPV6PREFIX = 1 << 4 151 }; 152 153 /** gateway HNA field byte offsets in the netmask field of the HNA */ 154 enum gateway_hna_fields { 155 GW_HNA_PAD = 0, 156 GW_HNA_FLAGS = 1, 157 GW_HNA_UPLINK = 2, 158 GW_HNA_DOWNLINK = 3, 159 GW_HNA_V6PREFIXLEN = 4, 160 GW_HNA_V6PREFIX = 5 161 }; 162 163 164 #define OLSR_EXTRACT_LINK_TYPE(link_code) (link_code & 0x3) 165 #define OLSR_EXTRACT_NEIGHBOR_TYPE(link_code) (link_code >> 2) 166 167 static const struct tok olsr_link_type_values[] = { 168 { 0, "Unspecified" }, 169 { 1, "Asymmetric" }, 170 { 2, "Symmetric" }, 171 { 3, "Lost" }, 172 { 0, NULL} 173 }; 174 175 static const struct tok olsr_neighbor_type_values[] = { 176 { 0, "Not-Neighbor" }, 177 { 1, "Symmetric" }, 178 { 2, "Symmetric-MPR" }, 179 { 0, NULL} 180 }; 181 182 struct olsr_lq_neighbor4 { 183 uint8_t neighbor[4]; 184 uint8_t link_quality; 185 uint8_t neighbor_link_quality; 186 uint8_t res[2]; 187 }; 188 189 struct olsr_lq_neighbor6 { 190 uint8_t neighbor[16]; 191 uint8_t link_quality; 192 uint8_t neighbor_link_quality; 193 uint8_t res[2]; 194 }; 195 196 #define MAX_SMARTGW_SPEED 320000000 197 198 /** 199 * Convert an encoded 1 byte transport value (5 bits mantissa, 3 bits exponent) 200 * to an uplink/downlink speed value 201 * 202 * @param value the encoded 1 byte transport value 203 * @return the uplink/downlink speed value (in kbit/s) 204 */ 205 static uint32_t deserialize_gw_speed(uint8_t value) { 206 uint32_t speed; 207 uint32_t exp; 208 209 if (!value) { 210 return 0; 211 } 212 213 if (value == UINT8_MAX) { 214 /* maximum value: also return maximum value */ 215 return MAX_SMARTGW_SPEED; 216 } 217 218 speed = (value >> 3) + 1; 219 exp = value & 7; 220 221 while (exp-- > 0) { 222 speed *= 10; 223 } 224 return speed; 225 } 226 227 /* 228 * macro to convert the 8-bit mantissa/exponent to a double float 229 * taken from olsr.org. 230 */ 231 #define VTIME_SCALE_FACTOR 0.0625 232 #define ME_TO_DOUBLE(me) \ 233 (double)(VTIME_SCALE_FACTOR*(1+(double)(me>>4)/16)*(double)(1<<(me&0x0F))) 234 235 /* 236 * print a neighbor list with LQ extensions. 237 */ 238 static int 239 olsr_print_lq_neighbor4(netdissect_options *ndo, 240 const u_char *msg_data, u_int hello_len) 241 { 242 const struct olsr_lq_neighbor4 *lq_neighbor; 243 244 while (hello_len >= sizeof(struct olsr_lq_neighbor4)) { 245 246 lq_neighbor = (const struct olsr_lq_neighbor4 *)msg_data; 247 if (!ND_TTEST(*lq_neighbor)) 248 return (-1); 249 250 ND_PRINT((ndo, "\n\t neighbor %s, link-quality %.2f%%" 251 ", neighbor-link-quality %.2f%%", 252 ipaddr_string(ndo, lq_neighbor->neighbor), 253 ((double)lq_neighbor->link_quality/2.55), 254 ((double)lq_neighbor->neighbor_link_quality/2.55))); 255 256 msg_data += sizeof(struct olsr_lq_neighbor4); 257 hello_len -= sizeof(struct olsr_lq_neighbor4); 258 } 259 return (0); 260 } 261 262 static int 263 olsr_print_lq_neighbor6(netdissect_options *ndo, 264 const u_char *msg_data, u_int hello_len) 265 { 266 const struct olsr_lq_neighbor6 *lq_neighbor; 267 268 while (hello_len >= sizeof(struct olsr_lq_neighbor6)) { 269 270 lq_neighbor = (const struct olsr_lq_neighbor6 *)msg_data; 271 if (!ND_TTEST(*lq_neighbor)) 272 return (-1); 273 274 ND_PRINT((ndo, "\n\t neighbor %s, link-quality %.2f%%" 275 ", neighbor-link-quality %.2f%%", 276 ip6addr_string(ndo, lq_neighbor->neighbor), 277 ((double)lq_neighbor->link_quality/2.55), 278 ((double)lq_neighbor->neighbor_link_quality/2.55))); 279 280 msg_data += sizeof(struct olsr_lq_neighbor6); 281 hello_len -= sizeof(struct olsr_lq_neighbor6); 282 } 283 return (0); 284 } 285 286 /* 287 * print a neighbor list. 288 */ 289 static int 290 olsr_print_neighbor(netdissect_options *ndo, 291 const u_char *msg_data, u_int hello_len) 292 { 293 int neighbor; 294 295 ND_PRINT((ndo, "\n\t neighbor\n\t\t")); 296 neighbor = 1; 297 298 while (hello_len >= sizeof(struct in_addr)) { 299 300 if (!ND_TTEST2(*msg_data, sizeof(struct in_addr))) 301 return (-1); 302 /* print 4 neighbors per line */ 303 304 ND_PRINT((ndo, "%s%s", ipaddr_string(ndo, msg_data), 305 neighbor % 4 == 0 ? "\n\t\t" : " ")); 306 307 msg_data += sizeof(struct in_addr); 308 hello_len -= sizeof(struct in_addr); 309 } 310 return (0); 311 } 312 313 314 void 315 olsr_print(netdissect_options *ndo, 316 const u_char *pptr, u_int length, int is_ipv6) 317 { 318 union { 319 const struct olsr_common *common; 320 const struct olsr_msg4 *msg4; 321 const struct olsr_msg6 *msg6; 322 const struct olsr_hello *hello; 323 const struct olsr_hello_link *hello_link; 324 const struct olsr_tc *tc; 325 const struct olsr_hna4 *hna; 326 } ptr; 327 328 u_int msg_type, msg_len, msg_tlen, hello_len; 329 uint16_t name_entry_type, name_entry_len; 330 u_int name_entry_padding; 331 uint8_t link_type, neighbor_type; 332 const u_char *tptr, *msg_data; 333 334 tptr = pptr; 335 336 if (length < sizeof(struct olsr_common)) { 337 goto trunc; 338 } 339 340 ND_TCHECK2(*tptr, sizeof(struct olsr_common)); 341 342 ptr.common = (const struct olsr_common *)tptr; 343 length = min(length, EXTRACT_16BITS(ptr.common->packet_len)); 344 345 ND_PRINT((ndo, "OLSRv%i, seq 0x%04x, length %u", 346 (is_ipv6 == 0) ? 4 : 6, 347 EXTRACT_16BITS(ptr.common->packet_seq), 348 length)); 349 350 tptr += sizeof(struct olsr_common); 351 352 /* 353 * In non-verbose mode, just print version. 354 */ 355 if (ndo->ndo_vflag < 1) { 356 return; 357 } 358 359 while (tptr < (pptr+length)) { 360 union 361 { 362 const struct olsr_msg4 *v4; 363 const struct olsr_msg6 *v6; 364 } msgptr; 365 int msg_len_valid = 0; 366 367 if (is_ipv6) 368 { 369 ND_TCHECK2(*tptr, sizeof(struct olsr_msg6)); 370 msgptr.v6 = (const struct olsr_msg6 *) tptr; 371 msg_type = msgptr.v6->msg_type; 372 msg_len = EXTRACT_16BITS(msgptr.v6->msg_len); 373 if ((msg_len >= sizeof (struct olsr_msg6)) 374 && (msg_len <= length)) 375 msg_len_valid = 1; 376 377 /* infinite loop check */ 378 if (msg_type == 0 || msg_len == 0) { 379 return; 380 } 381 382 ND_PRINT((ndo, "\n\t%s Message (%#04x), originator %s, ttl %u, hop %u" 383 "\n\t vtime %.3fs, msg-seq 0x%04x, length %u%s", 384 tok2str(olsr_msg_values, "Unknown", msg_type), 385 msg_type, ip6addr_string(ndo, msgptr.v6->originator), 386 msgptr.v6->ttl, 387 msgptr.v6->hopcount, 388 ME_TO_DOUBLE(msgptr.v6->vtime), 389 EXTRACT_16BITS(msgptr.v6->msg_seq), 390 msg_len, (msg_len_valid == 0) ? " (invalid)" : "")); 391 if (!msg_len_valid) { 392 return; 393 } 394 395 msg_tlen = msg_len - sizeof(struct olsr_msg6); 396 msg_data = tptr + sizeof(struct olsr_msg6); 397 } 398 else /* (!is_ipv6) */ 399 { 400 ND_TCHECK2(*tptr, sizeof(struct olsr_msg4)); 401 msgptr.v4 = (const struct olsr_msg4 *) tptr; 402 msg_type = msgptr.v4->msg_type; 403 msg_len = EXTRACT_16BITS(msgptr.v4->msg_len); 404 if ((msg_len >= sizeof (struct olsr_msg4)) 405 && (msg_len <= length)) 406 msg_len_valid = 1; 407 408 /* infinite loop check */ 409 if (msg_type == 0 || msg_len == 0) { 410 return; 411 } 412 413 ND_PRINT((ndo, "\n\t%s Message (%#04x), originator %s, ttl %u, hop %u" 414 "\n\t vtime %.3fs, msg-seq 0x%04x, length %u%s", 415 tok2str(olsr_msg_values, "Unknown", msg_type), 416 msg_type, ipaddr_string(ndo, msgptr.v4->originator), 417 msgptr.v4->ttl, 418 msgptr.v4->hopcount, 419 ME_TO_DOUBLE(msgptr.v4->vtime), 420 EXTRACT_16BITS(msgptr.v4->msg_seq), 421 msg_len, (msg_len_valid == 0) ? " (invalid)" : "")); 422 if (!msg_len_valid) { 423 return; 424 } 425 426 msg_tlen = msg_len - sizeof(struct olsr_msg4); 427 msg_data = tptr + sizeof(struct olsr_msg4); 428 } 429 430 switch (msg_type) { 431 case OLSR_HELLO_MSG: 432 case OLSR_HELLO_LQ_MSG: 433 if (msg_tlen < sizeof(struct olsr_hello)) 434 goto trunc; 435 ND_TCHECK2(*msg_data, sizeof(struct olsr_hello)); 436 437 ptr.hello = (const struct olsr_hello *)msg_data; 438 ND_PRINT((ndo, "\n\t hello-time %.3fs, MPR willingness %u", 439 ME_TO_DOUBLE(ptr.hello->htime), ptr.hello->will)); 440 msg_data += sizeof(struct olsr_hello); 441 msg_tlen -= sizeof(struct olsr_hello); 442 443 while (msg_tlen >= sizeof(struct olsr_hello_link)) { 444 int hello_len_valid = 0; 445 446 /* 447 * link-type. 448 */ 449 ND_TCHECK2(*msg_data, sizeof(struct olsr_hello_link)); 450 451 ptr.hello_link = (const struct olsr_hello_link *)msg_data; 452 453 hello_len = EXTRACT_16BITS(ptr.hello_link->len); 454 link_type = OLSR_EXTRACT_LINK_TYPE(ptr.hello_link->link_code); 455 neighbor_type = OLSR_EXTRACT_NEIGHBOR_TYPE(ptr.hello_link->link_code); 456 457 if ((hello_len <= msg_tlen) 458 && (hello_len >= sizeof(struct olsr_hello_link))) 459 hello_len_valid = 1; 460 461 ND_PRINT((ndo, "\n\t link-type %s, neighbor-type %s, len %u%s", 462 tok2str(olsr_link_type_values, "Unknown", link_type), 463 tok2str(olsr_neighbor_type_values, "Unknown", neighbor_type), 464 hello_len, 465 (hello_len_valid == 0) ? " (invalid)" : "")); 466 467 if (hello_len_valid == 0) 468 break; 469 470 msg_data += sizeof(struct olsr_hello_link); 471 msg_tlen -= sizeof(struct olsr_hello_link); 472 hello_len -= sizeof(struct olsr_hello_link); 473 474 ND_TCHECK2(*msg_data, hello_len); 475 if (msg_type == OLSR_HELLO_MSG) { 476 if (olsr_print_neighbor(ndo, msg_data, hello_len) == -1) 477 goto trunc; 478 } else { 479 if (is_ipv6) { 480 if (olsr_print_lq_neighbor6(ndo, msg_data, hello_len) == -1) 481 goto trunc; 482 } else { 483 if (olsr_print_lq_neighbor4(ndo, msg_data, hello_len) == -1) 484 goto trunc; 485 } 486 } 487 488 msg_data += hello_len; 489 msg_tlen -= hello_len; 490 } 491 break; 492 493 case OLSR_TC_MSG: 494 case OLSR_TC_LQ_MSG: 495 if (msg_tlen < sizeof(struct olsr_tc)) 496 goto trunc; 497 ND_TCHECK2(*msg_data, sizeof(struct olsr_tc)); 498 499 ptr.tc = (const struct olsr_tc *)msg_data; 500 ND_PRINT((ndo, "\n\t advertised neighbor seq 0x%04x", 501 EXTRACT_16BITS(ptr.tc->ans_seq))); 502 msg_data += sizeof(struct olsr_tc); 503 msg_tlen -= sizeof(struct olsr_tc); 504 505 if (msg_type == OLSR_TC_MSG) { 506 if (olsr_print_neighbor(ndo, msg_data, msg_tlen) == -1) 507 goto trunc; 508 } else { 509 if (is_ipv6) { 510 if (olsr_print_lq_neighbor6(ndo, msg_data, msg_tlen) == -1) 511 goto trunc; 512 } else { 513 if (olsr_print_lq_neighbor4(ndo, msg_data, msg_tlen) == -1) 514 goto trunc; 515 } 516 } 517 break; 518 519 case OLSR_MID_MSG: 520 { 521 size_t addr_size = sizeof(struct in_addr); 522 523 if (is_ipv6) 524 addr_size = sizeof(struct in6_addr); 525 526 while (msg_tlen >= addr_size) { 527 ND_TCHECK2(*msg_data, addr_size); 528 ND_PRINT((ndo, "\n\t interface address %s", 529 is_ipv6 ? ip6addr_string(ndo, msg_data) : 530 ipaddr_string(ndo, msg_data))); 531 532 msg_data += addr_size; 533 msg_tlen -= addr_size; 534 } 535 break; 536 } 537 538 case OLSR_HNA_MSG: 539 if (is_ipv6) 540 { 541 int i = 0; 542 543 ND_PRINT((ndo, "\n\t Advertised networks (total %u)", 544 (unsigned int) (msg_tlen / sizeof(struct olsr_hna6)))); 545 546 while (msg_tlen >= sizeof(struct olsr_hna6)) { 547 const struct olsr_hna6 *hna6; 548 549 ND_TCHECK2(*msg_data, sizeof(struct olsr_hna6)); 550 551 hna6 = (const struct olsr_hna6 *)msg_data; 552 553 ND_PRINT((ndo, "\n\t #%i: %s/%u", 554 i, ip6addr_string(ndo, hna6->network), 555 mask62plen (hna6->mask))); 556 557 msg_data += sizeof(struct olsr_hna6); 558 msg_tlen -= sizeof(struct olsr_hna6); 559 } 560 } 561 else 562 { 563 int col = 0; 564 565 ND_PRINT((ndo, "\n\t Advertised networks (total %u)", 566 (unsigned int) (msg_tlen / sizeof(struct olsr_hna4)))); 567 568 while (msg_tlen >= sizeof(struct olsr_hna4)) { 569 ND_TCHECK2(*msg_data, sizeof(struct olsr_hna4)); 570 571 ptr.hna = (const struct olsr_hna4 *)msg_data; 572 573 /* print 4 prefixes per line */ 574 if (!ptr.hna->network[0] && !ptr.hna->network[1] && 575 !ptr.hna->network[2] && !ptr.hna->network[3] && 576 !ptr.hna->mask[GW_HNA_PAD] && 577 ptr.hna->mask[GW_HNA_FLAGS]) { 578 /* smart gateway */ 579 ND_PRINT((ndo, "%sSmart-Gateway:%s%s%s%s%s %u/%u", 580 col == 0 ? "\n\t " : ", ", /* indent */ 581 /* sgw */ 582 /* LINKSPEED */ 583 (ptr.hna->mask[GW_HNA_FLAGS] & 584 GW_HNA_FLAG_LINKSPEED) ? " LINKSPEED" : "", 585 /* IPV4 */ 586 (ptr.hna->mask[GW_HNA_FLAGS] & 587 GW_HNA_FLAG_IPV4) ? " IPV4" : "", 588 /* IPV4-NAT */ 589 (ptr.hna->mask[GW_HNA_FLAGS] & 590 GW_HNA_FLAG_IPV4_NAT) ? " IPV4-NAT" : "", 591 /* IPV6 */ 592 (ptr.hna->mask[GW_HNA_FLAGS] & 593 GW_HNA_FLAG_IPV6) ? " IPV6" : "", 594 /* IPv6PREFIX */ 595 (ptr.hna->mask[GW_HNA_FLAGS] & 596 GW_HNA_FLAG_IPV6PREFIX) ? " IPv6-PREFIX" : "", 597 /* uplink */ 598 (ptr.hna->mask[GW_HNA_FLAGS] & 599 GW_HNA_FLAG_LINKSPEED) ? 600 deserialize_gw_speed(ptr.hna->mask[GW_HNA_UPLINK]) : 0, 601 /* downlink */ 602 (ptr.hna->mask[GW_HNA_FLAGS] & 603 GW_HNA_FLAG_LINKSPEED) ? 604 deserialize_gw_speed(ptr.hna->mask[GW_HNA_DOWNLINK]) : 0 605 )); 606 } else { 607 /* normal route */ 608 ND_PRINT((ndo, "%s%s/%u", 609 col == 0 ? "\n\t " : ", ", 610 ipaddr_string(ndo, ptr.hna->network), 611 mask2plen(EXTRACT_32BITS(ptr.hna->mask)))); 612 } 613 614 msg_data += sizeof(struct olsr_hna4); 615 msg_tlen -= sizeof(struct olsr_hna4); 616 617 col = (col + 1) % 4; 618 } 619 } 620 break; 621 622 case OLSR_NAMESERVICE_MSG: 623 { 624 u_int name_entries; 625 u_int addr_size; 626 int name_entries_valid; 627 u_int i; 628 629 if (msg_tlen < 4) 630 goto trunc; 631 ND_TCHECK2(*msg_data, 4); 632 633 name_entries = EXTRACT_16BITS(msg_data+2); 634 addr_size = 4; 635 if (is_ipv6) 636 addr_size = 16; 637 638 name_entries_valid = 0; 639 if ((name_entries > 0) 640 && ((name_entries * (4 + addr_size)) <= msg_tlen)) 641 name_entries_valid = 1; 642 643 ND_PRINT((ndo, "\n\t Version %u, Entries %u%s", 644 EXTRACT_16BITS(msg_data), 645 name_entries, (name_entries_valid == 0) ? " (invalid)" : "")); 646 647 if (name_entries_valid == 0) 648 break; 649 650 msg_data += 4; 651 msg_tlen -= 4; 652 653 for (i = 0; i < name_entries; i++) { 654 int name_entry_len_valid = 0; 655 656 if (msg_tlen < 4) 657 break; 658 ND_TCHECK2(*msg_data, 4); 659 660 name_entry_type = EXTRACT_16BITS(msg_data); 661 name_entry_len = EXTRACT_16BITS(msg_data+2); 662 663 msg_data += 4; 664 msg_tlen -= 4; 665 666 if ((name_entry_len > 0) && ((addr_size + name_entry_len) <= msg_tlen)) 667 name_entry_len_valid = 1; 668 669 ND_PRINT((ndo, "\n\t #%u: type %#06x, length %u%s", 670 (unsigned int) i, name_entry_type, 671 name_entry_len, (name_entry_len_valid == 0) ? " (invalid)" : "")); 672 673 if (name_entry_len_valid == 0) 674 break; 675 676 /* 32-bit alignment */ 677 name_entry_padding = 0; 678 if (name_entry_len%4 != 0) 679 name_entry_padding = 4-(name_entry_len%4); 680 681 if (msg_tlen < addr_size + name_entry_len + name_entry_padding) 682 goto trunc; 683 684 ND_TCHECK2(*msg_data, addr_size + name_entry_len + name_entry_padding); 685 686 if (is_ipv6) 687 ND_PRINT((ndo, ", address %s, name \"", 688 ip6addr_string(ndo, msg_data))); 689 else 690 ND_PRINT((ndo, ", address %s, name \"", 691 ipaddr_string(ndo, msg_data))); 692 (void)fn_printn(ndo, msg_data + addr_size, name_entry_len, NULL); 693 ND_PRINT((ndo, "\"")); 694 695 msg_data += addr_size + name_entry_len + name_entry_padding; 696 msg_tlen -= addr_size + name_entry_len + name_entry_padding; 697 } /* for (i = 0; i < name_entries; i++) */ 698 break; 699 } /* case OLSR_NAMESERVICE_MSG */ 700 701 /* 702 * FIXME those are the defined messages that lack a decoder 703 * you are welcome to contribute code ;-) 704 */ 705 case OLSR_POWERINFO_MSG: 706 default: 707 print_unknown_data(ndo, msg_data, "\n\t ", msg_tlen); 708 break; 709 } /* switch (msg_type) */ 710 tptr += msg_len; 711 } /* while (tptr < (pptr+length)) */ 712 713 return; 714 715 trunc: 716 ND_PRINT((ndo, "[|olsr]")); 717 } 718 719 /* 720 * Local Variables: 721 * c-style: whitesmith 722 * c-basic-offset: 4 723 * End: 724 */ 725