print-ip.c revision 277783
117680Spst/*
239300Sfenner * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
317680Spst *	The Regents of the University of California.  All rights reserved.
417680Spst *
517680Spst * Redistribution and use in source and binary forms, with or without
617680Spst * modification, are permitted provided that: (1) source code distributions
717680Spst * retain the above copyright notice and this paragraph in its entirety, (2)
817680Spst * distributions including binary code include the above copyright notice and
917680Spst * this paragraph in its entirety in the documentation or other materials
1017680Spst * provided with the distribution, and (3) all advertising materials mentioning
1117680Spst * features or use of this software display the following acknowledgement:
1217680Spst * ``This product includes software developed by the University of California,
1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1417680Spst * the University nor the names of its contributors may be used to endorse
1517680Spst * or promote products derived from this software without specific prior
1617680Spst * written permission.
1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2056896Sfenner *
2156896Sfenner * $FreeBSD: head/contrib/tcpdump/print-ip.c 277783 2015-01-27 01:45:47Z pfg $
2217680Spst */
2317680Spst
24276788Sdelphij#define NETDISSECT_REWORKED
2556896Sfenner#ifdef HAVE_CONFIG_H
2656896Sfenner#include "config.h"
2756896Sfenner#endif
2856896Sfenner
29127675Sbms#include <tcpdump-stdinc.h>
3017680Spst
3117680Spst#include <string.h>
3217680Spst
33276788Sdelphij#include "interface.h"
3417680Spst#include "addrtoname.h"
3517680Spst#include "extract.h"			/* must come after interface.h */
3617680Spst
3775118Sfenner#include "ip.h"
38127675Sbms#include "ipproto.h"
3975118Sfenner
40276788Sdelphijstatic const char tstr[] = "[|ip]";
41276788Sdelphij
42276788Sdelphijstatic const struct tok ip_option_values[] = {
43146778Ssam    { IPOPT_EOL, "EOL" },
44146778Ssam    { IPOPT_NOP, "NOP" },
45146778Ssam    { IPOPT_TS, "timestamp" },
46146778Ssam    { IPOPT_SECURITY, "security" },
47146778Ssam    { IPOPT_RR, "RR" },
48146778Ssam    { IPOPT_SSRR, "SSRR" },
49146778Ssam    { IPOPT_LSRR, "LSRR" },
50146778Ssam    { IPOPT_RA, "RA" },
51172686Smlaier    { IPOPT_RFC1393, "traceroute" },
52146778Ssam    { 0, NULL }
53146778Ssam};
54146778Ssam
5517680Spst/*
5617680Spst * print the recorded route in an IP RR, LSRR or SSRR option.
5717680Spst */
5817680Spststatic void
59276788Sdelphijip_printroute(netdissect_options *ndo,
60276788Sdelphij              register const u_char *cp, u_int length)
6117680Spst{
62127675Sbms	register u_int ptr;
6317680Spst	register u_int len;
6417680Spst
65127675Sbms	if (length < 3) {
66276788Sdelphij		ND_PRINT((ndo, " [bad length %u]", length));
67127675Sbms		return;
68127675Sbms	}
6917680Spst	if ((length + 1) & 3)
70276788Sdelphij		ND_PRINT((ndo, " [bad length %u]", length));
71127675Sbms	ptr = cp[2] - 1;
7217680Spst	if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1)
73276788Sdelphij		ND_PRINT((ndo, " [bad ptr %u]", cp[2]));
7417680Spst
7517680Spst	for (len = 3; len < length; len += 4) {
76276788Sdelphij		ND_PRINT((ndo, " %s", ipaddr_string(ndo, &cp[len])));
77276788Sdelphij		if (ptr > len)
78276788Sdelphij			ND_PRINT((ndo, ","));
7917680Spst	}
8017680Spst}
8117680Spst
82127675Sbms/*
83146778Ssam * If source-routing is present and valid, return the final destination.
84127675Sbms * Otherwise, return IP destination.
85127675Sbms *
86127675Sbms * This is used for UDP and TCP pseudo-header in the checksum
87127675Sbms * calculation.
88127675Sbms */
89276788Sdelphijstatic uint32_t
90276788Sdelphijip_finddst(netdissect_options *ndo,
91276788Sdelphij           const struct ip *ip)
92127675Sbms{
93127675Sbms	int length;
94127675Sbms	int len;
95127675Sbms	const u_char *cp;
96276788Sdelphij	uint32_t retval;
97127675Sbms
98127675Sbms	cp = (const u_char *)(ip + 1);
99127675Sbms	length = (IP_HL(ip) << 2) - sizeof(struct ip);
100127675Sbms
101127675Sbms	for (; length > 0; cp += len, length -= len) {
102127675Sbms		int tt;
103127675Sbms
104276788Sdelphij		ND_TCHECK(*cp);
105127675Sbms		tt = *cp;
106146778Ssam		if (tt == IPOPT_EOL)
107146778Ssam			break;
108146778Ssam		else if (tt == IPOPT_NOP)
109127675Sbms			len = 1;
110127675Sbms		else {
111276788Sdelphij			ND_TCHECK(cp[1]);
112127675Sbms			len = cp[1];
113146778Ssam			if (len < 2)
114146778Ssam				break;
115127675Sbms		}
116276788Sdelphij		ND_TCHECK2(*cp, len);
117127675Sbms		switch (tt) {
118127675Sbms
119127675Sbms		case IPOPT_SSRR:
120127675Sbms		case IPOPT_LSRR:
121127675Sbms			if (len < 7)
122146778Ssam				break;
123276788Sdelphij			UNALIGNED_MEMCPY(&retval, cp + len - 4, 4);
124127675Sbms			return retval;
125127675Sbms		}
126127675Sbms	}
127127675Sbmstrunc:
128276788Sdelphij	UNALIGNED_MEMCPY(&retval, &ip->ip_dst.s_addr, sizeof(uint32_t));
129146778Ssam	return retval;
130127675Sbms}
131127675Sbms
132235530Sdelphij/*
133235530Sdelphij * Compute a V4-style checksum by building a pseudoheader.
134235530Sdelphij */
135235530Sdelphijint
136276788Sdelphijnextproto4_cksum(netdissect_options *ndo,
137276788Sdelphij                 const struct ip *ip, const uint8_t *data,
138276788Sdelphij                 u_int len, u_int covlen, u_int next_proto)
139235530Sdelphij{
140235530Sdelphij	struct phdr {
141276788Sdelphij		uint32_t src;
142276788Sdelphij		uint32_t dst;
143235530Sdelphij		u_char mbz;
144235530Sdelphij		u_char proto;
145276788Sdelphij		uint16_t len;
146235530Sdelphij	} ph;
147235530Sdelphij	struct cksum_vec vec[2];
148235530Sdelphij
149235530Sdelphij	/* pseudo-header.. */
150276788Sdelphij	ph.len = htons((uint16_t)len);
151235530Sdelphij	ph.mbz = 0;
152235530Sdelphij	ph.proto = next_proto;
153276788Sdelphij	UNALIGNED_MEMCPY(&ph.src, &ip->ip_src.s_addr, sizeof(uint32_t));
154235530Sdelphij	if (IP_HL(ip) == 5)
155276788Sdelphij		UNALIGNED_MEMCPY(&ph.dst, &ip->ip_dst.s_addr, sizeof(uint32_t));
156235530Sdelphij	else
157276788Sdelphij		ph.dst = ip_finddst(ndo, ip);
158235530Sdelphij
159276788Sdelphij	vec[0].ptr = (const uint8_t *)(void *)&ph;
160235530Sdelphij	vec[0].len = sizeof(ph);
161235530Sdelphij	vec[1].ptr = data;
162276788Sdelphij	vec[1].len = covlen;
163235530Sdelphij	return (in_cksum(vec, 2));
164235530Sdelphij}
165235530Sdelphij
16656896Sfennerstatic void
167276788Sdelphijip_printts(netdissect_options *ndo,
168276788Sdelphij           register const u_char *cp, u_int length)
16956896Sfenner{
170127675Sbms	register u_int ptr;
171127675Sbms	register u_int len;
17256896Sfenner	int hoplen;
173127675Sbms	const char *type;
17456896Sfenner
175127675Sbms	if (length < 4) {
176276788Sdelphij		ND_PRINT((ndo, "[bad length %u]", length));
177127675Sbms		return;
178127675Sbms	}
179276788Sdelphij	ND_PRINT((ndo, " TS{"));
18056896Sfenner	hoplen = ((cp[3]&0xF) != IPOPT_TS_TSONLY) ? 8 : 4;
18156896Sfenner	if ((length - 4) & (hoplen-1))
182276788Sdelphij		ND_PRINT((ndo, "[bad length %u]", length));
183127675Sbms	ptr = cp[2] - 1;
184127675Sbms	len = 0;
18556896Sfenner	if (ptr < 4 || ((ptr - 4) & (hoplen-1)) || ptr > length + 1)
186276788Sdelphij		ND_PRINT((ndo, "[bad ptr %u]", cp[2]));
18756896Sfenner	switch (cp[3]&0xF) {
18856896Sfenner	case IPOPT_TS_TSONLY:
189276788Sdelphij		ND_PRINT((ndo, "TSONLY"));
19056896Sfenner		break;
19156896Sfenner	case IPOPT_TS_TSANDADDR:
192276788Sdelphij		ND_PRINT((ndo, "TS+ADDR"));
19356896Sfenner		break;
19456896Sfenner	/*
19556896Sfenner	 * prespecified should really be 3, but some ones might send 2
19656896Sfenner	 * instead, and the IPOPT_TS_PRESPEC constant can apparently
19756896Sfenner	 * have both values, so we have to hard-code it here.
19856896Sfenner	 */
19956896Sfenner
20056896Sfenner	case 2:
201276788Sdelphij		ND_PRINT((ndo, "PRESPEC2.0"));
20256896Sfenner		break;
20356896Sfenner	case 3:			/* IPOPT_TS_PRESPEC */
204276788Sdelphij		ND_PRINT((ndo, "PRESPEC"));
20556896Sfenner		break;
206127675Sbms	default:
207276788Sdelphij		ND_PRINT((ndo, "[bad ts type %d]", cp[3]&0xF));
20856896Sfenner		goto done;
20956896Sfenner	}
21056896Sfenner
21156896Sfenner	type = " ";
21256896Sfenner	for (len = 4; len < length; len += hoplen) {
21356896Sfenner		if (ptr == len)
21456896Sfenner			type = " ^ ";
215276788Sdelphij		ND_PRINT((ndo, "%s%d@%s", type, EXTRACT_32BITS(&cp[len+hoplen-4]),
216276788Sdelphij		       hoplen!=8 ? "" : ipaddr_string(ndo, &cp[len])));
21756896Sfenner		type = " ";
21856896Sfenner	}
21956896Sfenner
22056896Sfennerdone:
221276788Sdelphij	ND_PRINT((ndo, "%s", ptr == len ? " ^ " : ""));
22256896Sfenner
22356896Sfenner	if (cp[3]>>4)
224276788Sdelphij		ND_PRINT((ndo, " [%d hops not recorded]} ", cp[3]>>4));
22556896Sfenner	else
226276788Sdelphij		ND_PRINT((ndo, "}"));
22756896Sfenner}
22856896Sfenner
22917680Spst/*
23017680Spst * print IP options.
23117680Spst */
23217680Spststatic void
233276788Sdelphijip_optprint(netdissect_options *ndo,
234276788Sdelphij            register const u_char *cp, u_int length)
23517680Spst{
236146778Ssam	register u_int option_len;
237172686Smlaier	const char *sep = "";
23817680Spst
239146778Ssam	for (; length > 0; cp += option_len, length -= option_len) {
240146778Ssam		u_int option_code;
24117680Spst
242276788Sdelphij		ND_PRINT((ndo, "%s", sep));
243172686Smlaier		sep = ",";
244172686Smlaier
245276788Sdelphij		ND_TCHECK(*cp);
246146778Ssam		option_code = *cp;
247146778Ssam
248276788Sdelphij		ND_PRINT((ndo, "%s",
249276788Sdelphij		          tok2str(ip_option_values,"unknown %u",option_code)));
250172686Smlaier
251146778Ssam		if (option_code == IPOPT_NOP ||
252146778Ssam                    option_code == IPOPT_EOL)
253146778Ssam			option_len = 1;
254146778Ssam
25575118Sfenner		else {
256276788Sdelphij			ND_TCHECK(cp[1]);
257172686Smlaier			option_len = cp[1];
258172686Smlaier			if (option_len < 2) {
259276788Sdelphij				ND_PRINT((ndo, " [bad length %u]", option_len));
260172686Smlaier				return;
261172686Smlaier			}
26275118Sfenner		}
26317680Spst
264172686Smlaier		if (option_len > length) {
265276788Sdelphij			ND_PRINT((ndo, " [bad length %u]", option_len));
266172686Smlaier			return;
267172686Smlaier		}
268146778Ssam
269276788Sdelphij		ND_TCHECK2(*cp, option_len);
270146778Ssam
271146778Ssam		switch (option_code) {
27217680Spst		case IPOPT_EOL:
27317680Spst			return;
27417680Spst
27517680Spst		case IPOPT_TS:
276276788Sdelphij			ip_printts(ndo, cp, option_len);
27717680Spst			break;
27817680Spst
279146778Ssam		case IPOPT_RR:       /* fall through */
28017680Spst		case IPOPT_SSRR:
28117680Spst		case IPOPT_LSRR:
282276788Sdelphij			ip_printroute(ndo, cp, option_len);
28317680Spst			break;
28417680Spst
28517691Spst		case IPOPT_RA:
286172686Smlaier			if (option_len < 4) {
287276788Sdelphij				ND_PRINT((ndo, " [bad length %u]", option_len));
288172686Smlaier				break;
289172686Smlaier			}
290276788Sdelphij			ND_TCHECK(cp[3]);
291276788Sdelphij			if (EXTRACT_16BITS(&cp[2]) != 0)
292276788Sdelphij				ND_PRINT((ndo, " value %u", EXTRACT_16BITS(&cp[2])));
29398527Sfenner			break;
29417691Spst
295146778Ssam		case IPOPT_NOP:       /* nothing to print - fall through */
296146778Ssam		case IPOPT_SECURITY:
29717680Spst		default:
29817680Spst			break;
29917680Spst		}
30017680Spst	}
301127675Sbms	return;
302127675Sbms
303127675Sbmstrunc:
304276788Sdelphij	ND_PRINT((ndo, "%s", tstr));
30517680Spst}
30617680Spst
307127675Sbms#define IP_RES 0x8000
308127675Sbms
309276788Sdelphijstatic const struct tok ip_frag_values[] = {
310127675Sbms        { IP_MF,        "+" },
311127675Sbms        { IP_DF,        "DF" },
312127675Sbms	{ IP_RES,       "rsvd" }, /* The RFC3514 evil ;-) bit */
313127675Sbms        { 0,            NULL }
314127675Sbms};
315127675Sbms
316146778Ssamstruct ip_print_demux_state {
317146778Ssam	const struct ip *ip;
318146778Ssam	const u_char *cp;
319146778Ssam	u_int   len, off;
320146778Ssam	u_char  nh;
321146778Ssam	int     advance;
322146778Ssam};
323146778Ssam
324146778Ssamstatic void
325146778Ssamip_print_demux(netdissect_options *ndo,
326146778Ssam	       struct ip_print_demux_state *ipds)
327146778Ssam{
328146778Ssam	struct protoent *proto;
329235530Sdelphij	struct cksum_vec vec[1];
330146778Ssam
331146778Ssamagain:
332146778Ssam	switch (ipds->nh) {
333146778Ssam
334146778Ssam	case IPPROTO_AH:
335146778Ssam		ipds->nh = *ipds->cp;
336276788Sdelphij		ipds->advance = ah_print(ndo, ipds->cp);
337146778Ssam		if (ipds->advance <= 0)
338146778Ssam			break;
339146778Ssam		ipds->cp += ipds->advance;
340146778Ssam		ipds->len -= ipds->advance;
341146778Ssam		goto again;
342146778Ssam
343146778Ssam	case IPPROTO_ESP:
344146778Ssam	{
345146778Ssam		int enh, padlen;
346146778Ssam		ipds->advance = esp_print(ndo, ipds->cp, ipds->len,
347146778Ssam				    (const u_char *)ipds->ip,
348146778Ssam				    &enh, &padlen);
349146778Ssam		if (ipds->advance <= 0)
350146778Ssam			break;
351146778Ssam		ipds->cp += ipds->advance;
352146778Ssam		ipds->len -= ipds->advance + padlen;
353146778Ssam		ipds->nh = enh & 0xff;
354146778Ssam		goto again;
355146778Ssam	}
356241235Sdelphij
357146778Ssam	case IPPROTO_IPCOMP:
358146778Ssam	{
359146778Ssam		int enh;
360276788Sdelphij		ipds->advance = ipcomp_print(ndo, ipds->cp, &enh);
361146778Ssam		if (ipds->advance <= 0)
362146778Ssam			break;
363146778Ssam		ipds->cp += ipds->advance;
364146778Ssam		ipds->len -= ipds->advance;
365146778Ssam		ipds->nh = enh & 0xff;
366146778Ssam		goto again;
367146778Ssam	}
368146778Ssam
369146778Ssam	case IPPROTO_SCTP:
370276788Sdelphij		sctp_print(ndo, ipds->cp, (const u_char *)ipds->ip, ipds->len);
371146778Ssam		break;
372162021Ssam
373162021Ssam	case IPPROTO_DCCP:
374276788Sdelphij		dccp_print(ndo, ipds->cp, (const u_char *)ipds->ip, ipds->len);
375162021Ssam		break;
376241235Sdelphij
377146778Ssam	case IPPROTO_TCP:
378172686Smlaier		/* pass on the MF bit plus the offset to detect fragments */
379276788Sdelphij		tcp_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip,
380172686Smlaier			  ipds->off & (IP_MF|IP_OFFMASK));
381146778Ssam		break;
382241235Sdelphij
383146778Ssam	case IPPROTO_UDP:
384172686Smlaier		/* pass on the MF bit plus the offset to detect fragments */
385276788Sdelphij		udp_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip,
386172686Smlaier			  ipds->off & (IP_MF|IP_OFFMASK));
387146778Ssam		break;
388241235Sdelphij
389146778Ssam	case IPPROTO_ICMP:
390146778Ssam		/* pass on the MF bit plus the offset to detect fragments */
391276788Sdelphij		icmp_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip,
392172686Smlaier			   ipds->off & (IP_MF|IP_OFFMASK));
393146778Ssam		break;
394241235Sdelphij
395146778Ssam	case IPPROTO_PIGP:
396146778Ssam		/*
397146778Ssam		 * XXX - the current IANA protocol number assignments
398146778Ssam		 * page lists 9 as "any private interior gateway
399146778Ssam		 * (used by Cisco for their IGRP)" and 88 as
400146778Ssam		 * "EIGRP" from Cisco.
401146778Ssam		 *
402146778Ssam		 * Recent BSD <netinet/in.h> headers define
403146778Ssam		 * IP_PROTO_PIGP as 9 and IP_PROTO_IGRP as 88.
404146778Ssam		 * We define IP_PROTO_PIGP as 9 and
405146778Ssam		 * IP_PROTO_EIGRP as 88; those names better
406146778Ssam		 * match was the current protocol number
407146778Ssam		 * assignments say.
408146778Ssam		 */
409276788Sdelphij		igrp_print(ndo, ipds->cp, ipds->len);
410146778Ssam		break;
411241235Sdelphij
412146778Ssam	case IPPROTO_EIGRP:
413276788Sdelphij		eigrp_print(ndo, ipds->cp, ipds->len);
414146778Ssam		break;
415241235Sdelphij
416146778Ssam	case IPPROTO_ND:
417146778Ssam		ND_PRINT((ndo, " nd %d", ipds->len));
418146778Ssam		break;
419146778Ssam
420146778Ssam	case IPPROTO_EGP:
421276788Sdelphij		egp_print(ndo, ipds->cp, ipds->len);
422146778Ssam		break;
423146778Ssam
424146778Ssam	case IPPROTO_OSPF:
425276788Sdelphij		ospf_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip);
426146778Ssam		break;
427146778Ssam
428146778Ssam	case IPPROTO_IGMP:
429276788Sdelphij		igmp_print(ndo, ipds->cp, ipds->len);
430146778Ssam		break;
431146778Ssam
432146778Ssam	case IPPROTO_IPV4:
433146778Ssam		/* DVMRP multicast tunnel (ip-in-ip encapsulation) */
434235530Sdelphij		ip_print(ndo, ipds->cp, ipds->len);
435276788Sdelphij		if (! ndo->ndo_vflag) {
436146778Ssam			ND_PRINT((ndo, " (ipip-proto-4)"));
437146778Ssam			return;
438146778Ssam		}
439146778Ssam		break;
440241235Sdelphij
441146778Ssam#ifdef INET6
442146778Ssam	case IPPROTO_IPV6:
443146778Ssam		/* ip6-in-ip encapsulation */
444235530Sdelphij		ip6_print(ndo, ipds->cp, ipds->len);
445146778Ssam		break;
446146778Ssam#endif /*INET6*/
447146778Ssam
448146778Ssam	case IPPROTO_RSVP:
449276788Sdelphij		rsvp_print(ndo, ipds->cp, ipds->len);
450146778Ssam		break;
451146778Ssam
452146778Ssam	case IPPROTO_GRE:
453146778Ssam		/* do it */
454276788Sdelphij		gre_print(ndo, ipds->cp, ipds->len);
455146778Ssam		break;
456146778Ssam
457146778Ssam	case IPPROTO_MOBILE:
458276788Sdelphij		mobile_print(ndo, ipds->cp, ipds->len);
459146778Ssam		break;
460146778Ssam
461146778Ssam	case IPPROTO_PIM:
462235530Sdelphij		vec[0].ptr = ipds->cp;
463235530Sdelphij		vec[0].len = ipds->len;
464276788Sdelphij		pim_print(ndo, ipds->cp, ipds->len, in_cksum(vec, 1));
465146778Ssam		break;
466146778Ssam
467146778Ssam	case IPPROTO_VRRP:
468276788Sdelphij		if (ndo->ndo_packettype == PT_CARP) {
469276788Sdelphij			if (ndo->ndo_vflag)
470276788Sdelphij				ND_PRINT((ndo, "carp %s > %s: ",
471276788Sdelphij					     ipaddr_string(ndo, &ipds->ip->ip_src),
472276788Sdelphij					     ipaddr_string(ndo, &ipds->ip->ip_dst)));
473276788Sdelphij			carp_print(ndo, ipds->cp, ipds->len, ipds->ip->ip_ttl);
474235530Sdelphij		} else {
475276788Sdelphij			if (ndo->ndo_vflag)
476276788Sdelphij				ND_PRINT((ndo, "vrrp %s > %s: ",
477276788Sdelphij					     ipaddr_string(ndo, &ipds->ip->ip_src),
478276788Sdelphij					     ipaddr_string(ndo, &ipds->ip->ip_dst)));
479276788Sdelphij			vrrp_print(ndo, ipds->cp, ipds->len,
480276788Sdelphij				(const u_char *)ipds->ip, ipds->ip->ip_ttl);
481235530Sdelphij		}
482146778Ssam		break;
483146778Ssam
484147904Ssam	case IPPROTO_PGM:
485276788Sdelphij		pgm_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip);
486147904Ssam		break;
487147904Ssam
488257349Sglebius#if defined(HAVE_NET_PFVAR_H)
489241221Sglebius	case IPPROTO_PFSYNC:
490241221Sglebius		pfsync_ip_print(ipds->cp, ipds->len);
491241221Sglebius		break;
492257349Sglebius#endif
493241221Sglebius
494146778Ssam	default:
495241235Sdelphij		if (ndo->ndo_nflag==0 && (proto = getprotobynumber(ipds->nh)) != NULL)
496146778Ssam			ND_PRINT((ndo, " %s", proto->p_name));
497146778Ssam		else
498146778Ssam			ND_PRINT((ndo, " ip-proto-%d", ipds->nh));
499146778Ssam		ND_PRINT((ndo, " %d", ipds->len));
500146778Ssam		break;
501146778Ssam	}
502146778Ssam}
503241235Sdelphij
504146778Ssamvoid
505146778Ssamip_print_inner(netdissect_options *ndo,
506146778Ssam	       const u_char *bp,
507146778Ssam	       u_int length, u_int nh,
508146778Ssam	       const u_char *bp2)
509146778Ssam{
510146778Ssam	struct ip_print_demux_state  ipd;
511146778Ssam
512146778Ssam	ipd.ip = (const struct ip *)bp2;
513146778Ssam	ipd.cp = bp;
514146778Ssam	ipd.len  = length;
515146778Ssam	ipd.off  = 0;
516146778Ssam	ipd.nh   = nh;
517146778Ssam	ipd.advance = 0;
518146778Ssam
519146778Ssam	ip_print_demux(ndo, &ipd);
520146778Ssam}
521146778Ssam
522146778Ssam
523127675Sbms/*
52417680Spst * print an IP datagram.
52517680Spst */
52617680Spstvoid
527146778Ssamip_print(netdissect_options *ndo,
528146778Ssam	 const u_char *bp,
529146778Ssam	 u_int length)
53017680Spst{
531146778Ssam	struct ip_print_demux_state  ipd;
532146778Ssam	struct ip_print_demux_state *ipds=&ipd;
533127675Sbms	const u_char *ipend;
534146778Ssam	u_int hlen;
535235530Sdelphij	struct cksum_vec vec[1];
536276788Sdelphij	uint16_t sum, ip_sum;
537111729Sfenner	struct protoent *proto;
53817680Spst
539146778Ssam	ipds->ip = (const struct ip *)bp;
540277783Spfg	ND_TCHECK(ipds->ip->ip_vhl);
541146778Ssam	if (IP_V(ipds->ip) != 4) { /* print version if != 4 */
542276788Sdelphij	    ND_PRINT((ndo, "IP%u ", IP_V(ipds->ip)));
543146778Ssam	    if (IP_V(ipds->ip) == 6)
544276788Sdelphij	      ND_PRINT((ndo, ", wrong link-layer encapsulation"));
545127675Sbms	}
546276788Sdelphij	else if (!ndo->ndo_eflag)
547276788Sdelphij		ND_PRINT((ndo, "IP "));
54817680Spst
549277783Spfg	ND_TCHECK(*ipds->ip);
55017680Spst	if (length < sizeof (struct ip)) {
551276788Sdelphij		ND_PRINT((ndo, "truncated-ip %u", length));
55217680Spst		return;
55317680Spst	}
554146778Ssam	hlen = IP_HL(ipds->ip) * 4;
55575118Sfenner	if (hlen < sizeof (struct ip)) {
556276788Sdelphij		ND_PRINT((ndo, "bad-hlen %u", hlen));
55775118Sfenner		return;
55875118Sfenner	}
55917680Spst
560146778Ssam	ipds->len = EXTRACT_16BITS(&ipds->ip->ip_len);
561146778Ssam	if (length < ipds->len)
562276788Sdelphij		ND_PRINT((ndo, "truncated-ip - %u bytes missing! ",
563276788Sdelphij			ipds->len - length));
564146778Ssam	if (ipds->len < hlen) {
565146778Ssam#ifdef GUESS_TSO
566146778Ssam            if (ipds->len) {
567276788Sdelphij                ND_PRINT((ndo, "bad-len %u", ipds->len));
568146778Ssam                return;
569146778Ssam            }
570146778Ssam            else {
571146778Ssam                /* we guess that it is a TSO send */
572146778Ssam                ipds->len = length;
573146778Ssam            }
574146778Ssam#else
575276788Sdelphij            ND_PRINT((ndo, "bad-len %u", ipds->len));
576146778Ssam            return;
577146778Ssam#endif /* GUESS_TSO */
578127675Sbms	}
579127675Sbms
580127675Sbms	/*
581127675Sbms	 * Cut off the snapshot length to the end of the IP payload.
582127675Sbms	 */
583146778Ssam	ipend = bp + ipds->len;
584235530Sdelphij	if (ipend < ndo->ndo_snapend)
585235530Sdelphij		ndo->ndo_snapend = ipend;
586127675Sbms
587146778Ssam	ipds->len -= hlen;
58817680Spst
589146778Ssam	ipds->off = EXTRACT_16BITS(&ipds->ip->ip_off);
590127675Sbms
591276788Sdelphij        if (ndo->ndo_vflag) {
592276788Sdelphij            ND_PRINT((ndo, "(tos 0x%x", (int)ipds->ip->ip_tos));
593127675Sbms            /* ECN bits */
594146778Ssam            if (ipds->ip->ip_tos & 0x03) {
595146778Ssam                switch (ipds->ip->ip_tos & 0x03) {
596127675Sbms                case 1:
597276788Sdelphij                    ND_PRINT((ndo, ",ECT(1)"));
598127675Sbms                    break;
599127675Sbms                case 2:
600276788Sdelphij                    ND_PRINT((ndo, ",ECT(0)"));
601127675Sbms                    break;
602127675Sbms                case 3:
603276788Sdelphij                    ND_PRINT((ndo, ",CE"));
604127675Sbms                }
605127675Sbms            }
606127675Sbms
607146778Ssam            if (ipds->ip->ip_ttl >= 1)
608276788Sdelphij                ND_PRINT((ndo, ", ttl %u", ipds->ip->ip_ttl));
609127675Sbms
610127675Sbms	    /*
611127675Sbms	     * for the firewall guys, print id, offset.
612127675Sbms             * On all but the last stick a "+" in the flags portion.
613127675Sbms	     * For unfragmented datagrams, note the don't fragment flag.
614127675Sbms	     */
615127675Sbms
616276788Sdelphij	    ND_PRINT((ndo, ", id %u, offset %u, flags [%s], proto %s (%u)",
617146778Ssam                         EXTRACT_16BITS(&ipds->ip->ip_id),
618146778Ssam                         (ipds->off & 0x1fff) * 8,
619172686Smlaier                         bittok2str(ip_frag_values, "none", ipds->off&0xe000),
620146778Ssam                         tok2str(ipproto_values,"unknown",ipds->ip->ip_p),
621276788Sdelphij                         ipds->ip->ip_p));
622127675Sbms
623276788Sdelphij            ND_PRINT((ndo, ", length %u", EXTRACT_16BITS(&ipds->ip->ip_len)));
624127675Sbms
625127675Sbms            if ((hlen - sizeof(struct ip)) > 0) {
626276788Sdelphij                ND_PRINT((ndo, ", options ("));
627276788Sdelphij                ip_optprint(ndo, (u_char *)(ipds->ip + 1), hlen - sizeof(struct ip));
628276788Sdelphij                ND_PRINT((ndo, ")"));
629127675Sbms            }
630127675Sbms
631276788Sdelphij	    if (!ndo->ndo_Kflag && (u_char *)ipds->ip + hlen <= ndo->ndo_snapend) {
632276788Sdelphij	        vec[0].ptr = (const uint8_t *)(void *)ipds->ip;
633235530Sdelphij	        vec[0].len = hlen;
634235530Sdelphij	        sum = in_cksum(vec, 1);
635127675Sbms		if (sum != 0) {
636146778Ssam		    ip_sum = EXTRACT_16BITS(&ipds->ip->ip_sum);
637276788Sdelphij		    ND_PRINT((ndo, ", bad cksum %x (->%x)!", ip_sum,
638276788Sdelphij			     in_cksum_shouldbe(ip_sum, sum)));
639127675Sbms		}
640127675Sbms	    }
641127675Sbms
642276788Sdelphij		ND_PRINT((ndo, ")\n    "));
643127675Sbms	}
644127675Sbms
64517680Spst	/*
64617680Spst	 * If this is fragment zero, hand it to the next higher
64717680Spst	 * level protocol.
64817680Spst	 */
649146778Ssam	if ((ipds->off & 0x1fff) == 0) {
650146778Ssam		ipds->cp = (const u_char *)ipds->ip + hlen;
651146778Ssam		ipds->nh = ipds->ip->ip_p;
65217680Spst
653146778Ssam		if (ipds->nh != IPPROTO_TCP && ipds->nh != IPPROTO_UDP &&
654162021Ssam		    ipds->nh != IPPROTO_SCTP && ipds->nh != IPPROTO_DCCP) {
655276788Sdelphij			ND_PRINT((ndo, "%s > %s: ",
656276788Sdelphij				     ipaddr_string(ndo, &ipds->ip->ip_src),
657276788Sdelphij				     ipaddr_string(ndo, &ipds->ip->ip_dst)));
65856896Sfenner		}
659146778Ssam		ip_print_demux(ndo, ipds);
660127675Sbms	} else {
661127675Sbms	    /* Ultra quiet now means that all this stuff should be suppressed */
662276788Sdelphij	    if (ndo->ndo_qflag > 1) return;
66356896Sfenner
664127675Sbms	    /*
665127675Sbms	     * if this isn't the first frag, we're missing the
666127675Sbms	     * next level protocol header.  print the ip addr
667127675Sbms	     * and the protocol.
668127675Sbms	     */
669276788Sdelphij		if (ipds->off & 0x1fff) {
670276788Sdelphij			ND_PRINT((ndo, "%s > %s:", ipaddr_string(ndo, &ipds->ip->ip_src),
671276788Sdelphij			          ipaddr_string(ndo, &ipds->ip->ip_dst)));
672276788Sdelphij			if (!ndo->ndo_nflag && (proto = getprotobynumber(ipds->ip->ip_p)) != NULL)
673276788Sdelphij				ND_PRINT((ndo, " %s", proto->p_name));
674276788Sdelphij			else
675276788Sdelphij				ND_PRINT((ndo, " ip-proto-%d", ipds->ip->ip_p));
676276788Sdelphij		}
67756896Sfenner	}
678277783Spfg	return;
679277783Spfg
680277783Spfgtrunc:
681277783Spfg	ND_PRINT((ndo, "%s", tstr));
682277783Spfg	return;
68317680Spst}
68475118Sfenner
68575118Sfennervoid
686276788SdelphijipN_print(netdissect_options *ndo, register const u_char *bp, register u_int length)
68775118Sfenner{
688276788Sdelphij	struct ip hdr;
68975118Sfenner
69075118Sfenner	if (length < 4) {
691276788Sdelphij		ND_PRINT((ndo, "truncated-ip %d", length));
69275118Sfenner		return;
69375118Sfenner	}
694276788Sdelphij	memcpy (&hdr, bp, 4);
69575118Sfenner	switch (IP_V(&hdr)) {
69675118Sfenner	case 4:
697276788Sdelphij		ip_print (ndo, bp, length);
69898527Sfenner		return;
69975118Sfenner#ifdef INET6
70075118Sfenner	case 6:
701276788Sdelphij		ip6_print (ndo, bp, length);
70298527Sfenner		return;
70375118Sfenner#endif
70475118Sfenner	default:
705276788Sdelphij		ND_PRINT((ndo, "unknown ip %d", IP_V(&hdr)));
70698527Sfenner		return;
70775118Sfenner	}
70875118Sfenner}
709127675Sbms
710146778Ssam/*
711146778Ssam * Local Variables:
712146778Ssam * c-style: whitesmith
713146778Ssam * c-basic-offset: 8
714146778Ssam * End:
715146778Ssam */
716127675Sbms
717127675Sbms
718