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