print-ip.c revision 162021
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 162021 2006-09-04 20:25:04Z sam $
2217680Spst */
2317680Spst
2417680Spst#ifndef lint
25127675Sbmsstatic const char rcsid[] _U_ =
26162021Ssam    "@(#) $Header: /tcpdump/master/tcpdump/print-ip.c,v 1.149.2.2 2005/09/20 06:05:38 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" },
55146778Ssam    { 0, NULL }
56146778Ssam};
57146778Ssam
5817680Spst/*
5917680Spst * print the recorded route in an IP RR, LSRR or SSRR option.
6017680Spst */
6117680Spststatic void
62146778Ssamip_printroute(register const u_char *cp, u_int length)
6317680Spst{
64127675Sbms	register u_int ptr;
6517680Spst	register u_int len;
6617680Spst
67127675Sbms	if (length < 3) {
68127675Sbms		printf(" [bad length %u]", length);
69127675Sbms		return;
70127675Sbms	}
7117680Spst	if ((length + 1) & 3)
72127675Sbms		printf(" [bad length %u]", length);
73127675Sbms	ptr = cp[2] - 1;
7417680Spst	if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1)
75127675Sbms		printf(" [bad ptr %u]", cp[2]);
7617680Spst
7717680Spst	for (len = 3; len < length; len += 4) {
78146778Ssam		printf("%s", ipaddr_string(&cp[len]));
79146778Ssam                if (ptr > len)
80146778Ssam                    printf (", ");
8117680Spst	}
8217680Spst}
8317680Spst
84127675Sbms/*
85146778Ssam * If source-routing is present and valid, return the final destination.
86127675Sbms * Otherwise, return IP destination.
87127675Sbms *
88127675Sbms * This is used for UDP and TCP pseudo-header in the checksum
89127675Sbms * calculation.
90127675Sbms */
91127675Sbmsu_int32_t
92127675Sbmsip_finddst(const struct ip *ip)
93127675Sbms{
94127675Sbms	int length;
95127675Sbms	int len;
96127675Sbms	const u_char *cp;
97127675Sbms	u_int32_t retval;
98127675Sbms
99127675Sbms	cp = (const u_char *)(ip + 1);
100127675Sbms	length = (IP_HL(ip) << 2) - sizeof(struct ip);
101127675Sbms
102127675Sbms	for (; length > 0; cp += len, length -= len) {
103127675Sbms		int tt;
104127675Sbms
105127675Sbms		TCHECK(*cp);
106127675Sbms		tt = *cp;
107146778Ssam		if (tt == IPOPT_EOL)
108146778Ssam			break;
109146778Ssam		else if (tt == IPOPT_NOP)
110127675Sbms			len = 1;
111127675Sbms		else {
112127675Sbms			TCHECK(cp[1]);
113127675Sbms			len = cp[1];
114146778Ssam			if (len < 2)
115146778Ssam				break;
116127675Sbms		}
117127675Sbms		TCHECK2(*cp, len);
118127675Sbms		switch (tt) {
119127675Sbms
120127675Sbms		case IPOPT_SSRR:
121127675Sbms		case IPOPT_LSRR:
122127675Sbms			if (len < 7)
123146778Ssam				break;
124127675Sbms			memcpy(&retval, cp + len - 4, 4);
125127675Sbms			return retval;
126127675Sbms		}
127127675Sbms	}
128127675Sbmstrunc:
129146778Ssam	memcpy(&retval, &ip->ip_dst.s_addr, sizeof(u_int32_t));
130146778Ssam	return retval;
131127675Sbms}
132127675Sbms
13356896Sfennerstatic void
13456896Sfennerip_printts(register const u_char *cp, u_int length)
13556896Sfenner{
136127675Sbms	register u_int ptr;
137127675Sbms	register u_int len;
13856896Sfenner	int hoplen;
139127675Sbms	const char *type;
14056896Sfenner
141127675Sbms	if (length < 4) {
142127675Sbms		printf("[bad length %d]", length);
143127675Sbms		return;
144127675Sbms	}
14556896Sfenner	printf(" TS{");
14656896Sfenner	hoplen = ((cp[3]&0xF) != IPOPT_TS_TSONLY) ? 8 : 4;
14756896Sfenner	if ((length - 4) & (hoplen-1))
14856896Sfenner		printf("[bad length %d]", length);
149127675Sbms	ptr = cp[2] - 1;
150127675Sbms	len = 0;
15156896Sfenner	if (ptr < 4 || ((ptr - 4) & (hoplen-1)) || ptr > length + 1)
15256896Sfenner		printf("[bad ptr %d]", cp[2]);
15356896Sfenner	switch (cp[3]&0xF) {
15456896Sfenner	case IPOPT_TS_TSONLY:
15556896Sfenner		printf("TSONLY");
15656896Sfenner		break;
15756896Sfenner	case IPOPT_TS_TSANDADDR:
15856896Sfenner		printf("TS+ADDR");
15956896Sfenner		break;
16056896Sfenner	/*
16156896Sfenner	 * prespecified should really be 3, but some ones might send 2
16256896Sfenner	 * instead, and the IPOPT_TS_PRESPEC constant can apparently
16356896Sfenner	 * have both values, so we have to hard-code it here.
16456896Sfenner	 */
16556896Sfenner
16656896Sfenner	case 2:
16756896Sfenner		printf("PRESPEC2.0");
16856896Sfenner		break;
16956896Sfenner	case 3:			/* IPOPT_TS_PRESPEC */
17056896Sfenner		printf("PRESPEC");
17156896Sfenner		break;
172127675Sbms	default:
17356896Sfenner		printf("[bad ts type %d]", cp[3]&0xF);
17456896Sfenner		goto done;
17556896Sfenner	}
17656896Sfenner
17756896Sfenner	type = " ";
17856896Sfenner	for (len = 4; len < length; len += hoplen) {
17956896Sfenner		if (ptr == len)
18056896Sfenner			type = " ^ ";
18156896Sfenner		printf("%s%d@%s", type, EXTRACT_32BITS(&cp[len+hoplen-4]),
18256896Sfenner		       hoplen!=8 ? "" : ipaddr_string(&cp[len]));
18356896Sfenner		type = " ";
18456896Sfenner	}
18556896Sfenner
18656896Sfennerdone:
18756896Sfenner	printf("%s", ptr == len ? " ^ " : "");
18856896Sfenner
18956896Sfenner	if (cp[3]>>4)
19056896Sfenner		printf(" [%d hops not recorded]} ", cp[3]>>4);
19156896Sfenner	else
19256896Sfenner		printf("}");
19356896Sfenner}
19456896Sfenner
19517680Spst/*
19617680Spst * print IP options.
19717680Spst */
19817680Spststatic void
19917680Spstip_optprint(register const u_char *cp, u_int length)
20017680Spst{
201146778Ssam	register u_int option_len;
20217680Spst
203146778Ssam	for (; length > 0; cp += option_len, length -= option_len) {
204146778Ssam		u_int option_code;
20517680Spst
206127675Sbms		TCHECK(*cp);
207146778Ssam		option_code = *cp;
208146778Ssam
209146778Ssam		if (option_code == IPOPT_NOP ||
210146778Ssam                    option_code == IPOPT_EOL)
211146778Ssam			option_len = 1;
212146778Ssam
21375118Sfenner		else {
214127675Sbms			TCHECK(cp[1]);
215146778Ssam			option_len = cp[1];
21675118Sfenner		}
21717680Spst
218146778Ssam                printf("%s (%u) len %u",
219146778Ssam                       tok2str(ip_option_values,"unknown",option_code),
220146778Ssam                       option_code,
221146778Ssam                       option_len);
222146778Ssam
223146778Ssam                if (option_len < 2)
224146778Ssam                        return;
225146778Ssam
226146778Ssam                TCHECK2(*cp, option_len);
227146778Ssam
228146778Ssam		switch (option_code) {
22917680Spst		case IPOPT_EOL:
23017680Spst			return;
23117680Spst
23217680Spst		case IPOPT_TS:
233146778Ssam			ip_printts(cp, option_len);
23417680Spst			break;
23517680Spst
236146778Ssam		case IPOPT_RR:       /* fall through */
23717680Spst		case IPOPT_SSRR:
23817680Spst		case IPOPT_LSRR:
239146778Ssam			ip_printroute( cp, option_len);
24017680Spst			break;
24117680Spst
24217691Spst		case IPOPT_RA:
243146778Ssam                        TCHECK(cp[3]);
244146778Ssam                        if (EXTRACT_16BITS(&cp[2]) != 0)
245146778Ssam                            printf("value %u", EXTRACT_16BITS(&cp[2]));
24698527Sfenner			break;
24717691Spst
248146778Ssam		case IPOPT_NOP:       /* nothing to print - fall through */
249146778Ssam		case IPOPT_SECURITY:
25017680Spst		default:
25117680Spst			break;
25217680Spst		}
25317680Spst	}
254127675Sbms	return;
255127675Sbms
256127675Sbmstrunc:
257127675Sbms	printf("[|ip]");
25817680Spst}
25917680Spst
26017680Spst/*
26117680Spst * compute an IP header checksum.
26217680Spst * don't modifiy the packet.
26317680Spst */
26456896Sfenneru_short
26598527Sfennerin_cksum(const u_short *addr, register u_int len, int csum)
26617680Spst{
26756896Sfenner	int nleft = len;
26856896Sfenner	const u_short *w = addr;
26956896Sfenner	u_short answer;
27056896Sfenner	int sum = csum;
27117680Spst
272127675Sbms	/*
27356896Sfenner	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
27456896Sfenner	 *  we add sequential 16 bit words to it, and at the end, fold
27556896Sfenner	 *  back all the carry bits from the top 16 bits into the lower
27656896Sfenner	 *  16 bits.
277127675Sbms	 */
27856896Sfenner	while (nleft > 1)  {
27956896Sfenner		sum += *w++;
28056896Sfenner		nleft -= 2;
28156896Sfenner	}
28256896Sfenner	if (nleft == 1)
28356896Sfenner		sum += htons(*(u_char *)w<<8);
28456896Sfenner
28517680Spst	/*
28656896Sfenner	 * add back carry outs from top 16 bits to low 16 bits
28717680Spst	 */
28856896Sfenner	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
28956896Sfenner	sum += (sum >> 16);			/* add carry */
29056896Sfenner	answer = ~sum;				/* truncate to 16 bits */
29156896Sfenner	return (answer);
29217680Spst}
29317680Spst
29417680Spst/*
295127675Sbms * Given the host-byte-order value of the checksum field in a packet
296127675Sbms * header, and the network-byte-order computed checksum of the data
297127675Sbms * that the checksum covers (including the checksum itself), compute
298127675Sbms * what the checksum field *should* have been.
299127675Sbms */
300127675Sbmsu_int16_t
301127675Sbmsin_cksum_shouldbe(u_int16_t sum, u_int16_t computed_sum)
302127675Sbms{
303127675Sbms	u_int32_t shouldbe;
304127675Sbms
305127675Sbms	/*
306127675Sbms	 * The value that should have gone into the checksum field
307127675Sbms	 * is the negative of the value gotten by summing up everything
308127675Sbms	 * *but* the checksum field.
309127675Sbms	 *
310127675Sbms	 * We can compute that by subtracting the value of the checksum
311127675Sbms	 * field from the sum of all the data in the packet, and then
312127675Sbms	 * computing the negative of that value.
313127675Sbms	 *
314127675Sbms	 * "sum" is the value of the checksum field, and "computed_sum"
315127675Sbms	 * is the negative of the sum of all the data in the packets,
316127675Sbms	 * so that's -(-computed_sum - sum), or (sum + computed_sum).
317127675Sbms	 *
318127675Sbms	 * All the arithmetic in question is one's complement, so the
319127675Sbms	 * addition must include an end-around carry; we do this by
320127675Sbms	 * doing the arithmetic in 32 bits (with no sign-extension),
321127675Sbms	 * and then adding the upper 16 bits of the sum, which contain
322127675Sbms	 * the carry, to the lower 16 bits of the sum, and then do it
323127675Sbms	 * again in case *that* sum produced a carry.
324127675Sbms	 *
325127675Sbms	 * As RFC 1071 notes, the checksum can be computed without
326127675Sbms	 * byte-swapping the 16-bit words; summing 16-bit words
327127675Sbms	 * on a big-endian machine gives a big-endian checksum, which
328127675Sbms	 * can be directly stuffed into the big-endian checksum fields
329127675Sbms	 * in protocol headers, and summing words on a little-endian
330127675Sbms	 * machine gives a little-endian checksum, which must be
331127675Sbms	 * byte-swapped before being stuffed into a big-endian checksum
332127675Sbms	 * field.
333127675Sbms	 *
334127675Sbms	 * "computed_sum" is a network-byte-order value, so we must put
335127675Sbms	 * it in host byte order before subtracting it from the
336127675Sbms	 * host-byte-order value from the header; the adjusted checksum
337127675Sbms	 * will be in host byte order, which is what we'll return.
338127675Sbms	 */
339127675Sbms	shouldbe = sum;
340127675Sbms	shouldbe += ntohs(computed_sum);
341127675Sbms	shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16);
342127675Sbms	shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16);
343127675Sbms	return shouldbe;
344127675Sbms}
345127675Sbms
346127675Sbms#ifndef IP_MF
347127675Sbms#define IP_MF 0x2000
348127675Sbms#endif /* IP_MF */
349127675Sbms#ifndef IP_DF
350127675Sbms#define IP_DF 0x4000
351127675Sbms#endif /* IP_DF */
352127675Sbms#define IP_RES 0x8000
353127675Sbms
354127675Sbmsstatic struct tok ip_frag_values[] = {
355127675Sbms        { IP_MF,        "+" },
356127675Sbms        { IP_DF,        "DF" },
357127675Sbms	{ IP_RES,       "rsvd" }, /* The RFC3514 evil ;-) bit */
358127675Sbms        { 0,            NULL }
359127675Sbms};
360127675Sbms
361146778Ssamstruct ip_print_demux_state {
362146778Ssam	const struct ip *ip;
363146778Ssam	const u_char *cp;
364146778Ssam	u_int   len, off;
365146778Ssam	u_char  nh;
366146778Ssam	int     advance;
367146778Ssam};
368146778Ssam
369146778Ssamstatic void
370146778Ssamip_print_demux(netdissect_options *ndo,
371146778Ssam	       struct ip_print_demux_state *ipds)
372146778Ssam{
373146778Ssam	struct protoent *proto;
374146778Ssam
375146778Ssamagain:
376146778Ssam	switch (ipds->nh) {
377146778Ssam
378146778Ssam	case IPPROTO_AH:
379146778Ssam		ipds->nh = *ipds->cp;
380146778Ssam		ipds->advance = ah_print(ipds->cp);
381146778Ssam		if (ipds->advance <= 0)
382146778Ssam			break;
383146778Ssam		ipds->cp += ipds->advance;
384146778Ssam		ipds->len -= ipds->advance;
385146778Ssam		goto again;
386146778Ssam
387146778Ssam	case IPPROTO_ESP:
388146778Ssam	{
389146778Ssam		int enh, padlen;
390146778Ssam		ipds->advance = esp_print(ndo, ipds->cp, ipds->len,
391146778Ssam				    (const u_char *)ipds->ip,
392146778Ssam				    &enh, &padlen);
393146778Ssam		if (ipds->advance <= 0)
394146778Ssam			break;
395146778Ssam		ipds->cp += ipds->advance;
396146778Ssam		ipds->len -= ipds->advance + padlen;
397146778Ssam		ipds->nh = enh & 0xff;
398146778Ssam		goto again;
399146778Ssam	}
400146778Ssam
401146778Ssam	case IPPROTO_IPCOMP:
402146778Ssam	{
403146778Ssam		int enh;
404146778Ssam		ipds->advance = ipcomp_print(ipds->cp, &enh);
405146778Ssam		if (ipds->advance <= 0)
406146778Ssam			break;
407146778Ssam		ipds->cp += ipds->advance;
408146778Ssam		ipds->len -= ipds->advance;
409146778Ssam		ipds->nh = enh & 0xff;
410146778Ssam		goto again;
411146778Ssam	}
412146778Ssam
413146778Ssam	case IPPROTO_SCTP:
414146778Ssam		sctp_print(ipds->cp, (const u_char *)ipds->ip, ipds->len);
415146778Ssam		break;
416162021Ssam
417162021Ssam	case IPPROTO_DCCP:
418162021Ssam		dccp_print(ipds->cp, (const u_char *)ipds->ip, ipds->len);
419162021Ssam		break;
420146778Ssam
421146778Ssam	case IPPROTO_TCP:
422146778Ssam		tcp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip,
423146778Ssam			  (ipds->off &~ 0x6000));
424146778Ssam		break;
425146778Ssam
426146778Ssam	case IPPROTO_UDP:
427146778Ssam		udp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip,
428146778Ssam			  (ipds->off &~ 0x6000));
429146778Ssam		break;
430146778Ssam
431146778Ssam	case IPPROTO_ICMP:
432146778Ssam		/* pass on the MF bit plus the offset to detect fragments */
433146778Ssam		icmp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip,
434146778Ssam			   (ipds->off & 0x3fff));
435146778Ssam		break;
436146778Ssam
437146778Ssam	case IPPROTO_PIGP:
438146778Ssam		/*
439146778Ssam		 * XXX - the current IANA protocol number assignments
440146778Ssam		 * page lists 9 as "any private interior gateway
441146778Ssam		 * (used by Cisco for their IGRP)" and 88 as
442146778Ssam		 * "EIGRP" from Cisco.
443146778Ssam		 *
444146778Ssam		 * Recent BSD <netinet/in.h> headers define
445146778Ssam		 * IP_PROTO_PIGP as 9 and IP_PROTO_IGRP as 88.
446146778Ssam		 * We define IP_PROTO_PIGP as 9 and
447146778Ssam		 * IP_PROTO_EIGRP as 88; those names better
448146778Ssam		 * match was the current protocol number
449146778Ssam		 * assignments say.
450146778Ssam		 */
451146778Ssam		igrp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip);
452146778Ssam		break;
453146778Ssam
454146778Ssam	case IPPROTO_EIGRP:
455146778Ssam		eigrp_print(ipds->cp, ipds->len);
456146778Ssam		break;
457146778Ssam
458146778Ssam	case IPPROTO_ND:
459146778Ssam		ND_PRINT((ndo, " nd %d", ipds->len));
460146778Ssam		break;
461146778Ssam
462146778Ssam	case IPPROTO_EGP:
463146778Ssam		egp_print(ipds->cp, ipds->len);
464146778Ssam		break;
465146778Ssam
466146778Ssam	case IPPROTO_OSPF:
467146778Ssam		ospf_print(ipds->cp, ipds->len, (const u_char *)ipds->ip);
468146778Ssam		break;
469146778Ssam
470146778Ssam	case IPPROTO_IGMP:
471146778Ssam		igmp_print(ipds->cp, ipds->len);
472146778Ssam		break;
473146778Ssam
474146778Ssam	case IPPROTO_IPV4:
475146778Ssam		/* DVMRP multicast tunnel (ip-in-ip encapsulation) */
476146778Ssam		ip_print(gndo, ipds->cp, ipds->len);
477146778Ssam		if (! vflag) {
478146778Ssam			ND_PRINT((ndo, " (ipip-proto-4)"));
479146778Ssam			return;
480146778Ssam		}
481146778Ssam		break;
482146778Ssam
483146778Ssam#ifdef INET6
484146778Ssam	case IPPROTO_IPV6:
485146778Ssam		/* ip6-in-ip encapsulation */
486146778Ssam		ip6_print(ipds->cp, ipds->len);
487146778Ssam		break;
488146778Ssam#endif /*INET6*/
489146778Ssam
490146778Ssam	case IPPROTO_RSVP:
491146778Ssam		rsvp_print(ipds->cp, ipds->len);
492146778Ssam		break;
493146778Ssam
494146778Ssam	case IPPROTO_GRE:
495146778Ssam		/* do it */
496146778Ssam		gre_print(ipds->cp, ipds->len);
497146778Ssam		break;
498146778Ssam
499146778Ssam	case IPPROTO_MOBILE:
500146778Ssam		mobile_print(ipds->cp, ipds->len);
501146778Ssam		break;
502146778Ssam
503146778Ssam	case IPPROTO_PIM:
504146778Ssam		pim_print(ipds->cp,  ipds->len);
505146778Ssam		break;
506146778Ssam
507146778Ssam	case IPPROTO_VRRP:
508146778Ssam		vrrp_print(ipds->cp, ipds->len, ipds->ip->ip_ttl);
509146778Ssam		break;
510146778Ssam
511147904Ssam	case IPPROTO_PGM:
512147904Ssam		pgm_print(ipds->cp, ipds->len, (const u_char *)ipds->ip);
513147904Ssam		break;
514147904Ssam
515146778Ssam	default:
516146778Ssam		if ((proto = getprotobynumber(ipds->nh)) != NULL)
517146778Ssam			ND_PRINT((ndo, " %s", proto->p_name));
518146778Ssam		else
519146778Ssam			ND_PRINT((ndo, " ip-proto-%d", ipds->nh));
520146778Ssam		ND_PRINT((ndo, " %d", ipds->len));
521146778Ssam		break;
522146778Ssam	}
523146778Ssam}
524146778Ssam
525146778Ssamvoid
526146778Ssamip_print_inner(netdissect_options *ndo,
527146778Ssam	       const u_char *bp,
528146778Ssam	       u_int length, u_int nh,
529146778Ssam	       const u_char *bp2)
530146778Ssam{
531146778Ssam	struct ip_print_demux_state  ipd;
532146778Ssam
533146778Ssam	ipd.ip = (const struct ip *)bp2;
534146778Ssam	ipd.cp = bp;
535146778Ssam	ipd.len  = length;
536146778Ssam	ipd.off  = 0;
537146778Ssam	ipd.nh   = nh;
538146778Ssam	ipd.advance = 0;
539146778Ssam
540146778Ssam	ip_print_demux(ndo, &ipd);
541146778Ssam}
542146778Ssam
543146778Ssam
544127675Sbms/*
54517680Spst * print an IP datagram.
54617680Spst */
54717680Spstvoid
548146778Ssamip_print(netdissect_options *ndo,
549146778Ssam	 const u_char *bp,
550146778Ssam	 u_int length)
55117680Spst{
552146778Ssam	struct ip_print_demux_state  ipd;
553146778Ssam	struct ip_print_demux_state *ipds=&ipd;
554127675Sbms	const u_char *ipend;
555146778Ssam	u_int hlen;
556146778Ssam	u_int16_t sum, ip_sum;
557111729Sfenner	struct protoent *proto;
55817680Spst
559146778Ssam	ipds->ip = (const struct ip *)bp;
560146778Ssam	if (IP_V(ipds->ip) != 4) { /* print version if != 4 */
561146778Ssam	    printf("IP%u ", IP_V(ipds->ip));
562146778Ssam	    if (IP_V(ipds->ip) == 6)
563127675Sbms		printf(", wrong link-layer encapsulation");
564127675Sbms	}
565146778Ssam        else if (!eflag)
566127675Sbms	    printf("IP ");
56717680Spst
568146778Ssam	if ((u_char *)(ipds->ip + 1) > snapend) {
56917680Spst		printf("[|ip]");
57017680Spst		return;
57117680Spst	}
57217680Spst	if (length < sizeof (struct ip)) {
573146778Ssam		(void)printf("truncated-ip %u", length);
57417680Spst		return;
57517680Spst	}
576146778Ssam	hlen = IP_HL(ipds->ip) * 4;
57775118Sfenner	if (hlen < sizeof (struct ip)) {
578127675Sbms		(void)printf("bad-hlen %u", hlen);
57975118Sfenner		return;
58075118Sfenner	}
58117680Spst
582146778Ssam	ipds->len = EXTRACT_16BITS(&ipds->ip->ip_len);
583146778Ssam	if (length < ipds->len)
584127675Sbms		(void)printf("truncated-ip - %u bytes missing! ",
585146778Ssam			ipds->len - length);
586146778Ssam	if (ipds->len < hlen) {
587146778Ssam#ifdef GUESS_TSO
588146778Ssam            if (ipds->len) {
589146778Ssam                (void)printf("bad-len %u", ipds->len);
590146778Ssam                return;
591146778Ssam            }
592146778Ssam            else {
593146778Ssam                /* we guess that it is a TSO send */
594146778Ssam                ipds->len = length;
595146778Ssam            }
596146778Ssam#else
597146778Ssam            (void)printf("bad-len %u", ipds->len);
598146778Ssam            return;
599146778Ssam#endif /* GUESS_TSO */
600127675Sbms	}
601127675Sbms
602127675Sbms	/*
603127675Sbms	 * Cut off the snapshot length to the end of the IP payload.
604127675Sbms	 */
605146778Ssam	ipend = bp + ipds->len;
606127675Sbms	if (ipend < snapend)
607127675Sbms		snapend = ipend;
608127675Sbms
609146778Ssam	ipds->len -= hlen;
61017680Spst
611146778Ssam	ipds->off = EXTRACT_16BITS(&ipds->ip->ip_off);
612127675Sbms
613127675Sbms        if (vflag) {
614146778Ssam            (void)printf("(tos 0x%x", (int)ipds->ip->ip_tos);
615127675Sbms            /* ECN bits */
616146778Ssam            if (ipds->ip->ip_tos & 0x03) {
617146778Ssam                switch (ipds->ip->ip_tos & 0x03) {
618127675Sbms                case 1:
619127675Sbms                    (void)printf(",ECT(1)");
620127675Sbms                    break;
621127675Sbms                case 2:
622127675Sbms                    (void)printf(",ECT(0)");
623127675Sbms                    break;
624127675Sbms                case 3:
625127675Sbms                    (void)printf(",CE");
626127675Sbms                }
627127675Sbms            }
628127675Sbms
629146778Ssam            if (ipds->ip->ip_ttl >= 1)
630146778Ssam                (void)printf(", ttl %3u", ipds->ip->ip_ttl);
631127675Sbms
632127675Sbms	    /*
633127675Sbms	     * for the firewall guys, print id, offset.
634127675Sbms             * On all but the last stick a "+" in the flags portion.
635127675Sbms	     * For unfragmented datagrams, note the don't fragment flag.
636127675Sbms	     */
637127675Sbms
638146778Ssam	    (void)printf(", id %u, offset %u, flags [%s], proto: %s (%u)",
639146778Ssam                         EXTRACT_16BITS(&ipds->ip->ip_id),
640146778Ssam                         (ipds->off & 0x1fff) * 8,
641146778Ssam                         bittok2str(ip_frag_values, "none", ipds->off&0xe000 ),
642146778Ssam                         tok2str(ipproto_values,"unknown",ipds->ip->ip_p),
643146778Ssam                         ipds->ip->ip_p);
644127675Sbms
645146778Ssam            (void)printf(", length: %u", EXTRACT_16BITS(&ipds->ip->ip_len));
646127675Sbms
647127675Sbms            if ((hlen - sizeof(struct ip)) > 0) {
648146778Ssam                printf(", options ( ");
649146778Ssam                ip_optprint((u_char *)(ipds->ip + 1), hlen - sizeof(struct ip));
650127675Sbms                printf(" )");
651127675Sbms            }
652127675Sbms
653146778Ssam	    if ((u_char *)ipds->ip + hlen <= snapend) {
654146778Ssam	        sum = in_cksum((const u_short *)ipds->ip, hlen, 0);
655127675Sbms		if (sum != 0) {
656146778Ssam		    ip_sum = EXTRACT_16BITS(&ipds->ip->ip_sum);
657127675Sbms		    (void)printf(", bad cksum %x (->%x)!", ip_sum,
658127675Sbms			     in_cksum_shouldbe(ip_sum, sum));
659127675Sbms		}
660127675Sbms	    }
661127675Sbms
662127675Sbms            printf(") ");
663127675Sbms	}
664127675Sbms
66517680Spst	/*
66617680Spst	 * If this is fragment zero, hand it to the next higher
66717680Spst	 * level protocol.
66817680Spst	 */
669146778Ssam	if ((ipds->off & 0x1fff) == 0) {
670146778Ssam		ipds->cp = (const u_char *)ipds->ip + hlen;
671146778Ssam		ipds->nh = ipds->ip->ip_p;
67217680Spst
673146778Ssam		if (ipds->nh != IPPROTO_TCP && ipds->nh != IPPROTO_UDP &&
674162021Ssam		    ipds->nh != IPPROTO_SCTP && ipds->nh != IPPROTO_DCCP) {
675146778Ssam			(void)printf("%s > %s: ",
676146778Ssam				     ipaddr_string(&ipds->ip->ip_src),
677146778Ssam				     ipaddr_string(&ipds->ip->ip_dst));
67856896Sfenner		}
679146778Ssam		ip_print_demux(ndo, ipds);
680127675Sbms	} else {
681127675Sbms	    /* Ultra quiet now means that all this stuff should be suppressed */
682127675Sbms	    if (qflag > 1) return;
68356896Sfenner
684127675Sbms	    /*
685127675Sbms	     * if this isn't the first frag, we're missing the
686127675Sbms	     * next level protocol header.  print the ip addr
687127675Sbms	     * and the protocol.
688127675Sbms	     */
689146778Ssam	    if (ipds->off & 0x1fff) {
690146778Ssam	        (void)printf("%s > %s:", ipaddr_string(&ipds->ip->ip_src),
691146778Ssam			     ipaddr_string(&ipds->ip->ip_dst));
692146778Ssam		if ((proto = getprotobynumber(ipds->ip->ip_p)) != NULL)
693127675Sbms		    (void)printf(" %s", proto->p_name);
694127675Sbms		else
695146778Ssam		    (void)printf(" ip-proto-%d", ipds->ip->ip_p);
696127675Sbms	    }
69756896Sfenner	}
69817680Spst}
69975118Sfenner
70075118Sfennervoid
70175118SfenneripN_print(register const u_char *bp, register u_int length)
70275118Sfenner{
70375118Sfenner	struct ip *ip, hdr;
70475118Sfenner
70575118Sfenner	ip = (struct ip *)bp;
70675118Sfenner	if (length < 4) {
70775118Sfenner		(void)printf("truncated-ip %d", length);
70875118Sfenner		return;
70975118Sfenner	}
71075118Sfenner	memcpy (&hdr, (char *)ip, 4);
71175118Sfenner	switch (IP_V(&hdr)) {
71275118Sfenner	case 4:
713146778Ssam		ip_print (gndo, bp, length);
71498527Sfenner		return;
71575118Sfenner#ifdef INET6
71675118Sfenner	case 6:
71798527Sfenner		ip6_print (bp, length);
71898527Sfenner		return;
71975118Sfenner#endif
72075118Sfenner	default:
72198527Sfenner		(void)printf("unknown ip %d", IP_V(&hdr));
72298527Sfenner		return;
72375118Sfenner	}
72475118Sfenner}
725127675Sbms
726146778Ssam/*
727146778Ssam * Local Variables:
728146778Ssam * c-style: whitesmith
729146778Ssam * c-basic-offset: 8
730146778Ssam * End:
731146778Ssam */
732127675Sbms
733127675Sbms
734