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