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