Home | History | Annotate | Line # | Download | only in dist
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