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$
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
486263086Sglebius#if defined(HAVE_NET_PFVAR_H)
487241221Sglebius	case IPPROTO_PFSYNC:
488241221Sglebius		pfsync_ip_print(ipds->cp, ipds->len);
489241221Sglebius		break;
490263086Sglebius#endif
491241221Sglebius
492146778Ssam	default:
493241235Sdelphij		if (ndo->ndo_nflag==0 && (proto = getprotobynumber(ipds->nh)) != NULL)
494146778Ssam			ND_PRINT((ndo, " %s", proto->p_name));
495146778Ssam		else
496146778Ssam			ND_PRINT((ndo, " ip-proto-%d", ipds->nh));
497146778Ssam		ND_PRINT((ndo, " %d", ipds->len));
498146778Ssam		break;
499146778Ssam	}
500146778Ssam}
501241235Sdelphij
502146778Ssamvoid
503146778Ssamip_print_inner(netdissect_options *ndo,
504146778Ssam	       const u_char *bp,
505146778Ssam	       u_int length, u_int nh,
506146778Ssam	       const u_char *bp2)
507146778Ssam{
508146778Ssam	struct ip_print_demux_state  ipd;
509146778Ssam
510146778Ssam	ipd.ip = (const struct ip *)bp2;
511146778Ssam	ipd.cp = bp;
512146778Ssam	ipd.len  = length;
513146778Ssam	ipd.off  = 0;
514146778Ssam	ipd.nh   = nh;
515146778Ssam	ipd.advance = 0;
516146778Ssam
517146778Ssam	ip_print_demux(ndo, &ipd);
518146778Ssam}
519146778Ssam
520146778Ssam
521127675Sbms/*
52217680Spst * print an IP datagram.
52317680Spst */
52417680Spstvoid
525146778Ssamip_print(netdissect_options *ndo,
526146778Ssam	 const u_char *bp,
527146778Ssam	 u_int length)
52817680Spst{
529146778Ssam	struct ip_print_demux_state  ipd;
530146778Ssam	struct ip_print_demux_state *ipds=&ipd;
531127675Sbms	const u_char *ipend;
532146778Ssam	u_int hlen;
533235530Sdelphij	struct cksum_vec vec[1];
534146778Ssam	u_int16_t sum, ip_sum;
535111729Sfenner	struct protoent *proto;
53617680Spst
537146778Ssam	ipds->ip = (const struct ip *)bp;
538146778Ssam	if (IP_V(ipds->ip) != 4) { /* print version if != 4 */
539146778Ssam	    printf("IP%u ", IP_V(ipds->ip));
540146778Ssam	    if (IP_V(ipds->ip) == 6)
541127675Sbms		printf(", wrong link-layer encapsulation");
542127675Sbms	}
543146778Ssam        else if (!eflag)
544127675Sbms	    printf("IP ");
54517680Spst
546235530Sdelphij	if ((u_char *)(ipds->ip + 1) > ndo->ndo_snapend) {
54717680Spst		printf("[|ip]");
54817680Spst		return;
54917680Spst	}
55017680Spst	if (length < sizeof (struct ip)) {
551146778Ssam		(void)printf("truncated-ip %u", length);
55217680Spst		return;
55317680Spst	}
554146778Ssam	hlen = IP_HL(ipds->ip) * 4;
55575118Sfenner	if (hlen < sizeof (struct ip)) {
556127675Sbms		(void)printf("bad-hlen %u", hlen);
55775118Sfenner		return;
55875118Sfenner	}
55917680Spst
560146778Ssam	ipds->len = EXTRACT_16BITS(&ipds->ip->ip_len);
561146778Ssam	if (length < ipds->len)
562127675Sbms		(void)printf("truncated-ip - %u bytes missing! ",
563146778Ssam			ipds->len - length);
564146778Ssam	if (ipds->len < hlen) {
565146778Ssam#ifdef GUESS_TSO
566146778Ssam            if (ipds->len) {
567146778Ssam                (void)printf("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
575146778Ssam            (void)printf("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
591127675Sbms        if (vflag) {
592146778Ssam            (void)printf("(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:
597127675Sbms                    (void)printf(",ECT(1)");
598127675Sbms                    break;
599127675Sbms                case 2:
600127675Sbms                    (void)printf(",ECT(0)");
601127675Sbms                    break;
602127675Sbms                case 3:
603127675Sbms                    (void)printf(",CE");
604127675Sbms                }
605127675Sbms            }
606127675Sbms
607146778Ssam            if (ipds->ip->ip_ttl >= 1)
608241235Sdelphij                (void)printf(", 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
616172686Smlaier	    (void)printf(", 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),
621146778Ssam                         ipds->ip->ip_p);
622127675Sbms
623172686Smlaier            (void)printf(", length %u", EXTRACT_16BITS(&ipds->ip->ip_len));
624127675Sbms
625127675Sbms            if ((hlen - sizeof(struct ip)) > 0) {
626172686Smlaier                printf(", options (");
627146778Ssam                ip_optprint((u_char *)(ipds->ip + 1), hlen - sizeof(struct ip));
628172686Smlaier                printf(")");
629127675Sbms            }
630127675Sbms
631235530Sdelphij	    if (!Kflag && (u_char *)ipds->ip + hlen <= ndo->ndo_snapend) {
632235530Sdelphij	        vec[0].ptr = (const u_int8_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);
637127675Sbms		    (void)printf(", bad cksum %x (->%x)!", ip_sum,
638127675Sbms			     in_cksum_shouldbe(ip_sum, sum));
639127675Sbms		}
640127675Sbms	    }
641127675Sbms
642190207Srpaulo            printf(")\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) {
655146778Ssam			(void)printf("%s > %s: ",
656146778Ssam				     ipaddr_string(&ipds->ip->ip_src),
657146778Ssam				     ipaddr_string(&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 */
662127675Sbms	    if (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	     */
669146778Ssam	    if (ipds->off & 0x1fff) {
670146778Ssam	        (void)printf("%s > %s:", ipaddr_string(&ipds->ip->ip_src),
671146778Ssam			     ipaddr_string(&ipds->ip->ip_dst));
672241235Sdelphij		if (!ndo->ndo_nflag && (proto = getprotobynumber(ipds->ip->ip_p)) != NULL)
673127675Sbms		    (void)printf(" %s", proto->p_name);
674127675Sbms		else
675146778Ssam		    (void)printf(" ip-proto-%d", ipds->ip->ip_p);
676241235Sdelphij	    }
67756896Sfenner	}
67817680Spst}
67975118Sfenner
68075118Sfennervoid
68175118SfenneripN_print(register const u_char *bp, register u_int length)
68275118Sfenner{
68375118Sfenner	struct ip *ip, hdr;
68475118Sfenner
68575118Sfenner	ip = (struct ip *)bp;
68675118Sfenner	if (length < 4) {
68775118Sfenner		(void)printf("truncated-ip %d", length);
68875118Sfenner		return;
68975118Sfenner	}
69075118Sfenner	memcpy (&hdr, (char *)ip, 4);
69175118Sfenner	switch (IP_V(&hdr)) {
69275118Sfenner	case 4:
693146778Ssam		ip_print (gndo, bp, length);
69498527Sfenner		return;
69575118Sfenner#ifdef INET6
69675118Sfenner	case 6:
697235530Sdelphij		ip6_print (gndo, bp, length);
69898527Sfenner		return;
69975118Sfenner#endif
70075118Sfenner	default:
70198527Sfenner		(void)printf("unknown ip %d", IP_V(&hdr));
70298527Sfenner		return;
70375118Sfenner	}
70475118Sfenner}
705127675Sbms
706146778Ssam/*
707146778Ssam * Local Variables:
708146778Ssam * c-style: whitesmith
709146778Ssam * c-basic-offset: 8
710146778Ssam * End:
711146778Ssam */
712127675Sbms
713127675Sbms
714