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