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