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.5 2023/08/17 20:19:40 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 nd_uint16_t packet_len; 72 nd_uint16_t packet_seq; 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 nd_uint8_t msg_type; 98 nd_uint8_t vtime; 99 nd_uint16_t msg_len; 100 nd_ipv4 originator; 101 nd_uint8_t ttl; 102 nd_uint8_t hopcount; 103 nd_uint16_t msg_seq; 104 }; 105 106 struct olsr_msg6 { 107 nd_uint8_t msg_type; 108 nd_uint8_t vtime; 109 nd_uint16_t msg_len; 110 nd_ipv6 originator; 111 nd_uint8_t ttl; 112 nd_uint8_t hopcount; 113 nd_uint16_t msg_seq; 114 }; 115 116 struct olsr_hello { 117 nd_byte res[2]; 118 nd_uint8_t htime; 119 nd_uint8_t will; 120 }; 121 122 struct olsr_hello_link { 123 nd_uint8_t link_code; 124 nd_byte res; 125 nd_uint16_t len; 126 }; 127 128 struct olsr_tc { 129 nd_uint16_t ans_seq; 130 nd_byte res[2]; 131 }; 132 133 struct olsr_hna4 { 134 nd_ipv4 network; 135 nd_ipv4 mask; 136 }; 137 138 struct olsr_hna6 { 139 nd_ipv6 network; 140 nd_ipv6 mask; 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 nd_ipv4 neighbor; 184 nd_uint8_t link_quality; 185 nd_uint8_t neighbor_link_quality; 186 nd_byte res[2]; 187 }; 188 189 struct olsr_lq_neighbor6 { 190 nd_ipv6 neighbor; 191 nd_uint8_t link_quality; 192 nd_uint8_t neighbor_link_quality; 193 nd_byte 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 exp--; 224 } 225 return speed; 226 } 227 228 /* 229 * macro to convert the 8-bit mantissa/exponent to a double float 230 * taken from olsr.org. 231 */ 232 #define VTIME_SCALE_FACTOR 0.0625 233 #define ME_TO_DOUBLE(me) \ 234 (double)(VTIME_SCALE_FACTOR*(1+(double)(me>>4)/16)*(double)(1<<(me&0x0F))) 235 236 /* 237 * print a neighbor list with LQ extensions. 238 */ 239 static int 240 olsr_print_lq_neighbor4(netdissect_options *ndo, 241 const u_char *msg_data, u_int hello_len) 242 { 243 const struct olsr_lq_neighbor4 *lq_neighbor; 244 245 while (hello_len >= sizeof(struct olsr_lq_neighbor4)) { 246 247 lq_neighbor = (const struct olsr_lq_neighbor4 *)msg_data; 248 ND_TCHECK_SIZE(lq_neighbor); 249 250 ND_PRINT("\n\t neighbor %s, link-quality %.2f%%" 251 ", neighbor-link-quality %.2f%%", 252 GET_IPADDR_STRING(lq_neighbor->neighbor), 253 ((double) GET_U_1(lq_neighbor->link_quality)/2.55), 254 ((double) GET_U_1(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 trunc: 261 return -1; 262 } 263 264 static int 265 olsr_print_lq_neighbor6(netdissect_options *ndo, 266 const u_char *msg_data, u_int hello_len) 267 { 268 const struct olsr_lq_neighbor6 *lq_neighbor; 269 270 while (hello_len >= sizeof(struct olsr_lq_neighbor6)) { 271 272 lq_neighbor = (const struct olsr_lq_neighbor6 *)msg_data; 273 ND_TCHECK_SIZE(lq_neighbor); 274 275 ND_PRINT("\n\t neighbor %s, link-quality %.2f%%" 276 ", neighbor-link-quality %.2f%%", 277 GET_IP6ADDR_STRING(lq_neighbor->neighbor), 278 ((double) GET_U_1(lq_neighbor->link_quality)/2.55), 279 ((double) GET_U_1(lq_neighbor->neighbor_link_quality)/2.55)); 280 281 msg_data += sizeof(struct olsr_lq_neighbor6); 282 hello_len -= sizeof(struct olsr_lq_neighbor6); 283 } 284 return (0); 285 trunc: 286 return -1; 287 } 288 289 /* 290 * print a neighbor list. 291 */ 292 static int 293 olsr_print_neighbor(netdissect_options *ndo, 294 const u_char *msg_data, u_int hello_len) 295 { 296 int neighbor; 297 298 ND_PRINT("\n\t neighbor\n\t\t"); 299 neighbor = 1; 300 301 while (hello_len >= sizeof(nd_ipv4)) { 302 /* print 4 neighbors per line */ 303 ND_PRINT("%s%s", GET_IPADDR_STRING(msg_data), 304 neighbor % 4 == 0 ? "\n\t\t" : " "); 305 306 msg_data += sizeof(nd_ipv4); 307 hello_len -= sizeof(nd_ipv4); 308 } 309 return (0); 310 } 311 312 313 void 314 olsr_print(netdissect_options *ndo, 315 const u_char *pptr, u_int length, int is_ipv6) 316 { 317 union { 318 const struct olsr_common *common; 319 const struct olsr_msg4 *msg4; 320 const struct olsr_msg6 *msg6; 321 const struct olsr_hello *hello; 322 const struct olsr_hello_link *hello_link; 323 const struct olsr_tc *tc; 324 const struct olsr_hna4 *hna; 325 } ptr; 326 327 u_int msg_type, msg_len, msg_tlen, hello_len; 328 uint16_t name_entry_type, name_entry_len; 329 u_int name_entry_padding; 330 uint8_t link_type, neighbor_type; 331 const u_char *tptr, *msg_data; 332 333 ndo->ndo_protocol = "olsr"; 334 tptr = pptr; 335 336 nd_print_protocol_caps(ndo); 337 ND_PRINT("v%u", (is_ipv6) ? 6 : 4); 338 339 if (length < sizeof(struct olsr_common)) { 340 goto trunc; 341 } 342 343 ND_TCHECK_LEN(tptr, sizeof(struct olsr_common)); 344 345 ptr.common = (const struct olsr_common *)tptr; 346 length = ND_MIN(length, GET_BE_U_2(ptr.common->packet_len)); 347 348 ND_PRINT(", seq 0x%04x, length %u", 349 GET_BE_U_2(ptr.common->packet_seq), 350 length); 351 352 tptr += sizeof(struct olsr_common); 353 354 /* 355 * In non-verbose mode, just print version. 356 */ 357 if (ndo->ndo_vflag < 1) { 358 return; 359 } 360 361 while (tptr < (pptr+length)) { 362 union 363 { 364 const struct olsr_msg4 *v4; 365 const struct olsr_msg6 *v6; 366 } msgptr; 367 int msg_len_valid = 0; 368 369 if (is_ipv6) 370 { 371 ND_TCHECK_LEN(tptr, sizeof(struct olsr_msg6)); 372 msgptr.v6 = (const struct olsr_msg6 *) tptr; 373 msg_type = GET_U_1(msgptr.v6->msg_type); 374 msg_len = GET_BE_U_2(msgptr.v6->msg_len); 375 if ((msg_len >= sizeof (struct olsr_msg6)) 376 && (msg_len <= length)) 377 msg_len_valid = 1; 378 379 /* infinite loop check */ 380 if (msg_type == 0 || msg_len == 0) { 381 return; 382 } 383 384 ND_PRINT("\n\t%s Message (%#04x), originator %s, ttl %u, hop %u" 385 "\n\t vtime %.3fs, msg-seq 0x%04x, length %u%s", 386 tok2str(olsr_msg_values, "Unknown", msg_type), 387 msg_type, GET_IP6ADDR_STRING(msgptr.v6->originator), 388 GET_U_1(msgptr.v6->ttl), 389 GET_U_1(msgptr.v6->hopcount), 390 ME_TO_DOUBLE(GET_U_1(msgptr.v6->vtime)), 391 GET_BE_U_2(msgptr.v6->msg_seq), 392 msg_len, (msg_len_valid == 0) ? " (invalid)" : ""); 393 if (!msg_len_valid) { 394 return; 395 } 396 397 msg_tlen = msg_len - sizeof(struct olsr_msg6); 398 msg_data = tptr + sizeof(struct olsr_msg6); 399 } 400 else /* (!is_ipv6) */ 401 { 402 ND_TCHECK_LEN(tptr, sizeof(struct olsr_msg4)); 403 msgptr.v4 = (const struct olsr_msg4 *) tptr; 404 msg_type = GET_U_1(msgptr.v4->msg_type); 405 msg_len = GET_BE_U_2(msgptr.v4->msg_len); 406 if ((msg_len >= sizeof (struct olsr_msg4)) 407 && (msg_len <= length)) 408 msg_len_valid = 1; 409 410 /* infinite loop check */ 411 if (msg_type == 0 || msg_len == 0) { 412 return; 413 } 414 415 ND_PRINT("\n\t%s Message (%#04x), originator %s, ttl %u, hop %u" 416 "\n\t vtime %.3fs, msg-seq 0x%04x, length %u%s", 417 tok2str(olsr_msg_values, "Unknown", msg_type), 418 msg_type, GET_IPADDR_STRING(msgptr.v4->originator), 419 GET_U_1(msgptr.v4->ttl), 420 GET_U_1(msgptr.v4->hopcount), 421 ME_TO_DOUBLE(GET_U_1(msgptr.v4->vtime)), 422 GET_BE_U_2(msgptr.v4->msg_seq), 423 msg_len, (msg_len_valid == 0) ? " (invalid)" : ""); 424 if (!msg_len_valid) { 425 return; 426 } 427 428 msg_tlen = msg_len - sizeof(struct olsr_msg4); 429 msg_data = tptr + sizeof(struct olsr_msg4); 430 } 431 432 switch (msg_type) { 433 case OLSR_HELLO_MSG: 434 case OLSR_HELLO_LQ_MSG: 435 if (msg_tlen < sizeof(struct olsr_hello)) 436 goto trunc; 437 ND_TCHECK_LEN(msg_data, sizeof(struct olsr_hello)); 438 439 ptr.hello = (const struct olsr_hello *)msg_data; 440 ND_PRINT("\n\t hello-time %.3fs, MPR willingness %u", 441 ME_TO_DOUBLE(GET_U_1(ptr.hello->htime)), 442 GET_U_1(ptr.hello->will)); 443 msg_data += sizeof(struct olsr_hello); 444 msg_tlen -= sizeof(struct olsr_hello); 445 446 while (msg_tlen >= sizeof(struct olsr_hello_link)) { 447 int hello_len_valid = 0; 448 449 /* 450 * link-type. 451 */ 452 ND_TCHECK_LEN(msg_data, sizeof(struct olsr_hello_link)); 453 454 ptr.hello_link = (const struct olsr_hello_link *)msg_data; 455 456 hello_len = GET_BE_U_2(ptr.hello_link->len); 457 link_type = OLSR_EXTRACT_LINK_TYPE(GET_U_1(ptr.hello_link->link_code)); 458 neighbor_type = OLSR_EXTRACT_NEIGHBOR_TYPE(GET_U_1(ptr.hello_link->link_code)); 459 460 if ((hello_len <= msg_tlen) 461 && (hello_len >= sizeof(struct olsr_hello_link))) 462 hello_len_valid = 1; 463 464 ND_PRINT("\n\t link-type %s, neighbor-type %s, len %u%s", 465 tok2str(olsr_link_type_values, "Unknown", link_type), 466 tok2str(olsr_neighbor_type_values, "Unknown", neighbor_type), 467 hello_len, 468 (hello_len_valid == 0) ? " (invalid)" : ""); 469 470 if (hello_len_valid == 0) 471 break; 472 473 msg_data += sizeof(struct olsr_hello_link); 474 msg_tlen -= sizeof(struct olsr_hello_link); 475 hello_len -= sizeof(struct olsr_hello_link); 476 477 ND_TCHECK_LEN(msg_data, hello_len); 478 if (msg_type == OLSR_HELLO_MSG) { 479 if (olsr_print_neighbor(ndo, msg_data, hello_len) == -1) 480 goto trunc; 481 } else { 482 if (is_ipv6) { 483 if (olsr_print_lq_neighbor6(ndo, msg_data, hello_len) == -1) 484 goto trunc; 485 } else { 486 if (olsr_print_lq_neighbor4(ndo, msg_data, hello_len) == -1) 487 goto trunc; 488 } 489 } 490 491 msg_data += hello_len; 492 msg_tlen -= hello_len; 493 } 494 break; 495 496 case OLSR_TC_MSG: 497 case OLSR_TC_LQ_MSG: 498 if (msg_tlen < sizeof(struct olsr_tc)) 499 goto trunc; 500 ND_TCHECK_LEN(msg_data, sizeof(struct olsr_tc)); 501 502 ptr.tc = (const struct olsr_tc *)msg_data; 503 ND_PRINT("\n\t advertised neighbor seq 0x%04x", 504 GET_BE_U_2(ptr.tc->ans_seq)); 505 msg_data += sizeof(struct olsr_tc); 506 msg_tlen -= sizeof(struct olsr_tc); 507 508 if (msg_type == OLSR_TC_MSG) { 509 if (olsr_print_neighbor(ndo, msg_data, msg_tlen) == -1) 510 goto trunc; 511 } else { 512 if (is_ipv6) { 513 if (olsr_print_lq_neighbor6(ndo, msg_data, msg_tlen) == -1) 514 goto trunc; 515 } else { 516 if (olsr_print_lq_neighbor4(ndo, msg_data, msg_tlen) == -1) 517 goto trunc; 518 } 519 } 520 break; 521 522 case OLSR_MID_MSG: 523 { 524 u_int addr_size = (u_int)sizeof(nd_ipv4); 525 526 if (is_ipv6) 527 addr_size = (u_int)sizeof(nd_ipv6); 528 529 while (msg_tlen >= addr_size) { 530 ND_TCHECK_LEN(msg_data, addr_size); 531 ND_PRINT("\n\t interface address %s", 532 is_ipv6 ? GET_IP6ADDR_STRING(msg_data) : 533 GET_IPADDR_STRING(msg_data)); 534 535 msg_data += addr_size; 536 msg_tlen -= addr_size; 537 } 538 break; 539 } 540 541 case OLSR_HNA_MSG: 542 if (is_ipv6) 543 { 544 int i = 0; 545 546 ND_PRINT("\n\t Advertised networks (total %u)", 547 (unsigned int) (msg_tlen / sizeof(struct olsr_hna6))); 548 549 while (msg_tlen >= sizeof(struct olsr_hna6)) { 550 const struct olsr_hna6 *hna6; 551 552 ND_TCHECK_LEN(msg_data, sizeof(struct olsr_hna6)); 553 554 hna6 = (const struct olsr_hna6 *)msg_data; 555 556 ND_PRINT("\n\t #%i: %s/%u", 557 i, GET_IP6ADDR_STRING(hna6->network), 558 mask62plen (hna6->mask)); 559 560 msg_data += sizeof(struct olsr_hna6); 561 msg_tlen -= sizeof(struct olsr_hna6); 562 } 563 } 564 else 565 { 566 int col = 0; 567 568 ND_PRINT("\n\t Advertised networks (total %u)", 569 (unsigned int) (msg_tlen / sizeof(struct olsr_hna4))); 570 571 while (msg_tlen >= sizeof(struct olsr_hna4)) { 572 ND_TCHECK_LEN(msg_data, sizeof(struct olsr_hna4)); 573 574 ptr.hna = (const struct olsr_hna4 *)msg_data; 575 576 /* print 4 prefixes per line */ 577 if (!ptr.hna->network[0] && !ptr.hna->network[1] && 578 !ptr.hna->network[2] && !ptr.hna->network[3] && 579 !ptr.hna->mask[GW_HNA_PAD] && 580 ptr.hna->mask[GW_HNA_FLAGS]) { 581 /* smart gateway */ 582 ND_PRINT("%sSmart-Gateway:%s%s%s%s%s %u/%u", 583 col == 0 ? "\n\t " : ", ", /* indent */ 584 /* sgw */ 585 /* LINKSPEED */ 586 (ptr.hna->mask[GW_HNA_FLAGS] & 587 GW_HNA_FLAG_LINKSPEED) ? " LINKSPEED" : "", 588 /* IPV4 */ 589 (ptr.hna->mask[GW_HNA_FLAGS] & 590 GW_HNA_FLAG_IPV4) ? " IPV4" : "", 591 /* IPV4-NAT */ 592 (ptr.hna->mask[GW_HNA_FLAGS] & 593 GW_HNA_FLAG_IPV4_NAT) ? " IPV4-NAT" : "", 594 /* IPV6 */ 595 (ptr.hna->mask[GW_HNA_FLAGS] & 596 GW_HNA_FLAG_IPV6) ? " IPV6" : "", 597 /* IPv6PREFIX */ 598 (ptr.hna->mask[GW_HNA_FLAGS] & 599 GW_HNA_FLAG_IPV6PREFIX) ? " IPv6-PREFIX" : "", 600 /* uplink */ 601 (ptr.hna->mask[GW_HNA_FLAGS] & 602 GW_HNA_FLAG_LINKSPEED) ? 603 deserialize_gw_speed(ptr.hna->mask[GW_HNA_UPLINK]) : 0, 604 /* downlink */ 605 (ptr.hna->mask[GW_HNA_FLAGS] & 606 GW_HNA_FLAG_LINKSPEED) ? 607 deserialize_gw_speed(ptr.hna->mask[GW_HNA_DOWNLINK]) : 0 608 ); 609 } else { 610 /* normal route */ 611 ND_PRINT("%s%s/%u", 612 col == 0 ? "\n\t " : ", ", 613 GET_IPADDR_STRING(ptr.hna->network), 614 mask2plen(GET_BE_U_4(ptr.hna->mask))); 615 } 616 617 msg_data += sizeof(struct olsr_hna4); 618 msg_tlen -= sizeof(struct olsr_hna4); 619 620 col = (col + 1) % 4; 621 } 622 } 623 break; 624 625 case OLSR_NAMESERVICE_MSG: 626 { 627 u_int name_entries; 628 u_int addr_size; 629 int name_entries_valid; 630 u_int i; 631 632 if (msg_tlen < 4) 633 goto trunc; 634 635 name_entries = GET_BE_U_2(msg_data + 2); 636 addr_size = 4; 637 if (is_ipv6) 638 addr_size = 16; 639 640 name_entries_valid = 0; 641 if ((name_entries > 0) 642 && ((name_entries * (4 + addr_size)) <= msg_tlen)) 643 name_entries_valid = 1; 644 645 ND_PRINT("\n\t Version %u, Entries %u%s", 646 GET_BE_U_2(msg_data), 647 name_entries, (name_entries_valid == 0) ? " (invalid)" : ""); 648 649 if (name_entries_valid == 0) 650 break; 651 652 msg_data += 4; 653 msg_tlen -= 4; 654 655 for (i = 0; i < name_entries; i++) { 656 int name_entry_len_valid = 0; 657 658 if (msg_tlen < 4) 659 break; 660 661 name_entry_type = GET_BE_U_2(msg_data); 662 name_entry_len = GET_BE_U_2(msg_data + 2); 663 664 msg_data += 4; 665 msg_tlen -= 4; 666 667 if ((name_entry_len > 0) && ((addr_size + name_entry_len) <= msg_tlen)) 668 name_entry_len_valid = 1; 669 670 ND_PRINT("\n\t #%u: type %#06x, length %u%s", 671 (unsigned int) i, name_entry_type, 672 name_entry_len, (name_entry_len_valid == 0) ? " (invalid)" : ""); 673 674 if (name_entry_len_valid == 0) 675 break; 676 677 /* 32-bit alignment */ 678 name_entry_padding = 0; 679 if (name_entry_len%4 != 0) 680 name_entry_padding = 4-(name_entry_len%4); 681 682 if (msg_tlen < addr_size + name_entry_len + name_entry_padding) 683 goto trunc; 684 685 ND_TCHECK_LEN(msg_data, 686 addr_size + name_entry_len + name_entry_padding); 687 688 if (is_ipv6) 689 ND_PRINT(", address %s, name \"", 690 GET_IP6ADDR_STRING(msg_data)); 691 else 692 ND_PRINT(", address %s, name \"", 693 GET_IPADDR_STRING(msg_data)); 694 (void)nd_printn(ndo, msg_data + addr_size, name_entry_len, NULL); 695 ND_PRINT("\""); 696 697 msg_data += addr_size + name_entry_len + name_entry_padding; 698 msg_tlen -= addr_size + name_entry_len + name_entry_padding; 699 } /* for (i = 0; i < name_entries; i++) */ 700 break; 701 } /* case OLSR_NAMESERVICE_MSG */ 702 703 /* 704 * FIXME those are the defined messages that lack a decoder 705 * you are welcome to contribute code ;-) 706 */ 707 case OLSR_POWERINFO_MSG: 708 default: 709 print_unknown_data(ndo, msg_data, "\n\t ", msg_tlen); 710 break; 711 } /* switch (msg_type) */ 712 tptr += msg_len; 713 } /* while (tptr < (pptr+length)) */ 714 715 return; 716 717 trunc: 718 nd_print_trunc(ndo); 719 } 720