print-ip.c revision 241235
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 241235 2012-10-05 20:19:28Z delphij $
2217680Spst */
2317680Spst
2417680Spst#ifndef lint
25127675Sbmsstatic const char rcsid[] _U_ =
26190207Srpaulo    "@(#) $Header: /tcpdump/master/tcpdump/print-ip.c,v 1.159 2007-09-14 01:29:28 guy Exp $ (LBL)";
2717680Spst#endif
2817680Spst
2956896Sfenner#ifdef HAVE_CONFIG_H
3056896Sfenner#include "config.h"
3156896Sfenner#endif
3256896Sfenner
33127675Sbms#include <tcpdump-stdinc.h>
3417680Spst
3517680Spst#include <stdio.h>
3617680Spst#include <stdlib.h>
3717680Spst#include <string.h>
3817680Spst
3917680Spst#include "addrtoname.h"
4017680Spst#include "interface.h"
4117680Spst#include "extract.h"			/* must come after interface.h */
4217680Spst
4375118Sfenner#include "ip.h"
44127675Sbms#include "ipproto.h"
4575118Sfenner
46146778Ssamstruct tok ip_option_values[] = {
47146778Ssam    { IPOPT_EOL, "EOL" },
48146778Ssam    { IPOPT_NOP, "NOP" },
49146778Ssam    { IPOPT_TS, "timestamp" },
50146778Ssam    { IPOPT_SECURITY, "security" },
51146778Ssam    { IPOPT_RR, "RR" },
52146778Ssam    { IPOPT_SSRR, "SSRR" },
53146778Ssam    { IPOPT_LSRR, "LSRR" },
54146778Ssam    { IPOPT_RA, "RA" },
55172686Smlaier    { IPOPT_RFC1393, "traceroute" },
56146778Ssam    { 0, NULL }
57146778Ssam};
58146778Ssam
5917680Spst/*
6017680Spst * print the recorded route in an IP RR, LSRR or SSRR option.
6117680Spst */
6217680Spststatic void
63146778Ssamip_printroute(register const u_char *cp, u_int length)
6417680Spst{
65127675Sbms	register u_int ptr;
6617680Spst	register u_int len;
6717680Spst
68127675Sbms	if (length < 3) {
69127675Sbms		printf(" [bad length %u]", length);
70127675Sbms		return;
71127675Sbms	}
7217680Spst	if ((length + 1) & 3)
73127675Sbms		printf(" [bad length %u]", length);
74127675Sbms	ptr = cp[2] - 1;
7517680Spst	if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1)
76127675Sbms		printf(" [bad ptr %u]", cp[2]);
7717680Spst
7817680Spst	for (len = 3; len < length; len += 4) {
79172686Smlaier		printf(" %s", ipaddr_string(&cp[len]));
80146778Ssam                if (ptr > len)
81172686Smlaier                        printf(",");
8217680Spst	}
8317680Spst}
8417680Spst
85127675Sbms/*
86146778Ssam * If source-routing is present and valid, return the final destination.
87127675Sbms * Otherwise, return IP destination.
88127675Sbms *
89127675Sbms * This is used for UDP and TCP pseudo-header in the checksum
90127675Sbms * calculation.
91127675Sbms */
92235530Sdelphijstatic u_int32_t
93127675Sbmsip_finddst(const struct ip *ip)
94127675Sbms{
95127675Sbms	int length;
96127675Sbms	int len;
97127675Sbms	const u_char *cp;
98127675Sbms	u_int32_t retval;
99127675Sbms
100127675Sbms	cp = (const u_char *)(ip + 1);
101127675Sbms	length = (IP_HL(ip) << 2) - sizeof(struct ip);
102127675Sbms
103127675Sbms	for (; length > 0; cp += len, length -= len) {
104127675Sbms		int tt;
105127675Sbms
106127675Sbms		TCHECK(*cp);
107127675Sbms		tt = *cp;
108146778Ssam		if (tt == IPOPT_EOL)
109146778Ssam			break;
110146778Ssam		else if (tt == IPOPT_NOP)
111127675Sbms			len = 1;
112127675Sbms		else {
113127675Sbms			TCHECK(cp[1]);
114127675Sbms			len = cp[1];
115146778Ssam			if (len < 2)
116146778Ssam				break;
117127675Sbms		}
118127675Sbms		TCHECK2(*cp, len);
119127675Sbms		switch (tt) {
120127675Sbms
121127675Sbms		case IPOPT_SSRR:
122127675Sbms		case IPOPT_LSRR:
123127675Sbms			if (len < 7)
124146778Ssam				break;
125127675Sbms			memcpy(&retval, cp + len - 4, 4);
126127675Sbms			return retval;
127127675Sbms		}
128127675Sbms	}
129127675Sbmstrunc:
130146778Ssam	memcpy(&retval, &ip->ip_dst.s_addr, sizeof(u_int32_t));
131146778Ssam	return retval;
132127675Sbms}
133127675Sbms
134235530Sdelphij/*
135235530Sdelphij * Compute a V4-style checksum by building a pseudoheader.
136235530Sdelphij */
137235530Sdelphijint
138235530Sdelphijnextproto4_cksum(const struct ip *ip, const u_int8_t *data,
139235530Sdelphij		 u_int len, u_int next_proto)
140235530Sdelphij{
141235530Sdelphij	struct phdr {
142235530Sdelphij		u_int32_t src;
143235530Sdelphij		u_int32_t dst;
144235530Sdelphij		u_char mbz;
145235530Sdelphij		u_char proto;
146235530Sdelphij		u_int16_t len;
147235530Sdelphij	} ph;
148235530Sdelphij	struct cksum_vec vec[2];
149235530Sdelphij
150235530Sdelphij	/* pseudo-header.. */
151235530Sdelphij	ph.len = htons((u_int16_t)len);
152235530Sdelphij	ph.mbz = 0;
153235530Sdelphij	ph.proto = next_proto;
154235530Sdelphij	memcpy(&ph.src, &ip->ip_src.s_addr, sizeof(u_int32_t));
155235530Sdelphij	if (IP_HL(ip) == 5)
156235530Sdelphij		memcpy(&ph.dst, &ip->ip_dst.s_addr, sizeof(u_int32_t));
157235530Sdelphij	else
158235530Sdelphij		ph.dst = ip_finddst(ip);
159235530Sdelphij
160235530Sdelphij	vec[0].ptr = (const u_int8_t *)(void *)&ph;
161235530Sdelphij	vec[0].len = sizeof(ph);
162235530Sdelphij	vec[1].ptr = data;
163235530Sdelphij	vec[1].len = len;
164235530Sdelphij	return (in_cksum(vec, 2));
165235530Sdelphij}
166235530Sdelphij
16756896Sfennerstatic void
16856896Sfennerip_printts(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) {
176172686Smlaier		printf("[bad length %u]", length);
177127675Sbms		return;
178127675Sbms	}
17956896Sfenner	printf(" TS{");
18056896Sfenner	hoplen = ((cp[3]&0xF) != IPOPT_TS_TSONLY) ? 8 : 4;
18156896Sfenner	if ((length - 4) & (hoplen-1))
182172686Smlaier		printf("[bad length %u]", length);
183127675Sbms	ptr = cp[2] - 1;
184127675Sbms	len = 0;
18556896Sfenner	if (ptr < 4 || ((ptr - 4) & (hoplen-1)) || ptr > length + 1)
186172686Smlaier		printf("[bad ptr %u]", cp[2]);
18756896Sfenner	switch (cp[3]&0xF) {
18856896Sfenner	case IPOPT_TS_TSONLY:
18956896Sfenner		printf("TSONLY");
19056896Sfenner		break;
19156896Sfenner	case IPOPT_TS_TSANDADDR:
19256896Sfenner		printf("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:
20156896Sfenner		printf("PRESPEC2.0");
20256896Sfenner		break;
20356896Sfenner	case 3:			/* IPOPT_TS_PRESPEC */
20456896Sfenner		printf("PRESPEC");
20556896Sfenner		break;
206127675Sbms	default:
20756896Sfenner		printf("[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 = " ^ ";
21556896Sfenner		printf("%s%d@%s", type, EXTRACT_32BITS(&cp[len+hoplen-4]),
21656896Sfenner		       hoplen!=8 ? "" : ipaddr_string(&cp[len]));
21756896Sfenner		type = " ";
21856896Sfenner	}
21956896Sfenner
22056896Sfennerdone:
22156896Sfenner	printf("%s", ptr == len ? " ^ " : "");
22256896Sfenner
22356896Sfenner	if (cp[3]>>4)
22456896Sfenner		printf(" [%d hops not recorded]} ", cp[3]>>4);
22556896Sfenner	else
22656896Sfenner		printf("}");
22756896Sfenner}
22856896Sfenner
22917680Spst/*
23017680Spst * print IP options.
23117680Spst */
23217680Spststatic void
23317680Spstip_optprint(register const u_char *cp, u_int length)
23417680Spst{
235146778Ssam	register u_int option_len;
236172686Smlaier	const char *sep = "";
23717680Spst
238146778Ssam	for (; length > 0; cp += option_len, length -= option_len) {
239146778Ssam		u_int option_code;
24017680Spst
241172686Smlaier		printf("%s", sep);
242172686Smlaier		sep = ",";
243172686Smlaier
244127675Sbms		TCHECK(*cp);
245146778Ssam		option_code = *cp;
246146778Ssam
247172686Smlaier                printf("%s",
248172686Smlaier                        tok2str(ip_option_values,"unknown %u",option_code));
249172686Smlaier
250146778Ssam		if (option_code == IPOPT_NOP ||
251146778Ssam                    option_code == IPOPT_EOL)
252146778Ssam			option_len = 1;
253146778Ssam
25475118Sfenner		else {
255127675Sbms			TCHECK(cp[1]);
256172686Smlaier			option_len = cp[1];
257172686Smlaier			if (option_len < 2) {
258172686Smlaier		                printf(" [bad length %u]", option_len);
259172686Smlaier				return;
260172686Smlaier			}
26175118Sfenner		}
26217680Spst
263172686Smlaier		if (option_len > length) {
264172686Smlaier	                printf(" [bad length %u]", option_len);
265172686Smlaier			return;
266172686Smlaier		}
267146778Ssam
268146778Ssam                TCHECK2(*cp, option_len);
269146778Ssam
270146778Ssam		switch (option_code) {
27117680Spst		case IPOPT_EOL:
27217680Spst			return;
27317680Spst
27417680Spst		case IPOPT_TS:
275146778Ssam			ip_printts(cp, option_len);
27617680Spst			break;
27717680Spst
278146778Ssam		case IPOPT_RR:       /* fall through */
27917680Spst		case IPOPT_SSRR:
28017680Spst		case IPOPT_LSRR:
281172686Smlaier			ip_printroute(cp, option_len);
28217680Spst			break;
28317680Spst
28417691Spst		case IPOPT_RA:
285172686Smlaier			if (option_len < 4) {
286172686Smlaier				printf(" [bad length %u]", option_len);
287172686Smlaier				break;
288172686Smlaier			}
289146778Ssam                        TCHECK(cp[3]);
290146778Ssam                        if (EXTRACT_16BITS(&cp[2]) != 0)
291172686Smlaier                            printf(" value %u", EXTRACT_16BITS(&cp[2]));
29298527Sfenner			break;
29317691Spst
294146778Ssam		case IPOPT_NOP:       /* nothing to print - fall through */
295146778Ssam		case IPOPT_SECURITY:
29617680Spst		default:
29717680Spst			break;
29817680Spst		}
29917680Spst	}
300127675Sbms	return;
301127675Sbms
302127675Sbmstrunc:
303127675Sbms	printf("[|ip]");
30417680Spst}
30517680Spst
306127675Sbms#define IP_RES 0x8000
307127675Sbms
308127675Sbmsstatic struct tok ip_frag_values[] = {
309127675Sbms        { IP_MF,        "+" },
310127675Sbms        { IP_DF,        "DF" },
311127675Sbms	{ IP_RES,       "rsvd" }, /* The RFC3514 evil ;-) bit */
312127675Sbms        { 0,            NULL }
313127675Sbms};
314127675Sbms
315146778Ssamstruct ip_print_demux_state {
316146778Ssam	const struct ip *ip;
317146778Ssam	const u_char *cp;
318146778Ssam	u_int   len, off;
319146778Ssam	u_char  nh;
320146778Ssam	int     advance;
321146778Ssam};
322146778Ssam
323146778Ssamstatic void
324146778Ssamip_print_demux(netdissect_options *ndo,
325146778Ssam	       struct ip_print_demux_state *ipds)
326146778Ssam{
327146778Ssam	struct protoent *proto;
328235530Sdelphij	struct cksum_vec vec[1];
329146778Ssam
330146778Ssamagain:
331146778Ssam	switch (ipds->nh) {
332146778Ssam
333146778Ssam	case IPPROTO_AH:
334146778Ssam		ipds->nh = *ipds->cp;
335146778Ssam		ipds->advance = ah_print(ipds->cp);
336146778Ssam		if (ipds->advance <= 0)
337146778Ssam			break;
338146778Ssam		ipds->cp += ipds->advance;
339146778Ssam		ipds->len -= ipds->advance;
340146778Ssam		goto again;
341146778Ssam
342146778Ssam	case IPPROTO_ESP:
343146778Ssam	{
344146778Ssam		int enh, padlen;
345146778Ssam		ipds->advance = esp_print(ndo, ipds->cp, ipds->len,
346146778Ssam				    (const u_char *)ipds->ip,
347146778Ssam				    &enh, &padlen);
348146778Ssam		if (ipds->advance <= 0)
349146778Ssam			break;
350146778Ssam		ipds->cp += ipds->advance;
351146778Ssam		ipds->len -= ipds->advance + padlen;
352146778Ssam		ipds->nh = enh & 0xff;
353146778Ssam		goto again;
354146778Ssam	}
355241235Sdelphij
356146778Ssam	case IPPROTO_IPCOMP:
357146778Ssam	{
358146778Ssam		int enh;
359146778Ssam		ipds->advance = ipcomp_print(ipds->cp, &enh);
360146778Ssam		if (ipds->advance <= 0)
361146778Ssam			break;
362146778Ssam		ipds->cp += ipds->advance;
363146778Ssam		ipds->len -= ipds->advance;
364146778Ssam		ipds->nh = enh & 0xff;
365146778Ssam		goto again;
366146778Ssam	}
367146778Ssam
368146778Ssam	case IPPROTO_SCTP:
369146778Ssam		sctp_print(ipds->cp, (const u_char *)ipds->ip, ipds->len);
370146778Ssam		break;
371162021Ssam
372162021Ssam	case IPPROTO_DCCP:
373162021Ssam		dccp_print(ipds->cp, (const u_char *)ipds->ip, ipds->len);
374162021Ssam		break;
375241235Sdelphij
376146778Ssam	case IPPROTO_TCP:
377172686Smlaier		/* pass on the MF bit plus the offset to detect fragments */
378146778Ssam		tcp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip,
379172686Smlaier			  ipds->off & (IP_MF|IP_OFFMASK));
380146778Ssam		break;
381241235Sdelphij
382146778Ssam	case IPPROTO_UDP:
383172686Smlaier		/* pass on the MF bit plus the offset to detect fragments */
384146778Ssam		udp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip,
385172686Smlaier			  ipds->off & (IP_MF|IP_OFFMASK));
386146778Ssam		break;
387241235Sdelphij
388146778Ssam	case IPPROTO_ICMP:
389146778Ssam		/* pass on the MF bit plus the offset to detect fragments */
390146778Ssam		icmp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip,
391172686Smlaier			   ipds->off & (IP_MF|IP_OFFMASK));
392146778Ssam		break;
393241235Sdelphij
394146778Ssam	case IPPROTO_PIGP:
395146778Ssam		/*
396146778Ssam		 * XXX - the current IANA protocol number assignments
397146778Ssam		 * page lists 9 as "any private interior gateway
398146778Ssam		 * (used by Cisco for their IGRP)" and 88 as
399146778Ssam		 * "EIGRP" from Cisco.
400146778Ssam		 *
401146778Ssam		 * Recent BSD <netinet/in.h> headers define
402146778Ssam		 * IP_PROTO_PIGP as 9 and IP_PROTO_IGRP as 88.
403146778Ssam		 * We define IP_PROTO_PIGP as 9 and
404146778Ssam		 * IP_PROTO_EIGRP as 88; those names better
405146778Ssam		 * match was the current protocol number
406146778Ssam		 * assignments say.
407146778Ssam		 */
408146778Ssam		igrp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip);
409146778Ssam		break;
410241235Sdelphij
411146778Ssam	case IPPROTO_EIGRP:
412146778Ssam		eigrp_print(ipds->cp, ipds->len);
413146778Ssam		break;
414241235Sdelphij
415146778Ssam	case IPPROTO_ND:
416146778Ssam		ND_PRINT((ndo, " nd %d", ipds->len));
417146778Ssam		break;
418146778Ssam
419146778Ssam	case IPPROTO_EGP:
420146778Ssam		egp_print(ipds->cp, ipds->len);
421146778Ssam		break;
422146778Ssam
423146778Ssam	case IPPROTO_OSPF:
424146778Ssam		ospf_print(ipds->cp, ipds->len, (const u_char *)ipds->ip);
425146778Ssam		break;
426146778Ssam
427146778Ssam	case IPPROTO_IGMP:
428146778Ssam		igmp_print(ipds->cp, ipds->len);
429146778Ssam		break;
430146778Ssam
431146778Ssam	case IPPROTO_IPV4:
432146778Ssam		/* DVMRP multicast tunnel (ip-in-ip encapsulation) */
433235530Sdelphij		ip_print(ndo, ipds->cp, ipds->len);
434146778Ssam		if (! vflag) {
435146778Ssam			ND_PRINT((ndo, " (ipip-proto-4)"));
436146778Ssam			return;
437146778Ssam		}
438146778Ssam		break;
439241235Sdelphij
440146778Ssam#ifdef INET6
441146778Ssam	case IPPROTO_IPV6:
442146778Ssam		/* ip6-in-ip encapsulation */
443235530Sdelphij		ip6_print(ndo, ipds->cp, ipds->len);
444146778Ssam		break;
445146778Ssam#endif /*INET6*/
446146778Ssam
447146778Ssam	case IPPROTO_RSVP:
448146778Ssam		rsvp_print(ipds->cp, ipds->len);
449146778Ssam		break;
450146778Ssam
451146778Ssam	case IPPROTO_GRE:
452146778Ssam		/* do it */
453146778Ssam		gre_print(ipds->cp, ipds->len);
454146778Ssam		break;
455146778Ssam
456146778Ssam	case IPPROTO_MOBILE:
457146778Ssam		mobile_print(ipds->cp, ipds->len);
458146778Ssam		break;
459146778Ssam
460146778Ssam	case IPPROTO_PIM:
461235530Sdelphij		vec[0].ptr = ipds->cp;
462235530Sdelphij		vec[0].len = ipds->len;
463235530Sdelphij		pim_print(ipds->cp, ipds->len, in_cksum(vec, 1));
464146778Ssam		break;
465146778Ssam
466146778Ssam	case IPPROTO_VRRP:
467235530Sdelphij		if (packettype == PT_CARP) {
468235530Sdelphij			if (vflag)
469235530Sdelphij				(void)printf("carp %s > %s: ",
470235530Sdelphij					     ipaddr_string(&ipds->ip->ip_src),
471235530Sdelphij					     ipaddr_string(&ipds->ip->ip_dst));
472235530Sdelphij			carp_print(ipds->cp, ipds->len, ipds->ip->ip_ttl);
473235530Sdelphij		} else {
474235530Sdelphij			if (vflag)
475235530Sdelphij				(void)printf("vrrp %s > %s: ",
476235530Sdelphij					     ipaddr_string(&ipds->ip->ip_src),
477235530Sdelphij					     ipaddr_string(&ipds->ip->ip_dst));
478235530Sdelphij			vrrp_print(ipds->cp, ipds->len, ipds->ip->ip_ttl);
479235530Sdelphij		}
480146778Ssam		break;
481146778Ssam
482147904Ssam	case IPPROTO_PGM:
483147904Ssam		pgm_print(ipds->cp, ipds->len, (const u_char *)ipds->ip);
484147904Ssam		break;
485147904Ssam
486241221Sglebius	case IPPROTO_PFSYNC:
487241221Sglebius		pfsync_ip_print(ipds->cp, ipds->len);
488241221Sglebius		break;
489241221Sglebius
490146778Ssam	default:
491241235Sdelphij		if (ndo->ndo_nflag==0 && (proto = getprotobynumber(ipds->nh)) != NULL)
492146778Ssam			ND_PRINT((ndo, " %s", proto->p_name));
493146778Ssam		else
494146778Ssam			ND_PRINT((ndo, " ip-proto-%d", ipds->nh));
495146778Ssam		ND_PRINT((ndo, " %d", ipds->len));
496146778Ssam		break;
497146778Ssam	}
498146778Ssam}
499241235Sdelphij
500146778Ssamvoid
501146778Ssamip_print_inner(netdissect_options *ndo,
502146778Ssam	       const u_char *bp,
503146778Ssam	       u_int length, u_int nh,
504146778Ssam	       const u_char *bp2)
505146778Ssam{
506146778Ssam	struct ip_print_demux_state  ipd;
507146778Ssam
508146778Ssam	ipd.ip = (const struct ip *)bp2;
509146778Ssam	ipd.cp = bp;
510146778Ssam	ipd.len  = length;
511146778Ssam	ipd.off  = 0;
512146778Ssam	ipd.nh   = nh;
513146778Ssam	ipd.advance = 0;
514146778Ssam
515146778Ssam	ip_print_demux(ndo, &ipd);
516146778Ssam}
517146778Ssam
518146778Ssam
519127675Sbms/*
52017680Spst * print an IP datagram.
52117680Spst */
52217680Spstvoid
523146778Ssamip_print(netdissect_options *ndo,
524146778Ssam	 const u_char *bp,
525146778Ssam	 u_int length)
52617680Spst{
527146778Ssam	struct ip_print_demux_state  ipd;
528146778Ssam	struct ip_print_demux_state *ipds=&ipd;
529127675Sbms	const u_char *ipend;
530146778Ssam	u_int hlen;
531235530Sdelphij	struct cksum_vec vec[1];
532146778Ssam	u_int16_t sum, ip_sum;
533111729Sfenner	struct protoent *proto;
53417680Spst
535146778Ssam	ipds->ip = (const struct ip *)bp;
536146778Ssam	if (IP_V(ipds->ip) != 4) { /* print version if != 4 */
537146778Ssam	    printf("IP%u ", IP_V(ipds->ip));
538146778Ssam	    if (IP_V(ipds->ip) == 6)
539127675Sbms		printf(", wrong link-layer encapsulation");
540127675Sbms	}
541146778Ssam        else if (!eflag)
542127675Sbms	    printf("IP ");
54317680Spst
544235530Sdelphij	if ((u_char *)(ipds->ip + 1) > ndo->ndo_snapend) {
54517680Spst		printf("[|ip]");
54617680Spst		return;
54717680Spst	}
54817680Spst	if (length < sizeof (struct ip)) {
549146778Ssam		(void)printf("truncated-ip %u", length);
55017680Spst		return;
55117680Spst	}
552146778Ssam	hlen = IP_HL(ipds->ip) * 4;
55375118Sfenner	if (hlen < sizeof (struct ip)) {
554127675Sbms		(void)printf("bad-hlen %u", hlen);
55575118Sfenner		return;
55675118Sfenner	}
55717680Spst
558146778Ssam	ipds->len = EXTRACT_16BITS(&ipds->ip->ip_len);
559146778Ssam	if (length < ipds->len)
560127675Sbms		(void)printf("truncated-ip - %u bytes missing! ",
561146778Ssam			ipds->len - length);
562146778Ssam	if (ipds->len < hlen) {
563146778Ssam#ifdef GUESS_TSO
564146778Ssam            if (ipds->len) {
565146778Ssam                (void)printf("bad-len %u", ipds->len);
566146778Ssam                return;
567146778Ssam            }
568146778Ssam            else {
569146778Ssam                /* we guess that it is a TSO send */
570146778Ssam                ipds->len = length;
571146778Ssam            }
572146778Ssam#else
573146778Ssam            (void)printf("bad-len %u", ipds->len);
574146778Ssam            return;
575146778Ssam#endif /* GUESS_TSO */
576127675Sbms	}
577127675Sbms
578127675Sbms	/*
579127675Sbms	 * Cut off the snapshot length to the end of the IP payload.
580127675Sbms	 */
581146778Ssam	ipend = bp + ipds->len;
582235530Sdelphij	if (ipend < ndo->ndo_snapend)
583235530Sdelphij		ndo->ndo_snapend = ipend;
584127675Sbms
585146778Ssam	ipds->len -= hlen;
58617680Spst
587146778Ssam	ipds->off = EXTRACT_16BITS(&ipds->ip->ip_off);
588127675Sbms
589127675Sbms        if (vflag) {
590146778Ssam            (void)printf("(tos 0x%x", (int)ipds->ip->ip_tos);
591127675Sbms            /* ECN bits */
592146778Ssam            if (ipds->ip->ip_tos & 0x03) {
593146778Ssam                switch (ipds->ip->ip_tos & 0x03) {
594127675Sbms                case 1:
595127675Sbms                    (void)printf(",ECT(1)");
596127675Sbms                    break;
597127675Sbms                case 2:
598127675Sbms                    (void)printf(",ECT(0)");
599127675Sbms                    break;
600127675Sbms                case 3:
601127675Sbms                    (void)printf(",CE");
602127675Sbms                }
603127675Sbms            }
604127675Sbms
605146778Ssam            if (ipds->ip->ip_ttl >= 1)
606241235Sdelphij                (void)printf(", ttl %u", ipds->ip->ip_ttl);
607127675Sbms
608127675Sbms	    /*
609127675Sbms	     * for the firewall guys, print id, offset.
610127675Sbms             * On all but the last stick a "+" in the flags portion.
611127675Sbms	     * For unfragmented datagrams, note the don't fragment flag.
612127675Sbms	     */
613127675Sbms
614172686Smlaier	    (void)printf(", id %u, offset %u, flags [%s], proto %s (%u)",
615146778Ssam                         EXTRACT_16BITS(&ipds->ip->ip_id),
616146778Ssam                         (ipds->off & 0x1fff) * 8,
617172686Smlaier                         bittok2str(ip_frag_values, "none", ipds->off&0xe000),
618146778Ssam                         tok2str(ipproto_values,"unknown",ipds->ip->ip_p),
619146778Ssam                         ipds->ip->ip_p);
620127675Sbms
621172686Smlaier            (void)printf(", length %u", EXTRACT_16BITS(&ipds->ip->ip_len));
622127675Sbms
623127675Sbms            if ((hlen - sizeof(struct ip)) > 0) {
624172686Smlaier                printf(", options (");
625146778Ssam                ip_optprint((u_char *)(ipds->ip + 1), hlen - sizeof(struct ip));
626172686Smlaier                printf(")");
627127675Sbms            }
628127675Sbms
629235530Sdelphij	    if (!Kflag && (u_char *)ipds->ip + hlen <= ndo->ndo_snapend) {
630235530Sdelphij	        vec[0].ptr = (const u_int8_t *)(void *)ipds->ip;
631235530Sdelphij	        vec[0].len = hlen;
632235530Sdelphij	        sum = in_cksum(vec, 1);
633127675Sbms		if (sum != 0) {
634146778Ssam		    ip_sum = EXTRACT_16BITS(&ipds->ip->ip_sum);
635127675Sbms		    (void)printf(", bad cksum %x (->%x)!", ip_sum,
636127675Sbms			     in_cksum_shouldbe(ip_sum, sum));
637127675Sbms		}
638127675Sbms	    }
639127675Sbms
640190207Srpaulo            printf(")\n    ");
641127675Sbms	}
642127675Sbms
64317680Spst	/*
64417680Spst	 * If this is fragment zero, hand it to the next higher
64517680Spst	 * level protocol.
64617680Spst	 */
647146778Ssam	if ((ipds->off & 0x1fff) == 0) {
648146778Ssam		ipds->cp = (const u_char *)ipds->ip + hlen;
649146778Ssam		ipds->nh = ipds->ip->ip_p;
65017680Spst
651146778Ssam		if (ipds->nh != IPPROTO_TCP && ipds->nh != IPPROTO_UDP &&
652162021Ssam		    ipds->nh != IPPROTO_SCTP && ipds->nh != IPPROTO_DCCP) {
653146778Ssam			(void)printf("%s > %s: ",
654146778Ssam				     ipaddr_string(&ipds->ip->ip_src),
655146778Ssam				     ipaddr_string(&ipds->ip->ip_dst));
65656896Sfenner		}
657146778Ssam		ip_print_demux(ndo, ipds);
658127675Sbms	} else {
659127675Sbms	    /* Ultra quiet now means that all this stuff should be suppressed */
660127675Sbms	    if (qflag > 1) return;
66156896Sfenner
662127675Sbms	    /*
663127675Sbms	     * if this isn't the first frag, we're missing the
664127675Sbms	     * next level protocol header.  print the ip addr
665127675Sbms	     * and the protocol.
666127675Sbms	     */
667146778Ssam	    if (ipds->off & 0x1fff) {
668146778Ssam	        (void)printf("%s > %s:", ipaddr_string(&ipds->ip->ip_src),
669146778Ssam			     ipaddr_string(&ipds->ip->ip_dst));
670241235Sdelphij		if (!ndo->ndo_nflag && (proto = getprotobynumber(ipds->ip->ip_p)) != NULL)
671127675Sbms		    (void)printf(" %s", proto->p_name);
672127675Sbms		else
673146778Ssam		    (void)printf(" ip-proto-%d", ipds->ip->ip_p);
674241235Sdelphij	    }
67556896Sfenner	}
67617680Spst}
67775118Sfenner
67875118Sfennervoid
67975118SfenneripN_print(register const u_char *bp, register u_int length)
68075118Sfenner{
68175118Sfenner	struct ip *ip, hdr;
68275118Sfenner
68375118Sfenner	ip = (struct ip *)bp;
68475118Sfenner	if (length < 4) {
68575118Sfenner		(void)printf("truncated-ip %d", length);
68675118Sfenner		return;
68775118Sfenner	}
68875118Sfenner	memcpy (&hdr, (char *)ip, 4);
68975118Sfenner	switch (IP_V(&hdr)) {
69075118Sfenner	case 4:
691146778Ssam		ip_print (gndo, bp, length);
69298527Sfenner		return;
69375118Sfenner#ifdef INET6
69475118Sfenner	case 6:
695235530Sdelphij		ip6_print (gndo, bp, length);
69698527Sfenner		return;
69775118Sfenner#endif
69875118Sfenner	default:
69998527Sfenner		(void)printf("unknown ip %d", IP_V(&hdr));
70098527Sfenner		return;
70175118Sfenner	}
70275118Sfenner}
703127675Sbms
704146778Ssam/*
705146778Ssam * Local Variables:
706146778Ssam * c-style: whitesmith
707146778Ssam * c-basic-offset: 8
708146778Ssam * End:
709146778Ssam */
710127675Sbms
711127675Sbms
712