1 1.1 christos /* 2 1.1 christos * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 3 1.1 christos * The Regents of the University of California. All rights reserved. 4 1.1 christos * 5 1.1 christos * Redistribution and use in source and binary forms, with or without 6 1.1 christos * modification, are permitted provided that: (1) source code distributions 7 1.1 christos * retain the above copyright notice and this paragraph in its entirety, (2) 8 1.1 christos * distributions including binary code include the above copyright notice and 9 1.1 christos * this paragraph in its entirety in the documentation or other materials 10 1.1 christos * provided with the distribution, and (3) all advertising materials mentioning 11 1.1 christos * features or use of this software display the following acknowledgement: 12 1.1 christos * ``This product includes software developed by the University of California, 13 1.1 christos * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 14 1.1 christos * the University nor the names of its contributors may be used to endorse 15 1.1 christos * or promote products derived from this software without specific prior 16 1.1 christos * written permission. 17 1.1 christos * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 18 1.1 christos * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 19 1.1 christos * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20 1.1 christos */ 21 1.1 christos 22 1.2 christos #include <sys/cdefs.h> 23 1.1 christos #ifndef lint 24 1.15 christos __RCSID("$NetBSD: print-ip.c,v 1.15 2026/03/19 00:05:13 christos Exp $"); 25 1.1 christos #endif 26 1.1 christos 27 1.11 spz /* \summary: IP printer */ 28 1.11 spz 29 1.13 christos #include <config.h> 30 1.1 christos 31 1.13 christos #include "netdissect-stdinc.h" 32 1.1 christos 33 1.9 christos #include "netdissect.h" 34 1.1 christos #include "addrtoname.h" 35 1.9 christos #include "extract.h" 36 1.1 christos 37 1.1 christos #include "ip.h" 38 1.1 christos #include "ipproto.h" 39 1.1 christos 40 1.7 christos 41 1.6 christos static const struct tok ip_option_values[] = { 42 1.1 christos { IPOPT_EOL, "EOL" }, 43 1.1 christos { IPOPT_NOP, "NOP" }, 44 1.1 christos { IPOPT_TS, "timestamp" }, 45 1.1 christos { IPOPT_SECURITY, "security" }, 46 1.1 christos { IPOPT_RR, "RR" }, 47 1.1 christos { IPOPT_SSRR, "SSRR" }, 48 1.1 christos { IPOPT_LSRR, "LSRR" }, 49 1.1 christos { IPOPT_RA, "RA" }, 50 1.1 christos { IPOPT_RFC1393, "traceroute" }, 51 1.1 christos { 0, NULL } 52 1.1 christos }; 53 1.1 christos 54 1.1 christos /* 55 1.1 christos * print the recorded route in an IP RR, LSRR or SSRR option. 56 1.1 christos */ 57 1.12 christos static int 58 1.7 christos ip_printroute(netdissect_options *ndo, 59 1.13 christos const u_char *cp, u_int length) 60 1.1 christos { 61 1.13 christos u_int ptr; 62 1.13 christos u_int len; 63 1.1 christos 64 1.1 christos if (length < 3) { 65 1.13 christos ND_PRINT(" [bad length %u]", length); 66 1.12 christos return (0); 67 1.1 christos } 68 1.1 christos if ((length + 1) & 3) 69 1.13 christos ND_PRINT(" [bad length %u]", length); 70 1.13 christos ptr = GET_U_1(cp + 2) - 1; 71 1.1 christos if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1) 72 1.13 christos ND_PRINT(" [bad ptr %u]", GET_U_1(cp + 2)); 73 1.1 christos 74 1.1 christos for (len = 3; len < length; len += 4) { 75 1.13 christos ND_TCHECK_4(cp + len); /* Needed to print the IP addresses */ 76 1.13 christos ND_PRINT(" %s", GET_IPADDR_STRING(cp + len)); 77 1.7 christos if (ptr > len) 78 1.13 christos ND_PRINT(","); 79 1.1 christos } 80 1.12 christos return (0); 81 1.12 christos 82 1.12 christos trunc: 83 1.12 christos return (-1); 84 1.1 christos } 85 1.1 christos 86 1.1 christos /* 87 1.1 christos * If source-routing is present and valid, return the final destination. 88 1.1 christos * Otherwise, return IP destination. 89 1.1 christos * 90 1.1 christos * This is used for UDP and TCP pseudo-header in the checksum 91 1.1 christos * calculation. 92 1.1 christos */ 93 1.7 christos static uint32_t 94 1.7 christos ip_finddst(netdissect_options *ndo, 95 1.7 christos const struct ip *ip) 96 1.1 christos { 97 1.13 christos u_int length; 98 1.13 christos u_int len; 99 1.1 christos const u_char *cp; 100 1.1 christos 101 1.1 christos cp = (const u_char *)(ip + 1); 102 1.13 christos length = IP_HL(ip) * 4; 103 1.13 christos if (length < sizeof(struct ip)) 104 1.13 christos goto trunc; 105 1.13 christos length -= sizeof(struct ip); 106 1.1 christos 107 1.13 christos for (; length != 0; cp += len, length -= len) { 108 1.1 christos int tt; 109 1.1 christos 110 1.13 christos tt = GET_U_1(cp); 111 1.1 christos if (tt == IPOPT_EOL) 112 1.1 christos break; 113 1.1 christos else if (tt == IPOPT_NOP) 114 1.1 christos len = 1; 115 1.1 christos else { 116 1.13 christos len = GET_U_1(cp + 1); 117 1.1 christos if (len < 2) 118 1.1 christos break; 119 1.1 christos } 120 1.13 christos if (length < len) 121 1.13 christos goto trunc; 122 1.13 christos ND_TCHECK_LEN(cp, len); 123 1.1 christos switch (tt) { 124 1.1 christos 125 1.1 christos case IPOPT_SSRR: 126 1.1 christos case IPOPT_LSRR: 127 1.1 christos if (len < 7) 128 1.1 christos break; 129 1.13 christos return (GET_IPV4_TO_NETWORK_ORDER(cp + len - 4)); 130 1.1 christos } 131 1.1 christos } 132 1.1 christos trunc: 133 1.13 christos return (GET_IPV4_TO_NETWORK_ORDER(ip->ip_dst)); 134 1.1 christos } 135 1.1 christos 136 1.3 christos /* 137 1.3 christos * Compute a V4-style checksum by building a pseudoheader. 138 1.3 christos */ 139 1.13 christos uint16_t 140 1.7 christos nextproto4_cksum(netdissect_options *ndo, 141 1.7 christos const struct ip *ip, const uint8_t *data, 142 1.13 christos u_int len, u_int covlen, uint8_t next_proto) 143 1.3 christos { 144 1.3 christos struct phdr { 145 1.7 christos uint32_t src; 146 1.7 christos uint32_t dst; 147 1.13 christos uint8_t mbz; 148 1.13 christos uint8_t proto; 149 1.7 christos uint16_t len; 150 1.3 christos } ph; 151 1.3 christos struct cksum_vec vec[2]; 152 1.3 christos 153 1.3 christos /* pseudo-header.. */ 154 1.7 christos ph.len = htons((uint16_t)len); 155 1.3 christos ph.mbz = 0; 156 1.3 christos ph.proto = next_proto; 157 1.13 christos ph.src = GET_IPV4_TO_NETWORK_ORDER(ip->ip_src); 158 1.3 christos if (IP_HL(ip) == 5) 159 1.13 christos ph.dst = GET_IPV4_TO_NETWORK_ORDER(ip->ip_dst); 160 1.3 christos else 161 1.7 christos ph.dst = ip_finddst(ndo, ip); 162 1.3 christos 163 1.7 christos vec[0].ptr = (const uint8_t *)(void *)&ph; 164 1.3 christos vec[0].len = sizeof(ph); 165 1.3 christos vec[1].ptr = data; 166 1.7 christos vec[1].len = covlen; 167 1.3 christos return (in_cksum(vec, 2)); 168 1.3 christos } 169 1.3 christos 170 1.12 christos static int 171 1.7 christos ip_printts(netdissect_options *ndo, 172 1.13 christos const u_char *cp, u_int length) 173 1.1 christos { 174 1.13 christos u_int ptr; 175 1.13 christos u_int len; 176 1.13 christos u_int hoplen; 177 1.1 christos const char *type; 178 1.1 christos 179 1.1 christos if (length < 4) { 180 1.13 christos ND_PRINT("[bad length %u]", length); 181 1.12 christos return (0); 182 1.1 christos } 183 1.13 christos ND_PRINT(" TS{"); 184 1.13 christos hoplen = ((GET_U_1(cp + 3) & 0xF) != IPOPT_TS_TSONLY) ? 8 : 4; 185 1.1 christos if ((length - 4) & (hoplen-1)) 186 1.13 christos ND_PRINT("[bad length %u]", length); 187 1.13 christos ptr = GET_U_1(cp + 2) - 1; 188 1.1 christos len = 0; 189 1.1 christos if (ptr < 4 || ((ptr - 4) & (hoplen-1)) || ptr > length + 1) 190 1.13 christos ND_PRINT("[bad ptr %u]", GET_U_1(cp + 2)); 191 1.13 christos switch (GET_U_1(cp + 3)&0xF) { 192 1.1 christos case IPOPT_TS_TSONLY: 193 1.13 christos ND_PRINT("TSONLY"); 194 1.1 christos break; 195 1.1 christos case IPOPT_TS_TSANDADDR: 196 1.13 christos ND_PRINT("TS+ADDR"); 197 1.1 christos break; 198 1.13 christos case IPOPT_TS_PRESPEC: 199 1.13 christos ND_PRINT("PRESPEC"); 200 1.1 christos break; 201 1.1 christos default: 202 1.13 christos ND_PRINT("[bad ts type %u]", GET_U_1(cp + 3)&0xF); 203 1.1 christos goto done; 204 1.1 christos } 205 1.1 christos 206 1.1 christos type = " "; 207 1.1 christos for (len = 4; len < length; len += hoplen) { 208 1.1 christos if (ptr == len) 209 1.1 christos type = " ^ "; 210 1.13 christos ND_TCHECK_LEN(cp + len, hoplen); 211 1.13 christos ND_PRINT("%s%u@%s", type, GET_BE_U_4(cp + len + hoplen - 4), 212 1.13 christos hoplen!=8 ? "" : GET_IPADDR_STRING(cp + len)); 213 1.1 christos type = " "; 214 1.1 christos } 215 1.1 christos 216 1.1 christos done: 217 1.13 christos ND_PRINT("%s", ptr == len ? " ^ " : ""); 218 1.1 christos 219 1.13 christos if (GET_U_1(cp + 3) >> 4) 220 1.13 christos ND_PRINT(" [%u hops not recorded]} ", GET_U_1(cp + 3)>>4); 221 1.1 christos else 222 1.13 christos ND_PRINT("}"); 223 1.12 christos return (0); 224 1.12 christos 225 1.12 christos trunc: 226 1.12 christos return (-1); 227 1.1 christos } 228 1.1 christos 229 1.1 christos /* 230 1.1 christos * print IP options. 231 1.13 christos If truncated return -1, else 0. 232 1.1 christos */ 233 1.13 christos static int 234 1.7 christos ip_optprint(netdissect_options *ndo, 235 1.13 christos const u_char *cp, u_int length) 236 1.1 christos { 237 1.13 christos u_int option_len; 238 1.1 christos const char *sep = ""; 239 1.1 christos 240 1.1 christos for (; length > 0; cp += option_len, length -= option_len) { 241 1.1 christos u_int option_code; 242 1.1 christos 243 1.13 christos ND_PRINT("%s", sep); 244 1.1 christos sep = ","; 245 1.1 christos 246 1.13 christos option_code = GET_U_1(cp); 247 1.1 christos 248 1.13 christos ND_PRINT("%s", 249 1.13 christos tok2str(ip_option_values,"unknown %u",option_code)); 250 1.1 christos 251 1.1 christos if (option_code == IPOPT_NOP || 252 1.1 christos option_code == IPOPT_EOL) 253 1.1 christos option_len = 1; 254 1.1 christos 255 1.1 christos else { 256 1.13 christos option_len = GET_U_1(cp + 1); 257 1.1 christos if (option_len < 2) { 258 1.13 christos ND_PRINT(" [bad length %u]", option_len); 259 1.13 christos return 0; 260 1.1 christos } 261 1.1 christos } 262 1.1 christos 263 1.1 christos if (option_len > length) { 264 1.13 christos ND_PRINT(" [bad length %u]", option_len); 265 1.13 christos return 0; 266 1.1 christos } 267 1.1 christos 268 1.13 christos ND_TCHECK_LEN(cp, option_len); 269 1.1 christos 270 1.1 christos switch (option_code) { 271 1.1 christos case IPOPT_EOL: 272 1.13 christos return 0; 273 1.1 christos 274 1.1 christos case IPOPT_TS: 275 1.12 christos if (ip_printts(ndo, cp, option_len) == -1) 276 1.12 christos goto trunc; 277 1.1 christos break; 278 1.1 christos 279 1.1 christos case IPOPT_RR: /* fall through */ 280 1.1 christos case IPOPT_SSRR: 281 1.1 christos case IPOPT_LSRR: 282 1.12 christos if (ip_printroute(ndo, cp, option_len) == -1) 283 1.12 christos goto trunc; 284 1.1 christos break; 285 1.1 christos 286 1.1 christos case IPOPT_RA: 287 1.1 christos if (option_len < 4) { 288 1.13 christos ND_PRINT(" [bad length %u]", option_len); 289 1.1 christos break; 290 1.1 christos } 291 1.13 christos ND_TCHECK_1(cp + 3); 292 1.13 christos if (GET_BE_U_2(cp + 2) != 0) 293 1.13 christos ND_PRINT(" value %u", GET_BE_U_2(cp + 2)); 294 1.1 christos break; 295 1.1 christos 296 1.1 christos case IPOPT_NOP: /* nothing to print - fall through */ 297 1.1 christos case IPOPT_SECURITY: 298 1.1 christos default: 299 1.1 christos break; 300 1.1 christos } 301 1.1 christos } 302 1.13 christos return 0; 303 1.1 christos 304 1.1 christos trunc: 305 1.13 christos return -1; 306 1.1 christos } 307 1.1 christos 308 1.1 christos #define IP_RES 0x8000 309 1.1 christos 310 1.6 christos static const struct tok ip_frag_values[] = { 311 1.1 christos { IP_MF, "+" }, 312 1.1 christos { IP_DF, "DF" }, 313 1.1 christos { IP_RES, "rsvd" }, /* The RFC3514 evil ;-) bit */ 314 1.1 christos { 0, NULL } 315 1.1 christos }; 316 1.1 christos 317 1.1 christos 318 1.1 christos /* 319 1.1 christos * print an IP datagram. 320 1.1 christos */ 321 1.1 christos void 322 1.1 christos ip_print(netdissect_options *ndo, 323 1.1 christos const u_char *bp, 324 1.14 christos const u_int length) 325 1.1 christos { 326 1.13 christos const struct ip *ip; 327 1.13 christos u_int off; 328 1.1 christos u_int hlen; 329 1.13 christos u_int len; 330 1.3 christos struct cksum_vec vec[1]; 331 1.13 christos uint8_t ip_tos, ip_ttl, ip_proto; 332 1.7 christos uint16_t sum, ip_sum; 333 1.12 christos const char *p_name; 334 1.13 christos int truncated = 0; 335 1.14 christos int presumed_tso = 0; 336 1.1 christos 337 1.13 christos ndo->ndo_protocol = "ip"; 338 1.13 christos ip = (const struct ip *)bp; 339 1.14 christos 340 1.14 christos if (!ndo->ndo_eflag) { 341 1.14 christos nd_print_protocol_caps(ndo); 342 1.14 christos ND_PRINT(" "); 343 1.1 christos } 344 1.1 christos 345 1.14 christos ND_ICHECK_ZU(length, <, sizeof (struct ip)); 346 1.14 christos ND_ICHECKMSG_U("version", IP_V(ip), !=, 4); 347 1.14 christos 348 1.13 christos hlen = IP_HL(ip) * 4; 349 1.14 christos ND_ICHECKMSG_ZU("header length", hlen, <, sizeof (struct ip)); 350 1.1 christos 351 1.13 christos len = GET_BE_U_2(ip->ip_len); 352 1.14 christos if (len > length) { 353 1.14 christos ND_PRINT("[total length %u > length %u]", len, length); 354 1.14 christos nd_print_invalid(ndo); 355 1.14 christos ND_PRINT(" "); 356 1.14 christos } 357 1.14 christos if (len == 0) { 358 1.14 christos /* we guess that it is a TSO send */ 359 1.14 christos len = length; 360 1.14 christos presumed_tso = 1; 361 1.15 christos } 362 1.15 christos if (len < hlen) { 363 1.15 christos ND_PRINT("[total length %u < header length %u]", len, hlen); 364 1.15 christos goto invalid; 365 1.15 christos } 366 1.1 christos 367 1.14 christos ND_TCHECK_SIZE(ip); 368 1.1 christos /* 369 1.15 christos * Cut off the snapshot length to the end of the IP payload 370 1.15 christos * or the end of the data in which it's contained, whichever 371 1.15 christos * comes first. 372 1.1 christos */ 373 1.15 christos if (!nd_push_snaplen(ndo, bp, ND_MIN(length, len))) { 374 1.13 christos (*ndo->ndo_error)(ndo, S_ERR_ND_MEM_ALLOC, 375 1.13 christos "%s: can't push snaplen on buffer stack", __func__); 376 1.13 christos } 377 1.1 christos 378 1.13 christos len -= hlen; 379 1.1 christos 380 1.13 christos off = GET_BE_U_2(ip->ip_off); 381 1.13 christos 382 1.13 christos ip_proto = GET_U_1(ip->ip_p); 383 1.1 christos 384 1.7 christos if (ndo->ndo_vflag) { 385 1.13 christos ip_tos = GET_U_1(ip->ip_tos); 386 1.13 christos ND_PRINT("(tos 0x%x", ip_tos); 387 1.1 christos /* ECN bits */ 388 1.13 christos switch (ip_tos & 0x03) { 389 1.11 spz 390 1.11 spz case 0: 391 1.11 spz break; 392 1.11 spz 393 1.11 spz case 1: 394 1.13 christos ND_PRINT(",ECT(1)"); 395 1.11 spz break; 396 1.11 spz 397 1.11 spz case 2: 398 1.13 christos ND_PRINT(",ECT(0)"); 399 1.11 spz break; 400 1.11 spz 401 1.11 spz case 3: 402 1.13 christos ND_PRINT(",CE"); 403 1.11 spz break; 404 1.1 christos } 405 1.1 christos 406 1.13 christos ip_ttl = GET_U_1(ip->ip_ttl); 407 1.13 christos if (ip_ttl >= 1) 408 1.13 christos ND_PRINT(", ttl %u", ip_ttl); 409 1.1 christos 410 1.1 christos /* 411 1.1 christos * for the firewall guys, print id, offset. 412 1.1 christos * On all but the last stick a "+" in the flags portion. 413 1.1 christos * For unfragmented datagrams, note the don't fragment flag. 414 1.1 christos */ 415 1.13 christos ND_PRINT(", id %u, offset %u, flags [%s], proto %s (%u)", 416 1.13 christos GET_BE_U_2(ip->ip_id), 417 1.13 christos (off & IP_OFFMASK) * 8, 418 1.13 christos bittok2str(ip_frag_values, "none", off & (IP_RES|IP_DF|IP_MF)), 419 1.13 christos tok2str(ipproto_values, "unknown", ip_proto), 420 1.13 christos ip_proto); 421 1.1 christos 422 1.14 christos if (presumed_tso) 423 1.14 christos ND_PRINT(", length %u [was 0, presumed TSO]", length); 424 1.14 christos else 425 1.14 christos ND_PRINT(", length %u", GET_BE_U_2(ip->ip_len)); 426 1.1 christos 427 1.15 christos if ((hlen > sizeof(struct ip))) { 428 1.13 christos ND_PRINT(", options ("); 429 1.13 christos if (ip_optprint(ndo, (const u_char *)(ip + 1), 430 1.13 christos hlen - sizeof(struct ip)) == -1) { 431 1.13 christos ND_PRINT(" [truncated-option]"); 432 1.13 christos truncated = 1; 433 1.13 christos } 434 1.13 christos ND_PRINT(")"); 435 1.1 christos } 436 1.1 christos 437 1.15 christos if (!ndo->ndo_Kflag && ND_TTEST_LEN((const u_char *)ip, hlen)) { 438 1.13 christos vec[0].ptr = (const uint8_t *)(const void *)ip; 439 1.3 christos vec[0].len = hlen; 440 1.3 christos sum = in_cksum(vec, 1); 441 1.1 christos if (sum != 0) { 442 1.13 christos ip_sum = GET_BE_U_2(ip->ip_sum); 443 1.13 christos ND_PRINT(", bad cksum %x (->%x)!", ip_sum, 444 1.13 christos in_cksum_shouldbe(ip_sum, sum)); 445 1.1 christos } 446 1.1 christos } 447 1.1 christos 448 1.15 christos if (ndo->ndo_gflag) 449 1.15 christos ND_PRINT(") "); 450 1.15 christos else 451 1.15 christos ND_PRINT(")\n "); 452 1.13 christos if (truncated) { 453 1.13 christos ND_PRINT("%s > %s: ", 454 1.13 christos GET_IPADDR_STRING(ip->ip_src), 455 1.13 christos GET_IPADDR_STRING(ip->ip_dst)); 456 1.13 christos nd_print_trunc(ndo); 457 1.13 christos nd_pop_packet_info(ndo); 458 1.13 christos return; 459 1.13 christos } 460 1.1 christos } 461 1.1 christos 462 1.1 christos /* 463 1.1 christos * If this is fragment zero, hand it to the next higher 464 1.13 christos * level protocol. Let them know whether there are more 465 1.13 christos * fragments. 466 1.1 christos */ 467 1.13 christos if ((off & IP_OFFMASK) == 0) { 468 1.13 christos uint8_t nh = GET_U_1(ip->ip_p); 469 1.13 christos 470 1.13 christos if (nh != IPPROTO_TCP && nh != IPPROTO_UDP && 471 1.13 christos nh != IPPROTO_SCTP && nh != IPPROTO_DCCP) { 472 1.13 christos ND_PRINT("%s > %s: ", 473 1.13 christos GET_IPADDR_STRING(ip->ip_src), 474 1.13 christos GET_IPADDR_STRING(ip->ip_dst)); 475 1.13 christos } 476 1.13 christos /* 477 1.13 christos * Do a bounds check before calling ip_demux_print(). 478 1.13 christos * At least the header data is required. 479 1.13 christos */ 480 1.13 christos if (!ND_TTEST_LEN((const u_char *)ip, hlen)) { 481 1.13 christos ND_PRINT(" [remaining caplen(%u) < header length(%u)]", 482 1.13 christos ND_BYTES_AVAILABLE_AFTER((const u_char *)ip), 483 1.13 christos hlen); 484 1.13 christos nd_trunc_longjmp(ndo); 485 1.1 christos } 486 1.13 christos ip_demux_print(ndo, (const u_char *)ip + hlen, len, 4, 487 1.13 christos off & IP_MF, GET_U_1(ip->ip_ttl), nh, bp); 488 1.1 christos } else { 489 1.11 spz /* 490 1.11 spz * Ultra quiet now means that all this stuff should be 491 1.11 spz * suppressed. 492 1.11 spz */ 493 1.13 christos if (ndo->ndo_qflag > 1) { 494 1.13 christos nd_pop_packet_info(ndo); 495 1.11 spz return; 496 1.13 christos } 497 1.1 christos 498 1.11 spz /* 499 1.11 spz * This isn't the first frag, so we're missing the 500 1.11 spz * next level protocol header. print the ip addr 501 1.11 spz * and the protocol. 502 1.11 spz */ 503 1.13 christos ND_PRINT("%s > %s:", GET_IPADDR_STRING(ip->ip_src), 504 1.13 christos GET_IPADDR_STRING(ip->ip_dst)); 505 1.13 christos if (!ndo->ndo_nflag && (p_name = netdb_protoname(ip_proto)) != NULL) 506 1.13 christos ND_PRINT(" %s", p_name); 507 1.11 spz else 508 1.13 christos ND_PRINT(" ip-proto-%u", ip_proto); 509 1.1 christos } 510 1.13 christos nd_pop_packet_info(ndo); 511 1.8 christos return; 512 1.8 christos 513 1.8 christos trunc: 514 1.13 christos nd_print_trunc(ndo); 515 1.14 christos return; 516 1.14 christos 517 1.14 christos invalid: 518 1.14 christos nd_print_invalid(ndo); 519 1.1 christos } 520 1.1 christos 521 1.1 christos void 522 1.13 christos ipN_print(netdissect_options *ndo, const u_char *bp, u_int length) 523 1.1 christos { 524 1.13 christos ndo->ndo_protocol = "ipn"; 525 1.11 spz if (length < 1) { 526 1.13 christos ND_PRINT("truncated-ip %u", length); 527 1.1 christos return; 528 1.1 christos } 529 1.11 spz 530 1.13 christos switch (GET_U_1(bp) & 0xF0) { 531 1.11 spz case 0x40: 532 1.13 christos ip_print(ndo, bp, length); 533 1.11 spz break; 534 1.11 spz case 0x60: 535 1.13 christos ip6_print(ndo, bp, length); 536 1.11 spz break; 537 1.1 christos default: 538 1.13 christos ND_PRINT("unknown ip %u", (GET_U_1(bp) & 0xF0) >> 4); 539 1.11 spz break; 540 1.1 christos } 541 1.1 christos } 542