1/* 2 * Copyright (c) 2007-2011 Gr��goire Henry, Juliusz Chroboczek 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. Neither the name of the project nor the names of its contributors 13 * may be used to endorse or promote products derived from this software 14 * without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30#ifndef lint 31__RCSID("$NetBSD: print-babel.c,v 1.5 2023/08/17 20:19:40 christos Exp $"); 32#endif 33 34/* \summary: Babel Routing Protocol printer */ 35/* Specifications: 36 * 37 * RFC 6126 38 * RFC 7298 39 * RFC 7557 40 * draft-ietf-babel-rfc6126bis-17 41 * draft-ietf-babel-hmac-10 42 * draft-ietf-babel-source-specific-0 43 */ 44 45#ifdef HAVE_CONFIG_H 46#include <config.h> 47#endif 48 49#include "netdissect-stdinc.h" 50 51#include <stdio.h> 52#include <string.h> 53 54#include "netdissect.h" 55#include "addrtoname.h" 56#include "extract.h" 57 58static void babel_print_v2(netdissect_options *, const u_char *cp, u_int length); 59 60void 61babel_print(netdissect_options *ndo, 62 const u_char *cp, u_int length) 63{ 64 ndo->ndo_protocol = "babel"; 65 ND_PRINT("babel"); 66 67 ND_TCHECK_4(cp); 68 69 if(GET_U_1(cp) != 42) { 70 ND_PRINT(" invalid header"); 71 return; 72 } else { 73 ND_PRINT(" %u", GET_U_1(cp + 1)); 74 } 75 76 switch(GET_U_1(cp + 1)) { 77 case 2: 78 babel_print_v2(ndo, cp, length); 79 break; 80 default: 81 ND_PRINT(" unknown version"); 82 break; 83 } 84 85 return; 86 87 trunc: 88 nd_print_trunc(ndo); 89} 90 91/* TLVs */ 92#define MESSAGE_PAD1 0 93#define MESSAGE_PADN 1 94#define MESSAGE_ACK_REQ 2 95#define MESSAGE_ACK 3 96#define MESSAGE_HELLO 4 97#define MESSAGE_IHU 5 98#define MESSAGE_ROUTER_ID 6 99#define MESSAGE_NH 7 100#define MESSAGE_UPDATE 8 101#define MESSAGE_ROUTE_REQUEST 9 102#define MESSAGE_SEQNO_REQUEST 10 103#define MESSAGE_TSPC 11 104#define MESSAGE_HMAC 12 105#define MESSAGE_UPDATE_SRC_SPECIFIC 13 /* last appearance in draft-boutier-babel-source-specific-01 */ 106#define MESSAGE_REQUEST_SRC_SPECIFIC 14 /* idem */ 107#define MESSAGE_MH_REQUEST_SRC_SPECIFIC 15 /* idem */ 108#define MESSAGE_MAC 16 109#define MESSAGE_PC 17 110#define MESSAGE_CHALLENGE_REQUEST 18 111#define MESSAGE_CHALLENGE_REPLY 19 112 113/* sub-TLVs */ 114#define MESSAGE_SUB_PAD1 0 115#define MESSAGE_SUB_PADN 1 116#define MESSAGE_SUB_DIVERSITY 2 117#define MESSAGE_SUB_TIMESTAMP 3 118 119/* "Mandatory" bit in sub-TLV types */ 120#define MANDATORY_MASK 0x80 121 122/* Flags for the Hello TLV */ 123#define UNICAST_MASK 0x8000 124 125/* Diversity sub-TLV channel codes */ 126static const struct tok diversity_str[] = { 127 { 0, "reserved" }, 128 { 255, "all" }, 129 { 0, NULL } 130}; 131 132static const char * 133format_id(netdissect_options *ndo, const u_char *id) 134{ 135 static char buf[25]; 136 snprintf(buf, 25, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", 137 GET_U_1(id), GET_U_1(id + 1), GET_U_1(id + 2), 138 GET_U_1(id + 3), GET_U_1(id + 4), GET_U_1(id + 5), 139 GET_U_1(id + 6), GET_U_1(id + 7)); 140 buf[24] = '\0'; 141 return buf; 142} 143 144static const unsigned char v4prefix[16] = 145 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }; 146 147static const char * 148format_prefix(netdissect_options *ndo, const u_char *prefix, unsigned char plen) 149{ 150 static char buf[50]; 151 152 /* 153 * prefix points to a buffer on the stack into which the prefix has 154 * been placed, so we can't use GET_IPADDR_STRING() or 155 * GET_IP6ADDR_STRING() on it. 156 */ 157 if(plen >= 96 && memcmp(prefix, v4prefix, 12) == 0) 158 snprintf(buf, 50, "%s/%u", ipaddr_string(ndo, prefix + 12), plen - 96); 159 else 160 snprintf(buf, 50, "%s/%u", ip6addr_string(ndo, prefix), plen); 161 buf[49] = '\0'; 162 return buf; 163} 164 165static const char * 166format_address(netdissect_options *ndo, const u_char *prefix) 167{ 168 /* 169 * prefix points to a buffer on the stack into which the prefix has 170 * been placed, so we can't use GET_IPADDR_STRING() or 171 * GET_IP6ADDR_STRING() on it. 172 */ 173 if(memcmp(prefix, v4prefix, 12) == 0) 174 return ipaddr_string(ndo, prefix + 12); 175 else 176 return ip6addr_string(ndo, prefix); 177} 178 179static const char * 180format_interval(const uint16_t i) 181{ 182 static char buf[sizeof("000.00s")]; 183 184 if (i == 0) 185 return "0.0s (bogus)"; 186 snprintf(buf, sizeof(buf), "%u.%02us", i / 100, i % 100); 187 return buf; 188} 189 190static const char * 191format_interval_update(const uint16_t i) 192{ 193 return i == 0xFFFF ? "infinity" : format_interval(i); 194} 195 196static const char * 197format_timestamp(const uint32_t i) 198{ 199 static char buf[sizeof("0000.000000s")]; 200 snprintf(buf, sizeof(buf), "%u.%06us", i / 1000000, i % 1000000); 201 return buf; 202} 203 204/* Return number of octets consumed from the input buffer (not the prefix length 205 * in bytes), or -1 for encoding error. */ 206static int 207network_prefix(int ae, int plen, unsigned int omitted, 208 const unsigned char *p, const unsigned char *dp, 209 unsigned int len, unsigned char *p_r) 210{ 211 unsigned pb; 212 unsigned char prefix[16]; 213 int consumed = 0; 214 215 if(plen >= 0) 216 pb = (plen + 7) / 8; 217 else if(ae == 1) 218 pb = 4; 219 else 220 pb = 16; 221 222 if(pb > 16) 223 return -1; 224 225 memset(prefix, 0, 16); 226 227 switch(ae) { 228 case 0: break; 229 case 1: 230 if(omitted > 4 || pb > 4 || (pb > omitted && len < pb - omitted)) 231 return -1; 232 memcpy(prefix, v4prefix, 12); 233 if(omitted) { 234 if (dp == NULL) return -1; 235 memcpy(prefix, dp, 12 + omitted); 236 } 237 if(pb > omitted) { 238 memcpy(prefix + 12 + omitted, p, pb - omitted); 239 consumed = pb - omitted; 240 } 241 break; 242 case 2: 243 if(omitted > 16 || (pb > omitted && len < pb - omitted)) 244 return -1; 245 if(omitted) { 246 if (dp == NULL) return -1; 247 memcpy(prefix, dp, omitted); 248 } 249 if(pb > omitted) { 250 memcpy(prefix + omitted, p, pb - omitted); 251 consumed = pb - omitted; 252 } 253 break; 254 case 3: 255 if(pb > 8 && len < pb - 8) return -1; 256 prefix[0] = 0xfe; 257 prefix[1] = 0x80; 258 if(pb > 8) { 259 memcpy(prefix + 8, p, pb - 8); 260 consumed = pb - 8; 261 } 262 break; 263 default: 264 return -1; 265 } 266 267 memcpy(p_r, prefix, 16); 268 return consumed; 269} 270 271static int 272network_address(int ae, const unsigned char *a, unsigned int len, 273 unsigned char *a_r) 274{ 275 return network_prefix(ae, -1, 0, a, NULL, len, a_r); 276} 277 278/* 279 * Sub-TLVs consume the "extra data" of Babel TLVs (see Section 4.3 of RFC6126), 280 * their encoding is similar to the encoding of TLVs, but the type namespace is 281 * different: 282 * 283 * o Type 0 stands for Pad1 sub-TLV with the same encoding as the Pad1 TLV. 284 * o Type 1 stands for PadN sub-TLV with the same encoding as the PadN TLV. 285 * o Type 2 stands for Diversity sub-TLV, which propagates diversity routing 286 * data. Its body is a variable-length sequence of 8-bit unsigned integers, 287 * each representing per-hop number of interfering radio channel for the 288 * prefix. Channel 0 is invalid and must not be used in the sub-TLV, channel 289 * 255 interferes with any other channel. 290 * o Type 3 stands for Timestamp sub-TLV, used to compute RTT between 291 * neighbours. In the case of a Hello TLV, the body stores a 32-bits 292 * timestamp, while in the case of a IHU TLV, two 32-bits timestamps are 293 * stored. 294 * 295 * Sub-TLV types 0 and 1 are valid for any TLV type, whether sub-TLV type 2 is 296 * only valid for TLV type 8 (Update). Note that within an Update TLV a missing 297 * Diversity sub-TLV is not the same as a Diversity sub-TLV with an empty body. 298 * The former would mean a lack of any claims about the interference, and the 299 * latter would state that interference is definitely absent. 300 * A type 3 sub-TLV is valid both for Hello and IHU TLVs, though the exact 301 * semantic of the sub-TLV is different in each case. 302 */ 303static void 304subtlvs_print(netdissect_options *ndo, 305 const u_char *cp, const u_char *ep, const uint8_t tlv_type) 306{ 307 uint8_t subtype, sublen; 308 const char *sep; 309 uint32_t t1, t2; 310 311 while (cp < ep) { 312 subtype = GET_U_1(cp); 313 cp++; 314 if(subtype == MESSAGE_SUB_PAD1) { 315 ND_PRINT(" sub-pad1"); 316 continue; 317 } 318 if ((MANDATORY_MASK & subtype) != 0) 319 ND_PRINT(" (M)"); 320 if(cp == ep) 321 goto invalid; 322 sublen = GET_U_1(cp); 323 cp++; 324 if(cp + sublen > ep) 325 goto invalid; 326 327 switch(subtype) { 328 case MESSAGE_SUB_PADN: 329 ND_PRINT(" sub-padn"); 330 cp += sublen; 331 break; 332 case MESSAGE_SUB_DIVERSITY: 333 ND_PRINT(" sub-diversity"); 334 if (sublen == 0) { 335 ND_PRINT(" empty"); 336 break; 337 } 338 sep = " "; 339 while (sublen) { 340 ND_PRINT("%s%s", sep, 341 tok2str(diversity_str, "%u", GET_U_1(cp))); 342 cp++; 343 sep = "-"; 344 sublen--; 345 } 346 if(tlv_type != MESSAGE_UPDATE && 347 tlv_type != MESSAGE_UPDATE_SRC_SPECIFIC) 348 ND_PRINT(" (bogus)"); 349 break; 350 case MESSAGE_SUB_TIMESTAMP: 351 ND_PRINT(" sub-timestamp"); 352 if(tlv_type == MESSAGE_HELLO) { 353 if(sublen < 4) 354 goto invalid; 355 t1 = GET_BE_U_4(cp); 356 ND_PRINT(" %s", format_timestamp(t1)); 357 } else if(tlv_type == MESSAGE_IHU) { 358 if(sublen < 8) 359 goto invalid; 360 t1 = GET_BE_U_4(cp); 361 ND_PRINT(" %s", format_timestamp(t1)); 362 t2 = GET_BE_U_4(cp + 4); 363 ND_PRINT("|%s", format_timestamp(t2)); 364 } else 365 ND_PRINT(" (bogus)"); 366 cp += sublen; 367 break; 368 default: 369 ND_PRINT(" sub-unknown-0x%02x", subtype); 370 cp += sublen; 371 } /* switch */ 372 } /* while */ 373 return; 374 375 invalid: 376 nd_print_invalid(ndo); 377} 378 379#define ICHECK(i, l) \ 380 if ((i) + (l) > tlvs_length || (i) + (l) > packet_length_remaining) \ 381 goto invalid; 382 383static int 384babel_print_v2_tlvs(netdissect_options *ndo, 385 const u_char *cp, u_int tlvs_length, 386 u_int packet_length_remaining) 387{ 388 u_int i; 389 u_char v4_prefix[16] = 390 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }; 391 u_char v6_prefix[16] = {0}; 392 393 i = 0; 394 while(i < tlvs_length) { 395 const u_char *message; 396 uint8_t type; 397 u_int len; 398 399 message = cp + i; 400 401 ICHECK(i, 1); 402 if((type = GET_U_1(message)) == MESSAGE_PAD1) { 403 ND_PRINT(ndo->ndo_vflag ? "\n\tPad 1" : " pad1"); 404 i += 1; 405 continue; 406 } 407 408 ICHECK(i, 2); 409 ND_TCHECK_2(message); 410 len = GET_U_1(message + 1); 411 412 ICHECK(i, 2 + len); 413 ND_TCHECK_LEN(message, 2 + len); 414 415 switch(type) { 416 case MESSAGE_PADN: { 417 if (!ndo->ndo_vflag) 418 ND_PRINT(" padN"); 419 else 420 ND_PRINT("\n\tPad %u", len + 2); 421 } 422 break; 423 424 case MESSAGE_ACK_REQ: { 425 u_short nonce, interval; 426 if (!ndo->ndo_vflag) 427 ND_PRINT(" ack-req"); 428 else { 429 ND_PRINT("\n\tAcknowledgment Request "); 430 if(len < 6) goto invalid; 431 nonce = GET_BE_U_2(message + 4); 432 interval = GET_BE_U_2(message + 6); 433 ND_PRINT("%04x %s", nonce, format_interval(interval)); 434 } 435 } 436 break; 437 438 case MESSAGE_ACK: { 439 u_short nonce; 440 if (!ndo->ndo_vflag) 441 ND_PRINT(" ack"); 442 else { 443 ND_PRINT("\n\tAcknowledgment "); 444 if(len < 2) goto invalid; 445 nonce = GET_BE_U_2(message + 2); 446 ND_PRINT("%04x", nonce); 447 } 448 } 449 break; 450 451 case MESSAGE_HELLO: { 452 u_short seqno, interval, unicast; 453 if (!ndo->ndo_vflag) 454 ND_PRINT(" hello"); 455 else { 456 ND_PRINT("\n\tHello "); 457 if(len < 6) goto invalid; 458 unicast = (GET_BE_U_2(message + 2) & UNICAST_MASK); 459 seqno = GET_BE_U_2(message + 4); 460 interval = GET_BE_U_2(message + 6); 461 if(unicast) 462 ND_PRINT("(Unicast) "); 463 ND_PRINT("seqno %u ", seqno); 464 if(interval!=0) 465 ND_PRINT("interval %s", format_interval(interval)); 466 else 467 ND_PRINT("unscheduled"); 468 /* Extra data. */ 469 if(len > 6) 470 subtlvs_print(ndo, message + 8, message + 2 + len, type); 471 } 472 } 473 break; 474 475 case MESSAGE_IHU: { 476 unsigned short rxcost, interval; 477 if (!ndo->ndo_vflag) 478 ND_PRINT(" ihu"); 479 else { 480 u_char address[16]; 481 u_char ae; 482 int rc; 483 ND_PRINT("\n\tIHU "); 484 if(len < 6) goto invalid; 485 rxcost = GET_BE_U_2(message + 4); 486 interval = GET_BE_U_2(message + 6); 487 ae = GET_U_1(message + 2); 488 rc = network_address(ae, message + 8, 489 len - 6, address); 490 if(rc < 0) { nd_print_trunc(ndo); break; } 491 ND_PRINT("%s rxcost %u interval %s", 492 ae == 0 ? "any" : format_address(ndo, address), 493 rxcost, format_interval(interval)); 494 /* Extra data. */ 495 if((u_int)rc < len - 6) 496 subtlvs_print(ndo, message + 8 + rc, message + 2 + len, 497 type); 498 } 499 } 500 break; 501 502 case MESSAGE_ROUTER_ID: { 503 if (!ndo->ndo_vflag) 504 ND_PRINT(" router-id"); 505 else { 506 ND_PRINT("\n\tRouter Id"); 507 if(len < 10) goto invalid; 508 ND_PRINT(" %s", format_id(ndo, message + 4)); 509 } 510 } 511 break; 512 513 case MESSAGE_NH: { 514 if (!ndo->ndo_vflag) 515 ND_PRINT(" nh"); 516 else { 517 int rc; 518 u_char ae; 519 u_char nh[16]; 520 ND_PRINT("\n\tNext Hop"); 521 if(len < 2) goto invalid; 522 ae = GET_U_1(message + 2); 523 rc = network_address(ae, message + 4, 524 len - 2, nh); 525 if(rc < 0) goto invalid; 526 ND_PRINT(" %s", ae == 0 ? "invalid AE 0" : format_address(ndo, nh)); 527 } 528 } 529 break; 530 531 case MESSAGE_UPDATE: { 532 if (!ndo->ndo_vflag) { 533 ND_PRINT(" update"); 534 if(len < 10) 535 goto invalid; 536 else 537 ND_PRINT("%s%s%s", 538 (GET_U_1(message + 3) & 0x80) ? "/prefix": "", 539 (GET_U_1(message + 3) & 0x40) ? "/id" : "", 540 (GET_U_1(message + 3) & 0x3f) ? "/unknown" : ""); 541 } else { 542 u_short interval, seqno, metric; 543 u_char ae, plen; 544 int rc; 545 u_char prefix[16]; 546 ND_PRINT("\n\tUpdate"); 547 if(len < 10) goto invalid; 548 ae = GET_U_1(message + 2); 549 plen = GET_U_1(message + 4) + (GET_U_1(message + 2) == 1 ? 96 : 0); 550 rc = network_prefix(ae, 551 GET_U_1(message + 4), 552 GET_U_1(message + 5), 553 message + 12, 554 GET_U_1(message + 2) == 1 ? v4_prefix : v6_prefix, 555 len - 10, prefix); 556 if(rc < 0) goto invalid; 557 interval = GET_BE_U_2(message + 6); 558 seqno = GET_BE_U_2(message + 8); 559 metric = GET_BE_U_2(message + 10); 560 ND_PRINT("%s%s%s %s metric %u seqno %u interval %s", 561 (GET_U_1(message + 3) & 0x80) ? "/prefix": "", 562 (GET_U_1(message + 3) & 0x40) ? "/id" : "", 563 (GET_U_1(message + 3) & 0x3f) ? "/unknown" : "", 564 ae == 0 ? "any" : format_prefix(ndo, prefix, plen), 565 metric, seqno, format_interval_update(interval)); 566 if(GET_U_1(message + 3) & 0x80) { 567 if(GET_U_1(message + 2) == 1) 568 memcpy(v4_prefix, prefix, 16); 569 else 570 memcpy(v6_prefix, prefix, 16); 571 } 572 /* extra data? */ 573 if((u_int)rc < len - 10) 574 subtlvs_print(ndo, message + 12 + rc, message + 2 + len, type); 575 } 576 } 577 break; 578 579 case MESSAGE_ROUTE_REQUEST: { 580 if (!ndo->ndo_vflag) 581 ND_PRINT(" route-request"); 582 else { 583 int rc; 584 u_char prefix[16], ae, plen; 585 ND_PRINT("\n\tRoute Request "); 586 if(len < 2) goto invalid; 587 ae = GET_U_1(message + 2); 588 plen = GET_U_1(message + 3) + (GET_U_1(message + 2) == 1 ? 96 : 0); 589 rc = network_prefix(ae, 590 GET_U_1(message + 3), 0, 591 message + 4, NULL, len - 2, prefix); 592 if(rc < 0) goto invalid; 593 ND_PRINT("for %s", 594 ae == 0 ? "any" : format_prefix(ndo, prefix, plen)); 595 } 596 } 597 break; 598 599 case MESSAGE_SEQNO_REQUEST : { 600 if (!ndo->ndo_vflag) 601 ND_PRINT(" seqno-request"); 602 else { 603 int rc; 604 u_short seqno; 605 u_char prefix[16], ae, plen; 606 ND_PRINT("\n\tSeqno Request "); 607 if(len < 14) goto invalid; 608 ae = GET_U_1(message + 2); 609 seqno = GET_BE_U_2(message + 4); 610 rc = network_prefix(ae, 611 GET_U_1(message + 3), 0, 612 message + 16, NULL, len - 14, prefix); 613 if(rc < 0) goto invalid; 614 plen = GET_U_1(message + 3) + (GET_U_1(message + 2) == 1 ? 96 : 0); 615 ND_PRINT("(%u hops) for %s seqno %u id %s", 616 GET_U_1(message + 6), 617 ae == 0 ? "invalid AE 0" : format_prefix(ndo, prefix, plen), 618 seqno, format_id(ndo, message + 8)); 619 } 620 } 621 break; 622 case MESSAGE_TSPC : 623 if (!ndo->ndo_vflag) 624 ND_PRINT(" tspc"); 625 else { 626 ND_PRINT("\n\tTS/PC "); 627 if(len < 6) goto invalid; 628 ND_PRINT("timestamp %u packetcounter %u", 629 GET_BE_U_4(message + 4), 630 GET_BE_U_2(message + 2)); 631 } 632 break; 633 case MESSAGE_HMAC : { 634 if (!ndo->ndo_vflag) 635 ND_PRINT(" hmac"); 636 else { 637 unsigned j; 638 ND_PRINT("\n\tHMAC "); 639 if(len < 18) goto invalid; 640 ND_PRINT("key-id %u digest-%u ", GET_BE_U_2(message + 2), 641 len - 2); 642 for (j = 0; j < len - 2; j++) 643 ND_PRINT("%02X", GET_U_1(message + j + 4)); 644 } 645 } 646 break; 647 648 case MESSAGE_UPDATE_SRC_SPECIFIC : { 649 if(!ndo->ndo_vflag) { 650 ND_PRINT(" ss-update"); 651 } else { 652 u_char prefix[16], src_prefix[16]; 653 u_short interval, seqno, metric; 654 u_char ae, plen, src_plen, omitted; 655 int rc; 656 int parsed_len = 10; 657 ND_PRINT("\n\tSS-Update"); 658 if(len < 10) goto invalid; 659 ae = GET_U_1(message + 2); 660 src_plen = GET_U_1(message + 3); 661 plen = GET_U_1(message + 4); 662 omitted = GET_U_1(message + 5); 663 interval = GET_BE_U_2(message + 6); 664 seqno = GET_BE_U_2(message + 8); 665 metric = GET_BE_U_2(message + 10); 666 rc = network_prefix(ae, plen, omitted, message + 2 + parsed_len, 667 ae == 1 ? v4_prefix : v6_prefix, 668 len - parsed_len, prefix); 669 if(rc < 0) goto invalid; 670 if(ae == 1) 671 plen += 96; 672 parsed_len += rc; 673 rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len, 674 NULL, len - parsed_len, src_prefix); 675 if(rc < 0) goto invalid; 676 if(ae == 1) 677 src_plen += 96; 678 parsed_len += rc; 679 680 ND_PRINT(" %s from", format_prefix(ndo, prefix, plen)); 681 ND_PRINT(" %s metric %u seqno %u interval %s", 682 format_prefix(ndo, src_prefix, src_plen), 683 metric, seqno, format_interval_update(interval)); 684 /* extra data? */ 685 if((u_int)parsed_len < len) 686 subtlvs_print(ndo, message + 2 + parsed_len, 687 message + 2 + len, type); 688 } 689 } 690 break; 691 692 case MESSAGE_REQUEST_SRC_SPECIFIC : { 693 if(!ndo->ndo_vflag) 694 ND_PRINT(" ss-request"); 695 else { 696 int rc, parsed_len = 3; 697 u_char ae, plen, src_plen, prefix[16], src_prefix[16]; 698 ND_PRINT("\n\tSS-Request "); 699 if(len < 3) goto invalid; 700 ae = GET_U_1(message + 2); 701 plen = GET_U_1(message + 3); 702 src_plen = GET_U_1(message + 4); 703 rc = network_prefix(ae, plen, 0, message + 2 + parsed_len, 704 NULL, len - parsed_len, prefix); 705 if(rc < 0) goto invalid; 706 if(ae == 1) 707 plen += 96; 708 parsed_len += rc; 709 rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len, 710 NULL, len - parsed_len, src_prefix); 711 if(rc < 0) goto invalid; 712 if(ae == 1) 713 src_plen += 96; 714 parsed_len += rc; 715 if(ae == 0) { 716 ND_PRINT("for any"); 717 } else { 718 ND_PRINT("for (%s, ", format_prefix(ndo, prefix, plen)); 719 ND_PRINT("%s)", format_prefix(ndo, src_prefix, src_plen)); 720 } 721 } 722 } 723 break; 724 725 case MESSAGE_MH_REQUEST_SRC_SPECIFIC : { 726 if(!ndo->ndo_vflag) 727 ND_PRINT(" ss-mh-request"); 728 else { 729 int rc, parsed_len = 14; 730 u_short seqno; 731 u_char ae, plen, src_plen, prefix[16], src_prefix[16], hopc; 732 const u_char *router_id = NULL; 733 ND_PRINT("\n\tSS-MH-Request "); 734 if(len < 14) goto invalid; 735 ae = GET_U_1(message + 2); 736 plen = GET_U_1(message + 3); 737 seqno = GET_BE_U_2(message + 4); 738 hopc = GET_U_1(message + 6); 739 src_plen = GET_U_1(message + 7); 740 router_id = message + 8; 741 rc = network_prefix(ae, plen, 0, message + 2 + parsed_len, 742 NULL, len - parsed_len, prefix); 743 if(rc < 0) goto invalid; 744 if(ae == 1) 745 plen += 96; 746 parsed_len += rc; 747 rc = network_prefix(ae, src_plen, 0, message + 2 + parsed_len, 748 NULL, len - parsed_len, src_prefix); 749 if(rc < 0) goto invalid; 750 if(ae == 1) 751 src_plen += 96; 752 ND_PRINT("(%u hops) for (%s, ", 753 hopc, format_prefix(ndo, prefix, plen)); 754 ND_PRINT("%s) seqno %u id %s", 755 format_prefix(ndo, src_prefix, src_plen), 756 seqno, format_id(ndo, router_id)); 757 } 758 } 759 break; 760 761 case MESSAGE_MAC: { 762 if (!ndo->ndo_vflag) 763 ND_PRINT(" mac"); 764 else { 765 ND_PRINT("\n\tMAC "); 766 ND_PRINT("len %u", len); 767 } 768 } 769 break; 770 771 case MESSAGE_PC: { 772 if (!ndo->ndo_vflag) 773 ND_PRINT(" pc"); 774 else { 775 ND_PRINT("\n\tPC"); 776 if(len < 4) goto invalid; 777 ND_PRINT(" value %u", 778 GET_BE_U_4(message + 2)); 779 ND_PRINT(" index len %u", len-4); 780 } 781 } 782 break; 783 784 case MESSAGE_CHALLENGE_REQUEST: { 785 if (!ndo->ndo_vflag) 786 ND_PRINT(" challenge_request"); 787 else { 788 ND_PRINT("\n\tChallenge Request"); 789 if(len > 192) goto invalid; 790 ND_PRINT(" len %u", len); 791 } 792 } 793 break; 794 795 case MESSAGE_CHALLENGE_REPLY: { 796 if (!ndo->ndo_vflag) 797 ND_PRINT(" challenge_reply"); 798 else { 799 ND_PRINT("\n\tChallenge Reply"); 800 if (len > 192) goto invalid; 801 ND_PRINT(" len %u", len); 802 } 803 } 804 break; 805 806 default: 807 if (!ndo->ndo_vflag) 808 ND_PRINT(" unknown"); 809 else 810 ND_PRINT("\n\tUnknown message type %u", type); 811 } 812 i += len + 2; 813 } 814 815 return 0; /* OK */ 816 817trunc: 818 return -1; /* packet truncated by capture process */ 819 820invalid: 821 return -2; /* packet is invalid */ 822} 823 824static void 825babel_print_v2(netdissect_options *ndo, 826 const u_char *cp, u_int length) 827{ 828 u_short bodylen; 829 int ret; 830 831 ND_TCHECK_4(cp); 832 if (length < 4) 833 goto invalid; 834 bodylen = GET_BE_U_2(cp + 2); 835 ND_PRINT(" (%u)", bodylen); 836 length -= 4; 837 cp += 4; 838 839 /* Process the TLVs in the body */ 840 if (length < bodylen) 841 goto invalid; 842 ret = babel_print_v2_tlvs(ndo, cp, bodylen, length); 843 if (ret == -1) 844 goto trunc; 845 if (ret == -2) 846 goto invalid; 847 length -= bodylen; 848 cp += bodylen; 849 850 /* If there's a trailer, process the TLVs in the trailer */ 851 if (length != 0) { 852 if(ndo->ndo_vflag) ND_PRINT("\n\t----"); 853 else ND_PRINT(" |"); 854 ret = babel_print_v2_tlvs(ndo, cp, length, length); 855 if (ret == -1) 856 goto trunc; 857 if (ret == -2) 858 goto invalid; 859 } 860 return; 861 862 trunc: 863 nd_print_trunc(ndo); 864 return; 865 866 invalid: 867 nd_print_invalid(ndo); 868} 869