1 /* 2 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that: (1) source code distributions 7 * retain the above copyright notice and this paragraph in its entirety, (2) 8 * distributions including binary code include the above copyright notice and 9 * this paragraph in its entirety in the documentation or other materials 10 * provided with the distribution, and (3) all advertising materials mentioning 11 * features or use of this software display the following acknowledgement: 12 * ``This product includes software developed by the University of California, 13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 14 * the University nor the names of its contributors may be used to endorse 15 * or promote products derived from this software without specific prior 16 * written permission. 17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20 */ 21 22 #include <sys/cdefs.h> 23 #ifndef lint 24 __RCSID("$NetBSD: print-ip.c,v 1.12 2017/09/08 14:01:13 christos Exp $"); 25 #endif 26 27 /* \summary: IP printer */ 28 29 #ifdef HAVE_CONFIG_H 30 #include "config.h" 31 #endif 32 33 #include <netdissect-stdinc.h> 34 35 #include <string.h> 36 37 #include "netdissect.h" 38 #include "addrtoname.h" 39 #include "extract.h" 40 41 #include "ip.h" 42 #include "ipproto.h" 43 44 static const char tstr[] = "[|ip]"; 45 46 static const struct tok ip_option_values[] = { 47 { IPOPT_EOL, "EOL" }, 48 { IPOPT_NOP, "NOP" }, 49 { IPOPT_TS, "timestamp" }, 50 { IPOPT_SECURITY, "security" }, 51 { IPOPT_RR, "RR" }, 52 { IPOPT_SSRR, "SSRR" }, 53 { IPOPT_LSRR, "LSRR" }, 54 { IPOPT_RA, "RA" }, 55 { IPOPT_RFC1393, "traceroute" }, 56 { 0, NULL } 57 }; 58 59 /* 60 * print the recorded route in an IP RR, LSRR or SSRR option. 61 */ 62 static int 63 ip_printroute(netdissect_options *ndo, 64 register const u_char *cp, u_int length) 65 { 66 register u_int ptr; 67 register u_int len; 68 69 if (length < 3) { 70 ND_PRINT((ndo, " [bad length %u]", length)); 71 return (0); 72 } 73 if ((length + 1) & 3) 74 ND_PRINT((ndo, " [bad length %u]", length)); 75 ND_TCHECK(cp[2]); 76 ptr = cp[2] - 1; 77 if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1) 78 ND_PRINT((ndo, " [bad ptr %u]", cp[2])); 79 80 for (len = 3; len < length; len += 4) { 81 ND_TCHECK2(cp[len], 4); 82 ND_PRINT((ndo, " %s", ipaddr_string(ndo, &cp[len]))); 83 if (ptr > len) 84 ND_PRINT((ndo, ",")); 85 } 86 return (0); 87 88 trunc: 89 return (-1); 90 } 91 92 /* 93 * If source-routing is present and valid, return the final destination. 94 * Otherwise, return IP destination. 95 * 96 * This is used for UDP and TCP pseudo-header in the checksum 97 * calculation. 98 */ 99 static uint32_t 100 ip_finddst(netdissect_options *ndo, 101 const struct ip *ip) 102 { 103 int length; 104 int len; 105 const u_char *cp; 106 uint32_t retval; 107 108 cp = (const u_char *)(ip + 1); 109 length = (IP_HL(ip) << 2) - sizeof(struct ip); 110 111 for (; length > 0; cp += len, length -= len) { 112 int tt; 113 114 ND_TCHECK(*cp); 115 tt = *cp; 116 if (tt == IPOPT_EOL) 117 break; 118 else if (tt == IPOPT_NOP) 119 len = 1; 120 else { 121 ND_TCHECK(cp[1]); 122 len = cp[1]; 123 if (len < 2) 124 break; 125 } 126 ND_TCHECK2(*cp, len); 127 switch (tt) { 128 129 case IPOPT_SSRR: 130 case IPOPT_LSRR: 131 if (len < 7) 132 break; 133 UNALIGNED_MEMCPY(&retval, cp + len - 4, 4); 134 return retval; 135 } 136 } 137 trunc: 138 UNALIGNED_MEMCPY(&retval, &ip->ip_dst, sizeof(uint32_t)); 139 return retval; 140 } 141 142 /* 143 * Compute a V4-style checksum by building a pseudoheader. 144 */ 145 int 146 nextproto4_cksum(netdissect_options *ndo, 147 const struct ip *ip, const uint8_t *data, 148 u_int len, u_int covlen, u_int next_proto) 149 { 150 struct phdr { 151 uint32_t src; 152 uint32_t dst; 153 u_char mbz; 154 u_char proto; 155 uint16_t len; 156 } ph; 157 struct cksum_vec vec[2]; 158 159 /* pseudo-header.. */ 160 ph.len = htons((uint16_t)len); 161 ph.mbz = 0; 162 ph.proto = next_proto; 163 UNALIGNED_MEMCPY(&ph.src, &ip->ip_src, sizeof(uint32_t)); 164 if (IP_HL(ip) == 5) 165 UNALIGNED_MEMCPY(&ph.dst, &ip->ip_dst, sizeof(uint32_t)); 166 else 167 ph.dst = ip_finddst(ndo, ip); 168 169 vec[0].ptr = (const uint8_t *)(void *)&ph; 170 vec[0].len = sizeof(ph); 171 vec[1].ptr = data; 172 vec[1].len = covlen; 173 return (in_cksum(vec, 2)); 174 } 175 176 static int 177 ip_printts(netdissect_options *ndo, 178 register const u_char *cp, u_int length) 179 { 180 register u_int ptr; 181 register u_int len; 182 int hoplen; 183 const char *type; 184 185 if (length < 4) { 186 ND_PRINT((ndo, "[bad length %u]", length)); 187 return (0); 188 } 189 ND_PRINT((ndo, " TS{")); 190 hoplen = ((cp[3]&0xF) != IPOPT_TS_TSONLY) ? 8 : 4; 191 if ((length - 4) & (hoplen-1)) 192 ND_PRINT((ndo, "[bad length %u]", length)); 193 ND_TCHECK(cp[2]); 194 ptr = cp[2] - 1; 195 len = 0; 196 if (ptr < 4 || ((ptr - 4) & (hoplen-1)) || ptr > length + 1) 197 ND_PRINT((ndo, "[bad ptr %u]", cp[2])); 198 ND_TCHECK(cp[3]); 199 switch (cp[3]&0xF) { 200 case IPOPT_TS_TSONLY: 201 ND_PRINT((ndo, "TSONLY")); 202 break; 203 case IPOPT_TS_TSANDADDR: 204 ND_PRINT((ndo, "TS+ADDR")); 205 break; 206 /* 207 * prespecified should really be 3, but some ones might send 2 208 * instead, and the IPOPT_TS_PRESPEC constant can apparently 209 * have both values, so we have to hard-code it here. 210 */ 211 212 case 2: 213 ND_PRINT((ndo, "PRESPEC2.0")); 214 break; 215 case 3: /* IPOPT_TS_PRESPEC */ 216 ND_PRINT((ndo, "PRESPEC")); 217 break; 218 default: 219 ND_PRINT((ndo, "[bad ts type %d]", cp[3]&0xF)); 220 goto done; 221 } 222 223 type = " "; 224 for (len = 4; len < length; len += hoplen) { 225 if (ptr == len) 226 type = " ^ "; 227 ND_TCHECK2(cp[len], hoplen); 228 ND_PRINT((ndo, "%s%d@%s", type, EXTRACT_32BITS(&cp[len+hoplen-4]), 229 hoplen!=8 ? "" : ipaddr_string(ndo, &cp[len]))); 230 type = " "; 231 } 232 233 done: 234 ND_PRINT((ndo, "%s", ptr == len ? " ^ " : "")); 235 236 if (cp[3]>>4) 237 ND_PRINT((ndo, " [%d hops not recorded]} ", cp[3]>>4)); 238 else 239 ND_PRINT((ndo, "}")); 240 return (0); 241 242 trunc: 243 return (-1); 244 } 245 246 /* 247 * print IP options. 248 */ 249 static void 250 ip_optprint(netdissect_options *ndo, 251 register const u_char *cp, u_int length) 252 { 253 register u_int option_len; 254 const char *sep = ""; 255 256 for (; length > 0; cp += option_len, length -= option_len) { 257 u_int option_code; 258 259 ND_PRINT((ndo, "%s", sep)); 260 sep = ","; 261 262 ND_TCHECK(*cp); 263 option_code = *cp; 264 265 ND_PRINT((ndo, "%s", 266 tok2str(ip_option_values,"unknown %u",option_code))); 267 268 if (option_code == IPOPT_NOP || 269 option_code == IPOPT_EOL) 270 option_len = 1; 271 272 else { 273 ND_TCHECK(cp[1]); 274 option_len = cp[1]; 275 if (option_len < 2) { 276 ND_PRINT((ndo, " [bad length %u]", option_len)); 277 return; 278 } 279 } 280 281 if (option_len > length) { 282 ND_PRINT((ndo, " [bad length %u]", option_len)); 283 return; 284 } 285 286 ND_TCHECK2(*cp, option_len); 287 288 switch (option_code) { 289 case IPOPT_EOL: 290 return; 291 292 case IPOPT_TS: 293 if (ip_printts(ndo, cp, option_len) == -1) 294 goto trunc; 295 break; 296 297 case IPOPT_RR: /* fall through */ 298 case IPOPT_SSRR: 299 case IPOPT_LSRR: 300 if (ip_printroute(ndo, cp, option_len) == -1) 301 goto trunc; 302 break; 303 304 case IPOPT_RA: 305 if (option_len < 4) { 306 ND_PRINT((ndo, " [bad length %u]", option_len)); 307 break; 308 } 309 ND_TCHECK(cp[3]); 310 if (EXTRACT_16BITS(&cp[2]) != 0) 311 ND_PRINT((ndo, " value %u", EXTRACT_16BITS(&cp[2]))); 312 break; 313 314 case IPOPT_NOP: /* nothing to print - fall through */ 315 case IPOPT_SECURITY: 316 default: 317 break; 318 } 319 } 320 return; 321 322 trunc: 323 ND_PRINT((ndo, "%s", tstr)); 324 } 325 326 #define IP_RES 0x8000 327 328 static const struct tok ip_frag_values[] = { 329 { IP_MF, "+" }, 330 { IP_DF, "DF" }, 331 { IP_RES, "rsvd" }, /* The RFC3514 evil ;-) bit */ 332 { 0, NULL } 333 }; 334 335 struct ip_print_demux_state { 336 const struct ip *ip; 337 const u_char *cp; 338 u_int len, off; 339 u_char nh; 340 int advance; 341 }; 342 343 static void 344 ip_print_demux(netdissect_options *ndo, 345 struct ip_print_demux_state *ipds) 346 { 347 const char *p_name; 348 349 again: 350 switch (ipds->nh) { 351 352 case IPPROTO_AH: 353 if (!ND_TTEST(*ipds->cp)) { 354 ND_PRINT((ndo, "[|AH]")); 355 break; 356 } 357 ipds->nh = *ipds->cp; 358 ipds->advance = ah_print(ndo, ipds->cp); 359 if (ipds->advance <= 0) 360 break; 361 ipds->cp += ipds->advance; 362 ipds->len -= ipds->advance; 363 goto again; 364 365 case IPPROTO_ESP: 366 { 367 int enh, padlen; 368 ipds->advance = esp_print(ndo, ipds->cp, ipds->len, 369 (const u_char *)ipds->ip, 370 &enh, &padlen); 371 if (ipds->advance <= 0) 372 break; 373 ipds->cp += ipds->advance; 374 ipds->len -= ipds->advance + padlen; 375 ipds->nh = enh & 0xff; 376 goto again; 377 } 378 379 case IPPROTO_IPCOMP: 380 { 381 ipcomp_print(ndo, ipds->cp); 382 /* 383 * Either this has decompressed the payload and 384 * printed it, in which case there's nothing more 385 * to do, or it hasn't, in which case there's 386 * nothing more to do. 387 */ 388 break; 389 } 390 391 case IPPROTO_SCTP: 392 sctp_print(ndo, ipds->cp, (const u_char *)ipds->ip, ipds->len); 393 break; 394 395 case IPPROTO_DCCP: 396 dccp_print(ndo, ipds->cp, (const u_char *)ipds->ip, ipds->len); 397 break; 398 399 case IPPROTO_TCP: 400 /* pass on the MF bit plus the offset to detect fragments */ 401 tcp_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip, 402 ipds->off & (IP_MF|IP_OFFMASK)); 403 break; 404 405 case IPPROTO_UDP: 406 /* pass on the MF bit plus the offset to detect fragments */ 407 udp_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip, 408 ipds->off & (IP_MF|IP_OFFMASK)); 409 break; 410 411 case IPPROTO_ICMP: 412 /* pass on the MF bit plus the offset to detect fragments */ 413 icmp_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip, 414 ipds->off & (IP_MF|IP_OFFMASK)); 415 break; 416 417 case IPPROTO_PIGP: 418 /* 419 * XXX - the current IANA protocol number assignments 420 * page lists 9 as "any private interior gateway 421 * (used by Cisco for their IGRP)" and 88 as 422 * "EIGRP" from Cisco. 423 * 424 * Recent BSD <netinet/in.h> headers define 425 * IP_PROTO_PIGP as 9 and IP_PROTO_IGRP as 88. 426 * We define IP_PROTO_PIGP as 9 and 427 * IP_PROTO_EIGRP as 88; those names better 428 * match was the current protocol number 429 * assignments say. 430 */ 431 igrp_print(ndo, ipds->cp, ipds->len); 432 break; 433 434 case IPPROTO_EIGRP: 435 eigrp_print(ndo, ipds->cp, ipds->len); 436 break; 437 438 case IPPROTO_ND: 439 ND_PRINT((ndo, " nd %d", ipds->len)); 440 break; 441 442 case IPPROTO_EGP: 443 egp_print(ndo, ipds->cp, ipds->len); 444 break; 445 446 case IPPROTO_OSPF: 447 ospf_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip); 448 break; 449 450 case IPPROTO_IGMP: 451 igmp_print(ndo, ipds->cp, ipds->len); 452 break; 453 454 case IPPROTO_IPV4: 455 /* DVMRP multicast tunnel (ip-in-ip encapsulation) */ 456 ip_print(ndo, ipds->cp, ipds->len); 457 if (! ndo->ndo_vflag) { 458 ND_PRINT((ndo, " (ipip-proto-4)")); 459 return; 460 } 461 break; 462 463 case IPPROTO_IPV6: 464 /* ip6-in-ip encapsulation */ 465 ip6_print(ndo, ipds->cp, ipds->len); 466 break; 467 468 case IPPROTO_RSVP: 469 rsvp_print(ndo, ipds->cp, ipds->len); 470 break; 471 472 case IPPROTO_GRE: 473 /* do it */ 474 gre_print(ndo, ipds->cp, ipds->len); 475 break; 476 477 case IPPROTO_MOBILE: 478 mobile_print(ndo, ipds->cp, ipds->len); 479 break; 480 481 case IPPROTO_PIM: 482 pim_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip); 483 break; 484 485 case IPPROTO_VRRP: 486 if (ndo->ndo_packettype == PT_CARP) { 487 if (ndo->ndo_vflag) 488 ND_PRINT((ndo, "carp %s > %s: ", 489 ipaddr_string(ndo, &ipds->ip->ip_src), 490 ipaddr_string(ndo, &ipds->ip->ip_dst))); 491 carp_print(ndo, ipds->cp, ipds->len, ipds->ip->ip_ttl); 492 } else { 493 if (ndo->ndo_vflag) 494 ND_PRINT((ndo, "vrrp %s > %s: ", 495 ipaddr_string(ndo, &ipds->ip->ip_src), 496 ipaddr_string(ndo, &ipds->ip->ip_dst))); 497 vrrp_print(ndo, ipds->cp, ipds->len, 498 (const u_char *)ipds->ip, ipds->ip->ip_ttl); 499 } 500 break; 501 502 case IPPROTO_PGM: 503 pgm_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip); 504 break; 505 506 case IPPROTO_PFSYNC: 507 pfsync_ip_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip); 508 break; 509 510 default: 511 if (ndo->ndo_nflag==0 && (p_name = netdb_protoname(ipds->nh)) != NULL) 512 ND_PRINT((ndo, " %s", p_name)); 513 else 514 ND_PRINT((ndo, " ip-proto-%d", ipds->nh)); 515 ND_PRINT((ndo, " %d", ipds->len)); 516 break; 517 } 518 } 519 520 void 521 ip_print_inner(netdissect_options *ndo, 522 const u_char *bp, 523 u_int length, u_int nh, 524 const u_char *bp2) 525 { 526 struct ip_print_demux_state ipd; 527 528 ipd.ip = (const struct ip *)bp2; 529 ipd.cp = bp; 530 ipd.len = length; 531 ipd.off = 0; 532 ipd.nh = nh; 533 ipd.advance = 0; 534 535 ip_print_demux(ndo, &ipd); 536 } 537 538 539 /* 540 * print an IP datagram. 541 */ 542 void 543 ip_print(netdissect_options *ndo, 544 const u_char *bp, 545 u_int length) 546 { 547 struct ip_print_demux_state ipd; 548 struct ip_print_demux_state *ipds=&ipd; 549 const u_char *ipend; 550 u_int hlen; 551 struct cksum_vec vec[1]; 552 uint16_t sum, ip_sum; 553 const char *p_name; 554 555 ipds->ip = (const struct ip *)bp; 556 ND_TCHECK(ipds->ip->ip_vhl); 557 if (IP_V(ipds->ip) != 4) { /* print version and fail if != 4 */ 558 if (IP_V(ipds->ip) == 6) 559 ND_PRINT((ndo, "IP6, wrong link-layer encapsulation ")); 560 else 561 ND_PRINT((ndo, "IP%u ", IP_V(ipds->ip))); 562 return; 563 } 564 if (!ndo->ndo_eflag) 565 ND_PRINT((ndo, "IP ")); 566 567 ND_TCHECK(*ipds->ip); 568 if (length < sizeof (struct ip)) { 569 ND_PRINT((ndo, "truncated-ip %u", length)); 570 return; 571 } 572 hlen = IP_HL(ipds->ip) * 4; 573 if (hlen < sizeof (struct ip)) { 574 ND_PRINT((ndo, "bad-hlen %u", hlen)); 575 return; 576 } 577 578 ipds->len = EXTRACT_16BITS(&ipds->ip->ip_len); 579 if (length < ipds->len) 580 ND_PRINT((ndo, "truncated-ip - %u bytes missing! ", 581 ipds->len - length)); 582 if (ipds->len < hlen) { 583 #ifdef GUESS_TSO 584 if (ipds->len) { 585 ND_PRINT((ndo, "bad-len %u", ipds->len)); 586 return; 587 } 588 else { 589 /* we guess that it is a TSO send */ 590 ipds->len = length; 591 } 592 #else 593 ND_PRINT((ndo, "bad-len %u", ipds->len)); 594 return; 595 #endif /* GUESS_TSO */ 596 } 597 598 /* 599 * Cut off the snapshot length to the end of the IP payload. 600 */ 601 ipend = bp + ipds->len; 602 if (ipend < ndo->ndo_snapend) 603 ndo->ndo_snapend = ipend; 604 605 ipds->len -= hlen; 606 607 ipds->off = EXTRACT_16BITS(&ipds->ip->ip_off); 608 609 if (ndo->ndo_vflag) { 610 ND_PRINT((ndo, "(tos 0x%x", (int)ipds->ip->ip_tos)); 611 /* ECN bits */ 612 switch (ipds->ip->ip_tos & 0x03) { 613 614 case 0: 615 break; 616 617 case 1: 618 ND_PRINT((ndo, ",ECT(1)")); 619 break; 620 621 case 2: 622 ND_PRINT((ndo, ",ECT(0)")); 623 break; 624 625 case 3: 626 ND_PRINT((ndo, ",CE")); 627 break; 628 } 629 630 if (ipds->ip->ip_ttl >= 1) 631 ND_PRINT((ndo, ", ttl %u", ipds->ip->ip_ttl)); 632 633 /* 634 * for the firewall guys, print id, offset. 635 * On all but the last stick a "+" in the flags portion. 636 * For unfragmented datagrams, note the don't fragment flag. 637 */ 638 639 ND_PRINT((ndo, ", id %u, offset %u, flags [%s], proto %s (%u)", 640 EXTRACT_16BITS(&ipds->ip->ip_id), 641 (ipds->off & 0x1fff) * 8, 642 bittok2str(ip_frag_values, "none", ipds->off&0xe000), 643 tok2str(ipproto_values,"unknown",ipds->ip->ip_p), 644 ipds->ip->ip_p)); 645 646 ND_PRINT((ndo, ", length %u", EXTRACT_16BITS(&ipds->ip->ip_len))); 647 648 if ((hlen - sizeof(struct ip)) > 0) { 649 ND_PRINT((ndo, ", options (")); 650 ip_optprint(ndo, (const u_char *)(ipds->ip + 1), hlen - sizeof(struct ip)); 651 ND_PRINT((ndo, ")")); 652 } 653 654 if (!ndo->ndo_Kflag && (const u_char *)ipds->ip + hlen <= ndo->ndo_snapend) { 655 vec[0].ptr = (const uint8_t *)(const void *)ipds->ip; 656 vec[0].len = hlen; 657 sum = in_cksum(vec, 1); 658 if (sum != 0) { 659 ip_sum = EXTRACT_16BITS(&ipds->ip->ip_sum); 660 ND_PRINT((ndo, ", bad cksum %x (->%x)!", ip_sum, 661 in_cksum_shouldbe(ip_sum, sum))); 662 } 663 } 664 665 ND_PRINT((ndo, ")\n ")); 666 } 667 668 /* 669 * If this is fragment zero, hand it to the next higher 670 * level protocol. 671 */ 672 if ((ipds->off & 0x1fff) == 0) { 673 ipds->cp = (const u_char *)ipds->ip + hlen; 674 ipds->nh = ipds->ip->ip_p; 675 676 if (ipds->nh != IPPROTO_TCP && ipds->nh != IPPROTO_UDP && 677 ipds->nh != IPPROTO_SCTP && ipds->nh != IPPROTO_DCCP) { 678 ND_PRINT((ndo, "%s > %s: ", 679 ipaddr_string(ndo, &ipds->ip->ip_src), 680 ipaddr_string(ndo, &ipds->ip->ip_dst))); 681 } 682 ip_print_demux(ndo, ipds); 683 } else { 684 /* 685 * Ultra quiet now means that all this stuff should be 686 * suppressed. 687 */ 688 if (ndo->ndo_qflag > 1) 689 return; 690 691 /* 692 * This isn't the first frag, so we're missing the 693 * next level protocol header. print the ip addr 694 * and the protocol. 695 */ 696 ND_PRINT((ndo, "%s > %s:", ipaddr_string(ndo, &ipds->ip->ip_src), 697 ipaddr_string(ndo, &ipds->ip->ip_dst))); 698 if (!ndo->ndo_nflag && (p_name = netdb_protoname(ipds->ip->ip_p)) != NULL) 699 ND_PRINT((ndo, " %s", p_name)); 700 else 701 ND_PRINT((ndo, " ip-proto-%d", ipds->ip->ip_p)); 702 } 703 return; 704 705 trunc: 706 ND_PRINT((ndo, "%s", tstr)); 707 return; 708 } 709 710 void 711 ipN_print(netdissect_options *ndo, register const u_char *bp, register u_int length) 712 { 713 if (length < 1) { 714 ND_PRINT((ndo, "truncated-ip %d", length)); 715 return; 716 } 717 718 ND_TCHECK(*bp); 719 switch (*bp & 0xF0) { 720 case 0x40: 721 ip_print (ndo, bp, length); 722 break; 723 case 0x60: 724 ip6_print (ndo, bp, length); 725 break; 726 default: 727 ND_PRINT((ndo, "unknown ip %d", (*bp & 0xF0) >> 4)); 728 break; 729 } 730 return; 731 732 trunc: 733 ND_PRINT((ndo, "%s", tstr)); 734 return; 735 } 736 737 /* 738 * Local Variables: 739 * c-style: whitesmith 740 * c-basic-offset: 8 741 * End: 742 */ 743 744 745