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 * Optimized Link State Protocl (OLSR) as per rfc3626 17 * 18 * Original code by Hannes Gredler <hannes (at) juniper.net> 19 * IPv6 additions by Florian Forster <octo at verplant.org> 20 */ 21 22 #ifdef HAVE_CONFIG_H 23 #include "config.h" 24 #endif 25 26 #include <tcpdump-stdinc.h> 27 28 #include <stdio.h> 29 #include <string.h> 30 31 #include "interface.h" 32 #include "addrtoname.h" 33 #include "extract.h" 34 #include "ip.h" 35 36 /* 37 * RFC 3626 common header 38 * 39 * 0 1 2 3 40 * 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 41 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 42 * | Packet Length | Packet Sequence Number | 43 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 44 * | Message Type | Vtime | Message Size | 45 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 46 * | Originator Address | 47 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 48 * | Time To Live | Hop Count | Message Sequence Number | 49 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 50 * | | 51 * : MESSAGE : 52 * | | 53 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 54 * | Message Type | Vtime | Message Size | 55 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 56 * | Originator Address | 57 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 58 * | Time To Live | Hop Count | Message Sequence Number | 59 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 60 * | | 61 * : MESSAGE : 62 * | | 63 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 64 * : : 65 */ 66 67 struct olsr_common { 68 u_int8_t packet_len[2]; 69 u_int8_t packet_seq[2]; 70 }; 71 72 #define OLSR_HELLO_MSG 1 /* rfc3626 */ 73 #define OLSR_TC_MSG 2 /* rfc3626 */ 74 #define OLSR_MID_MSG 3 /* rfc3626 */ 75 #define OLSR_HNA_MSG 4 /* rfc3626 */ 76 #define OLSR_POWERINFO_MSG 128 77 #define OLSR_NAMESERVICE_MSG 130 78 #define OLSR_HELLO_LQ_MSG 201 /* LQ extensions olsr.org */ 79 #define OLSR_TC_LQ_MSG 202 /* LQ extensions olsr.org */ 80 81 static const struct tok olsr_msg_values[] = { 82 { OLSR_HELLO_MSG, "Hello" }, 83 { OLSR_TC_MSG, "TC" }, 84 { OLSR_MID_MSG, "MID" }, 85 { OLSR_HNA_MSG, "HNA" }, 86 { OLSR_POWERINFO_MSG, "Powerinfo" }, 87 { OLSR_NAMESERVICE_MSG, "Nameservice" }, 88 { OLSR_HELLO_LQ_MSG, "Hello-LQ" }, 89 { OLSR_TC_LQ_MSG, "TC-LQ" }, 90 { 0, NULL} 91 }; 92 93 struct olsr_msg4 { 94 u_int8_t msg_type; 95 u_int8_t vtime; 96 u_int8_t msg_len[2]; 97 u_int8_t originator[4]; 98 u_int8_t ttl; 99 u_int8_t hopcount; 100 u_int8_t msg_seq[2]; 101 }; 102 103 struct olsr_msg6 { 104 u_int8_t msg_type; 105 u_int8_t vtime; 106 u_int8_t msg_len[2]; 107 u_int8_t originator[16]; 108 u_int8_t ttl; 109 u_int8_t hopcount; 110 u_int8_t msg_seq[2]; 111 }; 112 113 struct olsr_hello { 114 u_int8_t res[2]; 115 u_int8_t htime; 116 u_int8_t will; 117 }; 118 119 struct olsr_hello_link { 120 u_int8_t link_code; 121 u_int8_t res; 122 u_int8_t len[2]; 123 }; 124 125 struct olsr_tc { 126 u_int8_t ans_seq[2]; 127 u_int8_t res[2]; 128 }; 129 130 struct olsr_hna4 { 131 u_int8_t network[4]; 132 u_int8_t mask[4]; 133 }; 134 135 struct olsr_hna6 { 136 u_int8_t network[16]; 137 u_int8_t mask[16]; 138 }; 139 140 141 #define OLSR_EXTRACT_LINK_TYPE(link_code) (link_code & 0x3) 142 #define OLSR_EXTRACT_NEIGHBOR_TYPE(link_code) (link_code >> 2) 143 144 static const struct tok olsr_link_type_values[] = { 145 { 0, "Unspecified" }, 146 { 1, "Asymmetric" }, 147 { 2, "Symmetric" }, 148 { 3, "Lost" }, 149 { 0, NULL} 150 }; 151 152 static const struct tok olsr_neighbor_type_values[] = { 153 { 0, "Not-Neighbor" }, 154 { 1, "Symmetric" }, 155 { 2, "Symmetric-MPR" }, 156 { 0, NULL} 157 }; 158 159 struct olsr_lq_neighbor4 { 160 u_int8_t neighbor[4]; 161 u_int8_t link_quality; 162 u_int8_t neighbor_link_quality; 163 u_int8_t res[2]; 164 }; 165 166 struct olsr_lq_neighbor6 { 167 u_int8_t neighbor[16]; 168 u_int8_t link_quality; 169 u_int8_t neighbor_link_quality; 170 u_int8_t res[2]; 171 }; 172 173 /* 174 * macro to convert the 8-bit mantissa/exponent to a double float 175 * taken from olsr.org. 176 */ 177 #define VTIME_SCALE_FACTOR 0.0625 178 #define ME_TO_DOUBLE(me) \ 179 (double)(VTIME_SCALE_FACTOR*(1+(double)(me>>4)/16)*(double)(1<<(me&0x0F))) 180 181 /* 182 * print a neighbor list with LQ extensions. 183 */ 184 static void 185 olsr_print_lq_neighbor4 (const u_char *msg_data, u_int hello_len) 186 { 187 struct olsr_lq_neighbor4 *lq_neighbor; 188 189 while (hello_len >= sizeof(struct olsr_lq_neighbor4)) { 190 191 lq_neighbor = (struct olsr_lq_neighbor4 *)msg_data; 192 193 printf("\n\t neighbor %s, link-quality %.2lf%%" 194 ", neighbor-link-quality %.2lf%%", 195 ipaddr_string(lq_neighbor->neighbor), 196 ((double)lq_neighbor->link_quality/2.55), 197 ((double)lq_neighbor->neighbor_link_quality/2.55)); 198 199 msg_data += sizeof(struct olsr_lq_neighbor4); 200 hello_len -= sizeof(struct olsr_lq_neighbor4); 201 } 202 } 203 204 #if INET6 205 static void 206 olsr_print_lq_neighbor6 (const u_char *msg_data, u_int hello_len) 207 { 208 struct olsr_lq_neighbor6 *lq_neighbor; 209 210 while (hello_len >= sizeof(struct olsr_lq_neighbor6)) { 211 212 lq_neighbor = (struct olsr_lq_neighbor6 *)msg_data; 213 214 printf("\n\t neighbor %s, link-quality %.2lf%%" 215 ", neighbor-link-quality %.2lf%%", 216 ip6addr_string(lq_neighbor->neighbor), 217 ((double)lq_neighbor->link_quality/2.55), 218 ((double)lq_neighbor->neighbor_link_quality/2.55)); 219 220 msg_data += sizeof(struct olsr_lq_neighbor6); 221 hello_len -= sizeof(struct olsr_lq_neighbor6); 222 } 223 } 224 #endif /* INET6 */ 225 226 /* 227 * print a neighbor list. 228 */ 229 static void 230 olsr_print_neighbor (const u_char *msg_data, u_int hello_len) 231 { 232 int neighbor; 233 234 printf("\n\t neighbor\n\t\t"); 235 neighbor = 1; 236 237 while (hello_len >= sizeof(struct in_addr)) { 238 239 /* print 4 neighbors per line */ 240 241 printf("%s%s", ipaddr_string(msg_data), 242 neighbor % 4 == 0 ? "\n\t\t" : " "); 243 244 msg_data += sizeof(struct in_addr); 245 hello_len -= sizeof(struct in_addr); 246 } 247 } 248 249 250 void 251 olsr_print (const u_char *pptr, u_int length, int is_ipv6) 252 { 253 union { 254 const struct olsr_common *common; 255 const struct olsr_msg4 *msg4; 256 const struct olsr_msg6 *msg6; 257 const struct olsr_hello *hello; 258 const struct olsr_hello_link *hello_link; 259 const struct olsr_tc *tc; 260 const struct olsr_hna4 *hna; 261 } ptr; 262 263 u_int msg_type, msg_len, msg_tlen, hello_len; 264 u_int16_t name_entry_type, name_entry_len; 265 u_int name_entry_padding; 266 u_int8_t link_type, neighbor_type; 267 const u_char *tptr, *msg_data; 268 269 tptr = pptr; 270 271 if (length < sizeof(struct olsr_common)) { 272 goto trunc; 273 } 274 275 if (!TTEST2(*tptr, sizeof(struct olsr_common))) { 276 goto trunc; 277 } 278 279 ptr.common = (struct olsr_common *)tptr; 280 length = MIN(length, EXTRACT_16BITS(ptr.common->packet_len)); 281 282 printf("OLSRv%i, seq 0x%04x, length %u", 283 (is_ipv6 == 0) ? 4 : 6, 284 EXTRACT_16BITS(ptr.common->packet_seq), 285 length); 286 287 tptr += sizeof(struct olsr_common); 288 289 /* 290 * In non-verbose mode, just print version. 291 */ 292 if (vflag < 1) { 293 return; 294 } 295 296 while (tptr < (pptr+length)) { 297 union 298 { 299 struct olsr_msg4 *v4; 300 struct olsr_msg6 *v6; 301 } msgptr; 302 int msg_len_valid = 0; 303 304 if (!TTEST2(*tptr, sizeof(struct olsr_msg4))) 305 goto trunc; 306 307 #if INET6 308 if (is_ipv6) 309 { 310 msgptr.v6 = (struct olsr_msg6 *) tptr; 311 msg_type = msgptr.v6->msg_type; 312 msg_len = EXTRACT_16BITS(msgptr.v6->msg_len); 313 if ((msg_len >= sizeof (struct olsr_msg6)) 314 && (msg_len <= length)) 315 msg_len_valid = 1; 316 317 /* infinite loop check */ 318 if (msg_type == 0 || msg_len == 0) { 319 return; 320 } 321 322 printf("\n\t%s Message (%#04x), originator %s, ttl %u, hop %u" 323 "\n\t vtime %.3lfs, msg-seq 0x%04x, length %u%s", 324 tok2str(olsr_msg_values, "Unknown", msg_type), 325 msg_type, ip6addr_string(msgptr.v6->originator), 326 msgptr.v6->ttl, 327 msgptr.v6->hopcount, 328 ME_TO_DOUBLE(msgptr.v6->vtime), 329 EXTRACT_16BITS(msgptr.v6->msg_seq), 330 msg_len, (msg_len_valid == 0) ? " (invalid)" : ""); 331 332 msg_tlen = msg_len - sizeof(struct olsr_msg6); 333 msg_data = tptr + sizeof(struct olsr_msg6); 334 } 335 else /* (!is_ipv6) */ 336 #endif /* INET6 */ 337 { 338 msgptr.v4 = (struct olsr_msg4 *) tptr; 339 msg_type = msgptr.v4->msg_type; 340 msg_len = EXTRACT_16BITS(msgptr.v4->msg_len); 341 if ((msg_len >= sizeof (struct olsr_msg4)) 342 && (msg_len <= length)) 343 msg_len_valid = 1; 344 345 /* infinite loop check */ 346 if (msg_type == 0 || msg_len == 0) { 347 return; 348 } 349 350 printf("\n\t%s Message (%#04x), originator %s, ttl %u, hop %u" 351 "\n\t vtime %.3lfs, msg-seq 0x%04x, length %u%s", 352 tok2str(olsr_msg_values, "Unknown", msg_type), 353 msg_type, ipaddr_string(msgptr.v4->originator), 354 msgptr.v4->ttl, 355 msgptr.v4->hopcount, 356 ME_TO_DOUBLE(msgptr.v4->vtime), 357 EXTRACT_16BITS(msgptr.v4->msg_seq), 358 msg_len, (msg_len_valid == 0) ? " (invalid)" : ""); 359 360 msg_tlen = msg_len - sizeof(struct olsr_msg4); 361 msg_data = tptr + sizeof(struct olsr_msg4); 362 } 363 364 switch (msg_type) { 365 case OLSR_HELLO_MSG: 366 case OLSR_HELLO_LQ_MSG: 367 if (!TTEST2(*msg_data, sizeof(struct olsr_hello))) 368 goto trunc; 369 370 ptr.hello = (struct olsr_hello *)msg_data; 371 printf("\n\t hello-time %.3lfs, MPR willingness %u", 372 ME_TO_DOUBLE(ptr.hello->htime), ptr.hello->will); 373 msg_data += sizeof(struct olsr_hello); 374 msg_tlen -= sizeof(struct olsr_hello); 375 376 while (msg_tlen >= sizeof(struct olsr_hello_link)) { 377 int hello_len_valid = 0; 378 379 /* 380 * link-type. 381 */ 382 if (!TTEST2(*msg_data, sizeof(struct olsr_hello_link))) 383 goto trunc; 384 385 ptr.hello_link = (struct olsr_hello_link *)msg_data; 386 387 hello_len = EXTRACT_16BITS(ptr.hello_link->len); 388 link_type = OLSR_EXTRACT_LINK_TYPE(ptr.hello_link->link_code); 389 neighbor_type = OLSR_EXTRACT_NEIGHBOR_TYPE(ptr.hello_link->link_code); 390 391 if ((hello_len <= msg_tlen) 392 && (hello_len >= sizeof(struct olsr_hello_link))) 393 hello_len_valid = 1; 394 395 printf("\n\t link-type %s, neighbor-type %s, len %u%s", 396 tok2str(olsr_link_type_values, "Unknown", link_type), 397 tok2str(olsr_neighbor_type_values, "Unknown", neighbor_type), 398 hello_len, 399 (hello_len_valid == 0) ? " (invalid)" : ""); 400 401 if (hello_len_valid == 0) 402 break; 403 404 msg_data += sizeof(struct olsr_hello_link); 405 msg_tlen -= sizeof(struct olsr_hello_link); 406 hello_len -= sizeof(struct olsr_hello_link); 407 408 if (msg_type == OLSR_HELLO_MSG) { 409 olsr_print_neighbor(msg_data, hello_len); 410 } else { 411 #if INET6 412 if (is_ipv6) 413 olsr_print_lq_neighbor6(msg_data, hello_len); 414 else 415 #endif 416 olsr_print_lq_neighbor4(msg_data, hello_len); 417 } 418 419 msg_data += hello_len; 420 msg_tlen -= hello_len; 421 } 422 break; 423 424 case OLSR_TC_MSG: 425 case OLSR_TC_LQ_MSG: 426 if (!TTEST2(*msg_data, sizeof(struct olsr_tc))) 427 goto trunc; 428 429 ptr.tc = (struct olsr_tc *)msg_data; 430 printf("\n\t advertised neighbor seq 0x%04x", 431 EXTRACT_16BITS(ptr.tc->ans_seq)); 432 msg_data += sizeof(struct olsr_tc); 433 msg_tlen -= sizeof(struct olsr_tc); 434 435 if (msg_type == OLSR_TC_MSG) { 436 olsr_print_neighbor(msg_data, msg_tlen); 437 } else { 438 #if INET6 439 if (is_ipv6) 440 olsr_print_lq_neighbor6(msg_data, msg_tlen); 441 else 442 #endif 443 olsr_print_lq_neighbor4(msg_data, msg_tlen); 444 } 445 break; 446 447 case OLSR_MID_MSG: 448 { 449 size_t addr_size = sizeof(struct in_addr); 450 451 #if INET6 452 if (is_ipv6) 453 addr_size = sizeof(struct in6_addr); 454 #endif 455 456 while (msg_tlen >= addr_size) { 457 if (!TTEST2(*msg_data, addr_size)) 458 goto trunc; 459 460 printf("\n\t interface address %s", 461 #if INET6 462 is_ipv6 ? ip6addr_string(msg_data) : 463 #endif 464 ipaddr_string(msg_data)); 465 msg_data += addr_size; 466 msg_tlen -= addr_size; 467 } 468 break; 469 } 470 471 case OLSR_HNA_MSG: 472 printf("\n\t Advertised networks (total %u)", 473 (unsigned int) (msg_tlen / sizeof(struct olsr_hna6))); 474 #if INET6 475 if (is_ipv6) 476 { 477 int i = 0; 478 while (msg_tlen >= sizeof(struct olsr_hna6)) { 479 struct olsr_hna6 *hna6; 480 481 if (!TTEST2(*msg_data, sizeof(struct olsr_hna6))) 482 goto trunc; 483 484 hna6 = (struct olsr_hna6 *)msg_data; 485 486 printf("\n\t #%i: %s/%u", 487 i, ip6addr_string(hna6->network), 488 mask62plen (hna6->mask)); 489 490 msg_data += sizeof(struct olsr_hna6); 491 msg_tlen -= sizeof(struct olsr_hna6); 492 } 493 } 494 else 495 #endif 496 { 497 int col = 0; 498 while (msg_tlen >= sizeof(struct olsr_hna4)) { 499 if (!TTEST2(*msg_data, sizeof(struct olsr_hna4))) 500 goto trunc; 501 502 ptr.hna = (struct olsr_hna4 *)msg_data; 503 504 /* print 4 prefixes per line */ 505 if (col == 0) 506 printf ("\n\t "); 507 else 508 printf (", "); 509 510 printf("%s/%u", 511 ipaddr_string(ptr.hna->network), 512 mask2plen(EXTRACT_32BITS(ptr.hna->mask))); 513 514 msg_data += sizeof(struct olsr_hna4); 515 msg_tlen -= sizeof(struct olsr_hna4); 516 517 col = (col + 1) % 4; 518 } 519 } 520 break; 521 522 case OLSR_NAMESERVICE_MSG: 523 { 524 u_int name_entries = EXTRACT_16BITS(msg_data+2); 525 u_int addr_size = 4; 526 int name_entries_valid = 0; 527 u_int i; 528 529 if (is_ipv6) 530 addr_size = 16; 531 532 if ((name_entries > 0) 533 && ((name_entries * (4 + addr_size)) <= msg_tlen)) 534 name_entries_valid = 1; 535 536 if (msg_tlen < 4) 537 goto trunc; 538 if (!TTEST2(*msg_data, 4)) 539 goto trunc; 540 541 printf("\n\t Version %u, Entries %u%s", 542 EXTRACT_16BITS(msg_data), 543 name_entries, (name_entries_valid == 0) ? " (invalid)" : ""); 544 545 if (name_entries_valid == 0) 546 break; 547 548 msg_data += 4; 549 msg_tlen -= 4; 550 551 for (i = 0; i < name_entries; i++) { 552 int name_entry_len_valid = 0; 553 554 if (msg_tlen < 4) 555 break; 556 if (!TTEST2(*msg_data, 4)) 557 goto trunc; 558 559 name_entry_type = EXTRACT_16BITS(msg_data); 560 name_entry_len = EXTRACT_16BITS(msg_data+2); 561 562 msg_data += 4; 563 msg_tlen -= 4; 564 565 if ((name_entry_len > 0) && ((addr_size + name_entry_len) <= msg_tlen)) 566 name_entry_len_valid = 1; 567 568 printf("\n\t #%u: type %#06x, length %u%s", 569 (unsigned int) i, name_entry_type, 570 name_entry_len, (name_entry_len_valid == 0) ? " (invalid)" : ""); 571 572 if (name_entry_len_valid == 0) 573 break; 574 575 /* 32-bit alignment */ 576 name_entry_padding = 0; 577 if (name_entry_len%4 != 0) 578 name_entry_padding = 4-(name_entry_len%4); 579 580 if (msg_tlen < addr_size + name_entry_len + name_entry_padding) 581 goto trunc; 582 583 if (!TTEST2(*msg_data, addr_size + name_entry_len + name_entry_padding)) 584 goto trunc; 585 586 #if INET6 587 if (is_ipv6) 588 printf(", address %s, name \"", 589 ip6addr_string(msg_data)); 590 else 591 #endif 592 printf(", address %s, name \"", 593 ipaddr_string(msg_data)); 594 fn_printn(msg_data + addr_size, name_entry_len, NULL); 595 printf("\""); 596 597 msg_data += addr_size + name_entry_len + name_entry_padding; 598 msg_tlen -= addr_size + name_entry_len + name_entry_padding; 599 } /* for (i = 0; i < name_entries; i++) */ 600 break; 601 } /* case OLSR_NAMESERVICE_MSG */ 602 603 /* 604 * FIXME those are the defined messages that lack a decoder 605 * you are welcome to contribute code ;-) 606 */ 607 case OLSR_POWERINFO_MSG: 608 default: 609 print_unknown_data(msg_data, "\n\t ", msg_tlen); 610 break; 611 } /* switch (msg_type) */ 612 tptr += msg_len; 613 } /* while (tptr < (pptr+length)) */ 614 615 return; 616 617 trunc: 618 printf("[|olsr]"); 619 } 620 621 /* 622 * Local Variables: 623 * c-style: whitesmith 624 * c-basic-offset: 4 625 * End: 626 */ 627