print-ip.c revision 172686
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 172686 2007-10-16 02:31:48Z mlaier $
2217680Spst */
2317680Spst
2417680Spst#ifndef lint
25127675Sbmsstatic const char rcsid[] _U_ =
26172686Smlaier    "@(#) $Header: /tcpdump/master/tcpdump/print-ip.c,v 1.149.2.9 2007/09/14 01:30:02 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 */
92127675Sbmsu_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
13456896Sfennerstatic void
13556896Sfennerip_printts(register const u_char *cp, u_int length)
13656896Sfenner{
137127675Sbms	register u_int ptr;
138127675Sbms	register u_int len;
13956896Sfenner	int hoplen;
140127675Sbms	const char *type;
14156896Sfenner
142127675Sbms	if (length < 4) {
143172686Smlaier		printf("[bad length %u]", length);
144127675Sbms		return;
145127675Sbms	}
14656896Sfenner	printf(" TS{");
14756896Sfenner	hoplen = ((cp[3]&0xF) != IPOPT_TS_TSONLY) ? 8 : 4;
14856896Sfenner	if ((length - 4) & (hoplen-1))
149172686Smlaier		printf("[bad length %u]", length);
150127675Sbms	ptr = cp[2] - 1;
151127675Sbms	len = 0;
15256896Sfenner	if (ptr < 4 || ((ptr - 4) & (hoplen-1)) || ptr > length + 1)
153172686Smlaier		printf("[bad ptr %u]", cp[2]);
15456896Sfenner	switch (cp[3]&0xF) {
15556896Sfenner	case IPOPT_TS_TSONLY:
15656896Sfenner		printf("TSONLY");
15756896Sfenner		break;
15856896Sfenner	case IPOPT_TS_TSANDADDR:
15956896Sfenner		printf("TS+ADDR");
16056896Sfenner		break;
16156896Sfenner	/*
16256896Sfenner	 * prespecified should really be 3, but some ones might send 2
16356896Sfenner	 * instead, and the IPOPT_TS_PRESPEC constant can apparently
16456896Sfenner	 * have both values, so we have to hard-code it here.
16556896Sfenner	 */
16656896Sfenner
16756896Sfenner	case 2:
16856896Sfenner		printf("PRESPEC2.0");
16956896Sfenner		break;
17056896Sfenner	case 3:			/* IPOPT_TS_PRESPEC */
17156896Sfenner		printf("PRESPEC");
17256896Sfenner		break;
173127675Sbms	default:
17456896Sfenner		printf("[bad ts type %d]", cp[3]&0xF);
17556896Sfenner		goto done;
17656896Sfenner	}
17756896Sfenner
17856896Sfenner	type = " ";
17956896Sfenner	for (len = 4; len < length; len += hoplen) {
18056896Sfenner		if (ptr == len)
18156896Sfenner			type = " ^ ";
18256896Sfenner		printf("%s%d@%s", type, EXTRACT_32BITS(&cp[len+hoplen-4]),
18356896Sfenner		       hoplen!=8 ? "" : ipaddr_string(&cp[len]));
18456896Sfenner		type = " ";
18556896Sfenner	}
18656896Sfenner
18756896Sfennerdone:
18856896Sfenner	printf("%s", ptr == len ? " ^ " : "");
18956896Sfenner
19056896Sfenner	if (cp[3]>>4)
19156896Sfenner		printf(" [%d hops not recorded]} ", cp[3]>>4);
19256896Sfenner	else
19356896Sfenner		printf("}");
19456896Sfenner}
19556896Sfenner
19617680Spst/*
19717680Spst * print IP options.
19817680Spst */
19917680Spststatic void
20017680Spstip_optprint(register const u_char *cp, u_int length)
20117680Spst{
202146778Ssam	register u_int option_len;
203172686Smlaier	const char *sep = "";
20417680Spst
205146778Ssam	for (; length > 0; cp += option_len, length -= option_len) {
206146778Ssam		u_int option_code;
20717680Spst
208172686Smlaier		printf("%s", sep);
209172686Smlaier		sep = ",";
210172686Smlaier
211127675Sbms		TCHECK(*cp);
212146778Ssam		option_code = *cp;
213146778Ssam
214172686Smlaier                printf("%s",
215172686Smlaier                        tok2str(ip_option_values,"unknown %u",option_code));
216172686Smlaier
217146778Ssam		if (option_code == IPOPT_NOP ||
218146778Ssam                    option_code == IPOPT_EOL)
219146778Ssam			option_len = 1;
220146778Ssam
22175118Sfenner		else {
222127675Sbms			TCHECK(cp[1]);
223172686Smlaier			option_len = cp[1];
224172686Smlaier			if (option_len < 2) {
225172686Smlaier		                printf(" [bad length %u]", option_len);
226172686Smlaier				return;
227172686Smlaier			}
22875118Sfenner		}
22917680Spst
230172686Smlaier		if (option_len > length) {
231172686Smlaier	                printf(" [bad length %u]", option_len);
232172686Smlaier			return;
233172686Smlaier		}
234146778Ssam
235146778Ssam                TCHECK2(*cp, option_len);
236146778Ssam
237146778Ssam		switch (option_code) {
23817680Spst		case IPOPT_EOL:
23917680Spst			return;
24017680Spst
24117680Spst		case IPOPT_TS:
242146778Ssam			ip_printts(cp, option_len);
24317680Spst			break;
24417680Spst
245146778Ssam		case IPOPT_RR:       /* fall through */
24617680Spst		case IPOPT_SSRR:
24717680Spst		case IPOPT_LSRR:
248172686Smlaier			ip_printroute(cp, option_len);
24917680Spst			break;
25017680Spst
25117691Spst		case IPOPT_RA:
252172686Smlaier			if (option_len < 4) {
253172686Smlaier				printf(" [bad length %u]", option_len);
254172686Smlaier				break;
255172686Smlaier			}
256146778Ssam                        TCHECK(cp[3]);
257146778Ssam                        if (EXTRACT_16BITS(&cp[2]) != 0)
258172686Smlaier                            printf(" value %u", EXTRACT_16BITS(&cp[2]));
25998527Sfenner			break;
26017691Spst
261146778Ssam		case IPOPT_NOP:       /* nothing to print - fall through */
262146778Ssam		case IPOPT_SECURITY:
26317680Spst		default:
26417680Spst			break;
26517680Spst		}
26617680Spst	}
267127675Sbms	return;
268127675Sbms
269127675Sbmstrunc:
270127675Sbms	printf("[|ip]");
27117680Spst}
27217680Spst
27317680Spst/*
27417680Spst * compute an IP header checksum.
27517680Spst * don't modifiy the packet.
27617680Spst */
27756896Sfenneru_short
27898527Sfennerin_cksum(const u_short *addr, register u_int len, int csum)
27917680Spst{
28056896Sfenner	int nleft = len;
28156896Sfenner	const u_short *w = addr;
28256896Sfenner	u_short answer;
28356896Sfenner	int sum = csum;
28417680Spst
285127675Sbms	/*
28656896Sfenner	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
28756896Sfenner	 *  we add sequential 16 bit words to it, and at the end, fold
28856896Sfenner	 *  back all the carry bits from the top 16 bits into the lower
28956896Sfenner	 *  16 bits.
290127675Sbms	 */
29156896Sfenner	while (nleft > 1)  {
29256896Sfenner		sum += *w++;
29356896Sfenner		nleft -= 2;
29456896Sfenner	}
29556896Sfenner	if (nleft == 1)
29656896Sfenner		sum += htons(*(u_char *)w<<8);
29756896Sfenner
29817680Spst	/*
29956896Sfenner	 * add back carry outs from top 16 bits to low 16 bits
30017680Spst	 */
30156896Sfenner	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
30256896Sfenner	sum += (sum >> 16);			/* add carry */
30356896Sfenner	answer = ~sum;				/* truncate to 16 bits */
30456896Sfenner	return (answer);
30517680Spst}
30617680Spst
30717680Spst/*
308127675Sbms * Given the host-byte-order value of the checksum field in a packet
309127675Sbms * header, and the network-byte-order computed checksum of the data
310127675Sbms * that the checksum covers (including the checksum itself), compute
311127675Sbms * what the checksum field *should* have been.
312127675Sbms */
313127675Sbmsu_int16_t
314127675Sbmsin_cksum_shouldbe(u_int16_t sum, u_int16_t computed_sum)
315127675Sbms{
316127675Sbms	u_int32_t shouldbe;
317127675Sbms
318127675Sbms	/*
319127675Sbms	 * The value that should have gone into the checksum field
320127675Sbms	 * is the negative of the value gotten by summing up everything
321127675Sbms	 * *but* the checksum field.
322127675Sbms	 *
323127675Sbms	 * We can compute that by subtracting the value of the checksum
324127675Sbms	 * field from the sum of all the data in the packet, and then
325127675Sbms	 * computing the negative of that value.
326127675Sbms	 *
327127675Sbms	 * "sum" is the value of the checksum field, and "computed_sum"
328127675Sbms	 * is the negative of the sum of all the data in the packets,
329127675Sbms	 * so that's -(-computed_sum - sum), or (sum + computed_sum).
330127675Sbms	 *
331127675Sbms	 * All the arithmetic in question is one's complement, so the
332127675Sbms	 * addition must include an end-around carry; we do this by
333127675Sbms	 * doing the arithmetic in 32 bits (with no sign-extension),
334127675Sbms	 * and then adding the upper 16 bits of the sum, which contain
335127675Sbms	 * the carry, to the lower 16 bits of the sum, and then do it
336127675Sbms	 * again in case *that* sum produced a carry.
337127675Sbms	 *
338127675Sbms	 * As RFC 1071 notes, the checksum can be computed without
339127675Sbms	 * byte-swapping the 16-bit words; summing 16-bit words
340127675Sbms	 * on a big-endian machine gives a big-endian checksum, which
341127675Sbms	 * can be directly stuffed into the big-endian checksum fields
342127675Sbms	 * in protocol headers, and summing words on a little-endian
343127675Sbms	 * machine gives a little-endian checksum, which must be
344127675Sbms	 * byte-swapped before being stuffed into a big-endian checksum
345127675Sbms	 * field.
346127675Sbms	 *
347127675Sbms	 * "computed_sum" is a network-byte-order value, so we must put
348127675Sbms	 * it in host byte order before subtracting it from the
349127675Sbms	 * host-byte-order value from the header; the adjusted checksum
350127675Sbms	 * will be in host byte order, which is what we'll return.
351127675Sbms	 */
352127675Sbms	shouldbe = sum;
353127675Sbms	shouldbe += ntohs(computed_sum);
354127675Sbms	shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16);
355127675Sbms	shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16);
356127675Sbms	return shouldbe;
357127675Sbms}
358127675Sbms
359127675Sbms#define IP_RES 0x8000
360127675Sbms
361127675Sbmsstatic struct tok ip_frag_values[] = {
362127675Sbms        { IP_MF,        "+" },
363127675Sbms        { IP_DF,        "DF" },
364127675Sbms	{ IP_RES,       "rsvd" }, /* The RFC3514 evil ;-) bit */
365127675Sbms        { 0,            NULL }
366127675Sbms};
367127675Sbms
368146778Ssamstruct ip_print_demux_state {
369146778Ssam	const struct ip *ip;
370146778Ssam	const u_char *cp;
371146778Ssam	u_int   len, off;
372146778Ssam	u_char  nh;
373146778Ssam	int     advance;
374146778Ssam};
375146778Ssam
376146778Ssamstatic void
377146778Ssamip_print_demux(netdissect_options *ndo,
378146778Ssam	       struct ip_print_demux_state *ipds)
379146778Ssam{
380146778Ssam	struct protoent *proto;
381146778Ssam
382146778Ssamagain:
383146778Ssam	switch (ipds->nh) {
384146778Ssam
385146778Ssam	case IPPROTO_AH:
386146778Ssam		ipds->nh = *ipds->cp;
387146778Ssam		ipds->advance = ah_print(ipds->cp);
388146778Ssam		if (ipds->advance <= 0)
389146778Ssam			break;
390146778Ssam		ipds->cp += ipds->advance;
391146778Ssam		ipds->len -= ipds->advance;
392146778Ssam		goto again;
393146778Ssam
394146778Ssam	case IPPROTO_ESP:
395146778Ssam	{
396146778Ssam		int enh, padlen;
397146778Ssam		ipds->advance = esp_print(ndo, ipds->cp, ipds->len,
398146778Ssam				    (const u_char *)ipds->ip,
399146778Ssam				    &enh, &padlen);
400146778Ssam		if (ipds->advance <= 0)
401146778Ssam			break;
402146778Ssam		ipds->cp += ipds->advance;
403146778Ssam		ipds->len -= ipds->advance + padlen;
404146778Ssam		ipds->nh = enh & 0xff;
405146778Ssam		goto again;
406146778Ssam	}
407146778Ssam
408146778Ssam	case IPPROTO_IPCOMP:
409146778Ssam	{
410146778Ssam		int enh;
411146778Ssam		ipds->advance = ipcomp_print(ipds->cp, &enh);
412146778Ssam		if (ipds->advance <= 0)
413146778Ssam			break;
414146778Ssam		ipds->cp += ipds->advance;
415146778Ssam		ipds->len -= ipds->advance;
416146778Ssam		ipds->nh = enh & 0xff;
417146778Ssam		goto again;
418146778Ssam	}
419146778Ssam
420146778Ssam	case IPPROTO_SCTP:
421146778Ssam		sctp_print(ipds->cp, (const u_char *)ipds->ip, ipds->len);
422146778Ssam		break;
423162021Ssam
424162021Ssam	case IPPROTO_DCCP:
425162021Ssam		dccp_print(ipds->cp, (const u_char *)ipds->ip, ipds->len);
426162021Ssam		break;
427146778Ssam
428146778Ssam	case IPPROTO_TCP:
429172686Smlaier		/* pass on the MF bit plus the offset to detect fragments */
430146778Ssam		tcp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip,
431172686Smlaier			  ipds->off & (IP_MF|IP_OFFMASK));
432146778Ssam		break;
433146778Ssam
434146778Ssam	case IPPROTO_UDP:
435172686Smlaier		/* pass on the MF bit plus the offset to detect fragments */
436146778Ssam		udp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip,
437172686Smlaier			  ipds->off & (IP_MF|IP_OFFMASK));
438146778Ssam		break;
439146778Ssam
440146778Ssam	case IPPROTO_ICMP:
441146778Ssam		/* pass on the MF bit plus the offset to detect fragments */
442146778Ssam		icmp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip,
443172686Smlaier			   ipds->off & (IP_MF|IP_OFFMASK));
444146778Ssam		break;
445146778Ssam
446146778Ssam	case IPPROTO_PIGP:
447146778Ssam		/*
448146778Ssam		 * XXX - the current IANA protocol number assignments
449146778Ssam		 * page lists 9 as "any private interior gateway
450146778Ssam		 * (used by Cisco for their IGRP)" and 88 as
451146778Ssam		 * "EIGRP" from Cisco.
452146778Ssam		 *
453146778Ssam		 * Recent BSD <netinet/in.h> headers define
454146778Ssam		 * IP_PROTO_PIGP as 9 and IP_PROTO_IGRP as 88.
455146778Ssam		 * We define IP_PROTO_PIGP as 9 and
456146778Ssam		 * IP_PROTO_EIGRP as 88; those names better
457146778Ssam		 * match was the current protocol number
458146778Ssam		 * assignments say.
459146778Ssam		 */
460146778Ssam		igrp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip);
461146778Ssam		break;
462146778Ssam
463146778Ssam	case IPPROTO_EIGRP:
464146778Ssam		eigrp_print(ipds->cp, ipds->len);
465146778Ssam		break;
466146778Ssam
467146778Ssam	case IPPROTO_ND:
468146778Ssam		ND_PRINT((ndo, " nd %d", ipds->len));
469146778Ssam		break;
470146778Ssam
471146778Ssam	case IPPROTO_EGP:
472146778Ssam		egp_print(ipds->cp, ipds->len);
473146778Ssam		break;
474146778Ssam
475146778Ssam	case IPPROTO_OSPF:
476146778Ssam		ospf_print(ipds->cp, ipds->len, (const u_char *)ipds->ip);
477146778Ssam		break;
478146778Ssam
479146778Ssam	case IPPROTO_IGMP:
480146778Ssam		igmp_print(ipds->cp, ipds->len);
481146778Ssam		break;
482146778Ssam
483146778Ssam	case IPPROTO_IPV4:
484146778Ssam		/* DVMRP multicast tunnel (ip-in-ip encapsulation) */
485146778Ssam		ip_print(gndo, ipds->cp, ipds->len);
486146778Ssam		if (! vflag) {
487146778Ssam			ND_PRINT((ndo, " (ipip-proto-4)"));
488146778Ssam			return;
489146778Ssam		}
490146778Ssam		break;
491146778Ssam
492146778Ssam#ifdef INET6
493146778Ssam	case IPPROTO_IPV6:
494146778Ssam		/* ip6-in-ip encapsulation */
495146778Ssam		ip6_print(ipds->cp, ipds->len);
496146778Ssam		break;
497146778Ssam#endif /*INET6*/
498146778Ssam
499146778Ssam	case IPPROTO_RSVP:
500146778Ssam		rsvp_print(ipds->cp, ipds->len);
501146778Ssam		break;
502146778Ssam
503146778Ssam	case IPPROTO_GRE:
504146778Ssam		/* do it */
505146778Ssam		gre_print(ipds->cp, ipds->len);
506146778Ssam		break;
507146778Ssam
508146778Ssam	case IPPROTO_MOBILE:
509146778Ssam		mobile_print(ipds->cp, ipds->len);
510146778Ssam		break;
511146778Ssam
512146778Ssam	case IPPROTO_PIM:
513146778Ssam		pim_print(ipds->cp,  ipds->len);
514146778Ssam		break;
515146778Ssam
516146778Ssam	case IPPROTO_VRRP:
517146778Ssam		vrrp_print(ipds->cp, ipds->len, ipds->ip->ip_ttl);
518146778Ssam		break;
519146778Ssam
520147904Ssam	case IPPROTO_PGM:
521147904Ssam		pgm_print(ipds->cp, ipds->len, (const u_char *)ipds->ip);
522147904Ssam		break;
523147904Ssam
524146778Ssam	default:
525146778Ssam		if ((proto = getprotobynumber(ipds->nh)) != NULL)
526146778Ssam			ND_PRINT((ndo, " %s", proto->p_name));
527146778Ssam		else
528146778Ssam			ND_PRINT((ndo, " ip-proto-%d", ipds->nh));
529146778Ssam		ND_PRINT((ndo, " %d", ipds->len));
530146778Ssam		break;
531146778Ssam	}
532146778Ssam}
533146778Ssam
534146778Ssamvoid
535146778Ssamip_print_inner(netdissect_options *ndo,
536146778Ssam	       const u_char *bp,
537146778Ssam	       u_int length, u_int nh,
538146778Ssam	       const u_char *bp2)
539146778Ssam{
540146778Ssam	struct ip_print_demux_state  ipd;
541146778Ssam
542146778Ssam	ipd.ip = (const struct ip *)bp2;
543146778Ssam	ipd.cp = bp;
544146778Ssam	ipd.len  = length;
545146778Ssam	ipd.off  = 0;
546146778Ssam	ipd.nh   = nh;
547146778Ssam	ipd.advance = 0;
548146778Ssam
549146778Ssam	ip_print_demux(ndo, &ipd);
550146778Ssam}
551146778Ssam
552146778Ssam
553127675Sbms/*
55417680Spst * print an IP datagram.
55517680Spst */
55617680Spstvoid
557146778Ssamip_print(netdissect_options *ndo,
558146778Ssam	 const u_char *bp,
559146778Ssam	 u_int length)
56017680Spst{
561146778Ssam	struct ip_print_demux_state  ipd;
562146778Ssam	struct ip_print_demux_state *ipds=&ipd;
563127675Sbms	const u_char *ipend;
564146778Ssam	u_int hlen;
565146778Ssam	u_int16_t sum, ip_sum;
566111729Sfenner	struct protoent *proto;
56717680Spst
568146778Ssam	ipds->ip = (const struct ip *)bp;
569146778Ssam	if (IP_V(ipds->ip) != 4) { /* print version if != 4 */
570146778Ssam	    printf("IP%u ", IP_V(ipds->ip));
571146778Ssam	    if (IP_V(ipds->ip) == 6)
572127675Sbms		printf(", wrong link-layer encapsulation");
573127675Sbms	}
574146778Ssam        else if (!eflag)
575127675Sbms	    printf("IP ");
57617680Spst
577146778Ssam	if ((u_char *)(ipds->ip + 1) > snapend) {
57817680Spst		printf("[|ip]");
57917680Spst		return;
58017680Spst	}
58117680Spst	if (length < sizeof (struct ip)) {
582146778Ssam		(void)printf("truncated-ip %u", length);
58317680Spst		return;
58417680Spst	}
585146778Ssam	hlen = IP_HL(ipds->ip) * 4;
58675118Sfenner	if (hlen < sizeof (struct ip)) {
587127675Sbms		(void)printf("bad-hlen %u", hlen);
58875118Sfenner		return;
58975118Sfenner	}
59017680Spst
591146778Ssam	ipds->len = EXTRACT_16BITS(&ipds->ip->ip_len);
592146778Ssam	if (length < ipds->len)
593127675Sbms		(void)printf("truncated-ip - %u bytes missing! ",
594146778Ssam			ipds->len - length);
595146778Ssam	if (ipds->len < hlen) {
596146778Ssam#ifdef GUESS_TSO
597146778Ssam            if (ipds->len) {
598146778Ssam                (void)printf("bad-len %u", ipds->len);
599146778Ssam                return;
600146778Ssam            }
601146778Ssam            else {
602146778Ssam                /* we guess that it is a TSO send */
603146778Ssam                ipds->len = length;
604146778Ssam            }
605146778Ssam#else
606146778Ssam            (void)printf("bad-len %u", ipds->len);
607146778Ssam            return;
608146778Ssam#endif /* GUESS_TSO */
609127675Sbms	}
610127675Sbms
611127675Sbms	/*
612127675Sbms	 * Cut off the snapshot length to the end of the IP payload.
613127675Sbms	 */
614146778Ssam	ipend = bp + ipds->len;
615127675Sbms	if (ipend < snapend)
616127675Sbms		snapend = ipend;
617127675Sbms
618146778Ssam	ipds->len -= hlen;
61917680Spst
620146778Ssam	ipds->off = EXTRACT_16BITS(&ipds->ip->ip_off);
621127675Sbms
622127675Sbms        if (vflag) {
623146778Ssam            (void)printf("(tos 0x%x", (int)ipds->ip->ip_tos);
624127675Sbms            /* ECN bits */
625146778Ssam            if (ipds->ip->ip_tos & 0x03) {
626146778Ssam                switch (ipds->ip->ip_tos & 0x03) {
627127675Sbms                case 1:
628127675Sbms                    (void)printf(",ECT(1)");
629127675Sbms                    break;
630127675Sbms                case 2:
631127675Sbms                    (void)printf(",ECT(0)");
632127675Sbms                    break;
633127675Sbms                case 3:
634127675Sbms                    (void)printf(",CE");
635127675Sbms                }
636127675Sbms            }
637127675Sbms
638146778Ssam            if (ipds->ip->ip_ttl >= 1)
639172686Smlaier                (void)printf(", ttl %u", ipds->ip->ip_ttl);
640127675Sbms
641127675Sbms	    /*
642127675Sbms	     * for the firewall guys, print id, offset.
643127675Sbms             * On all but the last stick a "+" in the flags portion.
644127675Sbms	     * For unfragmented datagrams, note the don't fragment flag.
645127675Sbms	     */
646127675Sbms
647172686Smlaier	    (void)printf(", id %u, offset %u, flags [%s], proto %s (%u)",
648146778Ssam                         EXTRACT_16BITS(&ipds->ip->ip_id),
649146778Ssam                         (ipds->off & 0x1fff) * 8,
650172686Smlaier                         bittok2str(ip_frag_values, "none", ipds->off&0xe000),
651146778Ssam                         tok2str(ipproto_values,"unknown",ipds->ip->ip_p),
652146778Ssam                         ipds->ip->ip_p);
653127675Sbms
654172686Smlaier            (void)printf(", length %u", EXTRACT_16BITS(&ipds->ip->ip_len));
655127675Sbms
656127675Sbms            if ((hlen - sizeof(struct ip)) > 0) {
657172686Smlaier                printf(", options (");
658146778Ssam                ip_optprint((u_char *)(ipds->ip + 1), hlen - sizeof(struct ip));
659172686Smlaier                printf(")");
660127675Sbms            }
661127675Sbms
662146778Ssam	    if ((u_char *)ipds->ip + hlen <= snapend) {
663146778Ssam	        sum = in_cksum((const u_short *)ipds->ip, hlen, 0);
664127675Sbms		if (sum != 0) {
665146778Ssam		    ip_sum = EXTRACT_16BITS(&ipds->ip->ip_sum);
666127675Sbms		    (void)printf(", bad cksum %x (->%x)!", ip_sum,
667127675Sbms			     in_cksum_shouldbe(ip_sum, sum));
668127675Sbms		}
669127675Sbms	    }
670127675Sbms
671127675Sbms            printf(") ");
672127675Sbms	}
673127675Sbms
67417680Spst	/*
67517680Spst	 * If this is fragment zero, hand it to the next higher
67617680Spst	 * level protocol.
67717680Spst	 */
678146778Ssam	if ((ipds->off & 0x1fff) == 0) {
679146778Ssam		ipds->cp = (const u_char *)ipds->ip + hlen;
680146778Ssam		ipds->nh = ipds->ip->ip_p;
68117680Spst
682146778Ssam		if (ipds->nh != IPPROTO_TCP && ipds->nh != IPPROTO_UDP &&
683162021Ssam		    ipds->nh != IPPROTO_SCTP && ipds->nh != IPPROTO_DCCP) {
684146778Ssam			(void)printf("%s > %s: ",
685146778Ssam				     ipaddr_string(&ipds->ip->ip_src),
686146778Ssam				     ipaddr_string(&ipds->ip->ip_dst));
68756896Sfenner		}
688146778Ssam		ip_print_demux(ndo, ipds);
689127675Sbms	} else {
690127675Sbms	    /* Ultra quiet now means that all this stuff should be suppressed */
691127675Sbms	    if (qflag > 1) return;
69256896Sfenner
693127675Sbms	    /*
694127675Sbms	     * if this isn't the first frag, we're missing the
695127675Sbms	     * next level protocol header.  print the ip addr
696127675Sbms	     * and the protocol.
697127675Sbms	     */
698146778Ssam	    if (ipds->off & 0x1fff) {
699146778Ssam	        (void)printf("%s > %s:", ipaddr_string(&ipds->ip->ip_src),
700146778Ssam			     ipaddr_string(&ipds->ip->ip_dst));
701146778Ssam		if ((proto = getprotobynumber(ipds->ip->ip_p)) != NULL)
702127675Sbms		    (void)printf(" %s", proto->p_name);
703127675Sbms		else
704146778Ssam		    (void)printf(" ip-proto-%d", ipds->ip->ip_p);
705127675Sbms	    }
70656896Sfenner	}
70717680Spst}
70875118Sfenner
70975118Sfennervoid
71075118SfenneripN_print(register const u_char *bp, register u_int length)
71175118Sfenner{
71275118Sfenner	struct ip *ip, hdr;
71375118Sfenner
71475118Sfenner	ip = (struct ip *)bp;
71575118Sfenner	if (length < 4) {
71675118Sfenner		(void)printf("truncated-ip %d", length);
71775118Sfenner		return;
71875118Sfenner	}
71975118Sfenner	memcpy (&hdr, (char *)ip, 4);
72075118Sfenner	switch (IP_V(&hdr)) {
72175118Sfenner	case 4:
722146778Ssam		ip_print (gndo, bp, length);
72398527Sfenner		return;
72475118Sfenner#ifdef INET6
72575118Sfenner	case 6:
72698527Sfenner		ip6_print (bp, length);
72798527Sfenner		return;
72875118Sfenner#endif
72975118Sfenner	default:
73098527Sfenner		(void)printf("unknown ip %d", IP_V(&hdr));
73198527Sfenner		return;
73275118Sfenner	}
73375118Sfenner}
734127675Sbms
735146778Ssam/*
736146778Ssam * Local Variables:
737146778Ssam * c-style: whitesmith
738146778Ssam * c-basic-offset: 8
739146778Ssam * End:
740146778Ssam */
741127675Sbms
742127675Sbms
743