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.
2017680Spst */
2117680Spst
22313537Sglebius/* \summary: IP printer */
23313537Sglebius
2456896Sfenner#ifdef HAVE_CONFIG_H
2556896Sfenner#include "config.h"
2656896Sfenner#endif
2756896Sfenner
28313537Sglebius#include <netdissect-stdinc.h>
2917680Spst
3017680Spst#include <string.h>
3117680Spst
32313537Sglebius#include "netdissect.h"
3317680Spst#include "addrtoname.h"
34313537Sglebius#include "extract.h"
3517680Spst
3675118Sfenner#include "ip.h"
37127675Sbms#include "ipproto.h"
3875118Sfenner
39276788Sdelphijstatic const char tstr[] = "[|ip]";
40276788Sdelphij
41276788Sdelphijstatic const struct tok ip_option_values[] = {
42146778Ssam    { IPOPT_EOL, "EOL" },
43146778Ssam    { IPOPT_NOP, "NOP" },
44146778Ssam    { IPOPT_TS, "timestamp" },
45146778Ssam    { IPOPT_SECURITY, "security" },
46146778Ssam    { IPOPT_RR, "RR" },
47146778Ssam    { IPOPT_SSRR, "SSRR" },
48146778Ssam    { IPOPT_LSRR, "LSRR" },
49146778Ssam    { IPOPT_RA, "RA" },
50172686Smlaier    { IPOPT_RFC1393, "traceroute" },
51146778Ssam    { 0, NULL }
52146778Ssam};
53146778Ssam
5417680Spst/*
5517680Spst * print the recorded route in an IP RR, LSRR or SSRR option.
5617680Spst */
57327234Semastestatic int
58276788Sdelphijip_printroute(netdissect_options *ndo,
59276788Sdelphij              register const u_char *cp, u_int length)
6017680Spst{
61127675Sbms	register u_int ptr;
6217680Spst	register u_int len;
6317680Spst
64127675Sbms	if (length < 3) {
65276788Sdelphij		ND_PRINT((ndo, " [bad length %u]", length));
66327234Semaste		return (0);
67127675Sbms	}
6817680Spst	if ((length + 1) & 3)
69276788Sdelphij		ND_PRINT((ndo, " [bad length %u]", length));
70327234Semaste	ND_TCHECK(cp[2]);
71127675Sbms	ptr = cp[2] - 1;
7217680Spst	if (ptr < 3 || ((ptr + 1) & 3) || ptr > length + 1)
73276788Sdelphij		ND_PRINT((ndo, " [bad ptr %u]", cp[2]));
7417680Spst
7517680Spst	for (len = 3; len < length; len += 4) {
76327234Semaste		ND_TCHECK2(cp[len], 4);
77276788Sdelphij		ND_PRINT((ndo, " %s", ipaddr_string(ndo, &cp[len])));
78276788Sdelphij		if (ptr > len)
79276788Sdelphij			ND_PRINT((ndo, ","));
8017680Spst	}
81327234Semaste	return (0);
82327234Semaste
83327234Semastetrunc:
84327234Semaste	return (-1);
8517680Spst}
8617680Spst
87127675Sbms/*
88146778Ssam * If source-routing is present and valid, return the final destination.
89127675Sbms * Otherwise, return IP destination.
90127675Sbms *
91127675Sbms * This is used for UDP and TCP pseudo-header in the checksum
92127675Sbms * calculation.
93127675Sbms */
94276788Sdelphijstatic uint32_t
95276788Sdelphijip_finddst(netdissect_options *ndo,
96276788Sdelphij           const struct ip *ip)
97127675Sbms{
98127675Sbms	int length;
99127675Sbms	int len;
100127675Sbms	const u_char *cp;
101276788Sdelphij	uint32_t retval;
102127675Sbms
103127675Sbms	cp = (const u_char *)(ip + 1);
104127675Sbms	length = (IP_HL(ip) << 2) - sizeof(struct ip);
105127675Sbms
106127675Sbms	for (; length > 0; cp += len, length -= len) {
107127675Sbms		int tt;
108127675Sbms
109276788Sdelphij		ND_TCHECK(*cp);
110127675Sbms		tt = *cp;
111146778Ssam		if (tt == IPOPT_EOL)
112146778Ssam			break;
113146778Ssam		else if (tt == IPOPT_NOP)
114127675Sbms			len = 1;
115127675Sbms		else {
116276788Sdelphij			ND_TCHECK(cp[1]);
117127675Sbms			len = cp[1];
118146778Ssam			if (len < 2)
119146778Ssam				break;
120127675Sbms		}
121276788Sdelphij		ND_TCHECK2(*cp, len);
122127675Sbms		switch (tt) {
123127675Sbms
124127675Sbms		case IPOPT_SSRR:
125127675Sbms		case IPOPT_LSRR:
126127675Sbms			if (len < 7)
127146778Ssam				break;
128276788Sdelphij			UNALIGNED_MEMCPY(&retval, cp + len - 4, 4);
129127675Sbms			return retval;
130127675Sbms		}
131127675Sbms	}
132127675Sbmstrunc:
133313537Sglebius	UNALIGNED_MEMCPY(&retval, &ip->ip_dst, sizeof(uint32_t));
134146778Ssam	return retval;
135127675Sbms}
136127675Sbms
137235530Sdelphij/*
138235530Sdelphij * Compute a V4-style checksum by building a pseudoheader.
139235530Sdelphij */
140235530Sdelphijint
141276788Sdelphijnextproto4_cksum(netdissect_options *ndo,
142276788Sdelphij                 const struct ip *ip, const uint8_t *data,
143276788Sdelphij                 u_int len, u_int covlen, u_int next_proto)
144235530Sdelphij{
145235530Sdelphij	struct phdr {
146276788Sdelphij		uint32_t src;
147276788Sdelphij		uint32_t dst;
148235530Sdelphij		u_char mbz;
149235530Sdelphij		u_char proto;
150276788Sdelphij		uint16_t len;
151235530Sdelphij	} ph;
152235530Sdelphij	struct cksum_vec vec[2];
153235530Sdelphij
154235530Sdelphij	/* pseudo-header.. */
155276788Sdelphij	ph.len = htons((uint16_t)len);
156235530Sdelphij	ph.mbz = 0;
157235530Sdelphij	ph.proto = next_proto;
158313537Sglebius	UNALIGNED_MEMCPY(&ph.src, &ip->ip_src, sizeof(uint32_t));
159235530Sdelphij	if (IP_HL(ip) == 5)
160313537Sglebius		UNALIGNED_MEMCPY(&ph.dst, &ip->ip_dst, sizeof(uint32_t));
161235530Sdelphij	else
162276788Sdelphij		ph.dst = ip_finddst(ndo, ip);
163235530Sdelphij
164276788Sdelphij	vec[0].ptr = (const uint8_t *)(void *)&ph;
165235530Sdelphij	vec[0].len = sizeof(ph);
166235530Sdelphij	vec[1].ptr = data;
167276788Sdelphij	vec[1].len = covlen;
168235530Sdelphij	return (in_cksum(vec, 2));
169235530Sdelphij}
170235530Sdelphij
171327234Semastestatic int
172276788Sdelphijip_printts(netdissect_options *ndo,
173276788Sdelphij           register const u_char *cp, u_int length)
17456896Sfenner{
175127675Sbms	register u_int ptr;
176127675Sbms	register u_int len;
17756896Sfenner	int hoplen;
178127675Sbms	const char *type;
17956896Sfenner
180127675Sbms	if (length < 4) {
181276788Sdelphij		ND_PRINT((ndo, "[bad length %u]", length));
182327234Semaste		return (0);
183127675Sbms	}
184276788Sdelphij	ND_PRINT((ndo, " TS{"));
18556896Sfenner	hoplen = ((cp[3]&0xF) != IPOPT_TS_TSONLY) ? 8 : 4;
18656896Sfenner	if ((length - 4) & (hoplen-1))
187276788Sdelphij		ND_PRINT((ndo, "[bad length %u]", length));
188327234Semaste	ND_TCHECK(cp[2]);
189127675Sbms	ptr = cp[2] - 1;
190127675Sbms	len = 0;
19156896Sfenner	if (ptr < 4 || ((ptr - 4) & (hoplen-1)) || ptr > length + 1)
192276788Sdelphij		ND_PRINT((ndo, "[bad ptr %u]", cp[2]));
193327234Semaste	ND_TCHECK(cp[3]);
19456896Sfenner	switch (cp[3]&0xF) {
19556896Sfenner	case IPOPT_TS_TSONLY:
196276788Sdelphij		ND_PRINT((ndo, "TSONLY"));
19756896Sfenner		break;
19856896Sfenner	case IPOPT_TS_TSANDADDR:
199276788Sdelphij		ND_PRINT((ndo, "TS+ADDR"));
20056896Sfenner		break;
20156896Sfenner	/*
20256896Sfenner	 * prespecified should really be 3, but some ones might send 2
20356896Sfenner	 * instead, and the IPOPT_TS_PRESPEC constant can apparently
20456896Sfenner	 * have both values, so we have to hard-code it here.
20556896Sfenner	 */
20656896Sfenner
20756896Sfenner	case 2:
208276788Sdelphij		ND_PRINT((ndo, "PRESPEC2.0"));
20956896Sfenner		break;
21056896Sfenner	case 3:			/* IPOPT_TS_PRESPEC */
211276788Sdelphij		ND_PRINT((ndo, "PRESPEC"));
21256896Sfenner		break;
213127675Sbms	default:
214276788Sdelphij		ND_PRINT((ndo, "[bad ts type %d]", cp[3]&0xF));
21556896Sfenner		goto done;
21656896Sfenner	}
21756896Sfenner
21856896Sfenner	type = " ";
21956896Sfenner	for (len = 4; len < length; len += hoplen) {
22056896Sfenner		if (ptr == len)
22156896Sfenner			type = " ^ ";
222327234Semaste		ND_TCHECK2(cp[len], hoplen);
223276788Sdelphij		ND_PRINT((ndo, "%s%d@%s", type, EXTRACT_32BITS(&cp[len+hoplen-4]),
224276788Sdelphij		       hoplen!=8 ? "" : ipaddr_string(ndo, &cp[len])));
22556896Sfenner		type = " ";
22656896Sfenner	}
22756896Sfenner
22856896Sfennerdone:
229276788Sdelphij	ND_PRINT((ndo, "%s", ptr == len ? " ^ " : ""));
23056896Sfenner
23156896Sfenner	if (cp[3]>>4)
232276788Sdelphij		ND_PRINT((ndo, " [%d hops not recorded]} ", cp[3]>>4));
23356896Sfenner	else
234276788Sdelphij		ND_PRINT((ndo, "}"));
235327234Semaste	return (0);
236327234Semaste
237327234Semastetrunc:
238327234Semaste	return (-1);
23956896Sfenner}
24056896Sfenner
24117680Spst/*
24217680Spst * print IP options.
24317680Spst */
24417680Spststatic void
245276788Sdelphijip_optprint(netdissect_options *ndo,
246276788Sdelphij            register const u_char *cp, u_int length)
24717680Spst{
248146778Ssam	register u_int option_len;
249172686Smlaier	const char *sep = "";
25017680Spst
251146778Ssam	for (; length > 0; cp += option_len, length -= option_len) {
252146778Ssam		u_int option_code;
25317680Spst
254276788Sdelphij		ND_PRINT((ndo, "%s", sep));
255172686Smlaier		sep = ",";
256172686Smlaier
257276788Sdelphij		ND_TCHECK(*cp);
258146778Ssam		option_code = *cp;
259146778Ssam
260276788Sdelphij		ND_PRINT((ndo, "%s",
261276788Sdelphij		          tok2str(ip_option_values,"unknown %u",option_code)));
262172686Smlaier
263146778Ssam		if (option_code == IPOPT_NOP ||
264146778Ssam                    option_code == IPOPT_EOL)
265146778Ssam			option_len = 1;
266146778Ssam
26775118Sfenner		else {
268276788Sdelphij			ND_TCHECK(cp[1]);
269172686Smlaier			option_len = cp[1];
270172686Smlaier			if (option_len < 2) {
271276788Sdelphij				ND_PRINT((ndo, " [bad length %u]", option_len));
272172686Smlaier				return;
273172686Smlaier			}
27475118Sfenner		}
27517680Spst
276172686Smlaier		if (option_len > length) {
277276788Sdelphij			ND_PRINT((ndo, " [bad length %u]", option_len));
278172686Smlaier			return;
279172686Smlaier		}
280146778Ssam
281276788Sdelphij		ND_TCHECK2(*cp, option_len);
282146778Ssam
283146778Ssam		switch (option_code) {
28417680Spst		case IPOPT_EOL:
28517680Spst			return;
28617680Spst
28717680Spst		case IPOPT_TS:
288327234Semaste			if (ip_printts(ndo, cp, option_len) == -1)
289327234Semaste				goto trunc;
29017680Spst			break;
29117680Spst
292146778Ssam		case IPOPT_RR:       /* fall through */
29317680Spst		case IPOPT_SSRR:
29417680Spst		case IPOPT_LSRR:
295327234Semaste			if (ip_printroute(ndo, cp, option_len) == -1)
296327234Semaste				goto trunc;
29717680Spst			break;
29817680Spst
29917691Spst		case IPOPT_RA:
300172686Smlaier			if (option_len < 4) {
301276788Sdelphij				ND_PRINT((ndo, " [bad length %u]", option_len));
302172686Smlaier				break;
303172686Smlaier			}
304276788Sdelphij			ND_TCHECK(cp[3]);
305276788Sdelphij			if (EXTRACT_16BITS(&cp[2]) != 0)
306276788Sdelphij				ND_PRINT((ndo, " value %u", EXTRACT_16BITS(&cp[2])));
30798527Sfenner			break;
30817691Spst
309146778Ssam		case IPOPT_NOP:       /* nothing to print - fall through */
310146778Ssam		case IPOPT_SECURITY:
31117680Spst		default:
31217680Spst			break;
31317680Spst		}
31417680Spst	}
315127675Sbms	return;
316127675Sbms
317127675Sbmstrunc:
318276788Sdelphij	ND_PRINT((ndo, "%s", tstr));
31917680Spst}
32017680Spst
321127675Sbms#define IP_RES 0x8000
322127675Sbms
323276788Sdelphijstatic const struct tok ip_frag_values[] = {
324127675Sbms        { IP_MF,        "+" },
325127675Sbms        { IP_DF,        "DF" },
326127675Sbms	{ IP_RES,       "rsvd" }, /* The RFC3514 evil ;-) bit */
327127675Sbms        { 0,            NULL }
328127675Sbms};
329127675Sbms
330146778Ssamstruct ip_print_demux_state {
331146778Ssam	const struct ip *ip;
332146778Ssam	const u_char *cp;
333146778Ssam	u_int   len, off;
334146778Ssam	u_char  nh;
335146778Ssam	int     advance;
336146778Ssam};
337146778Ssam
338146778Ssamstatic void
339146778Ssamip_print_demux(netdissect_options *ndo,
340146778Ssam	       struct ip_print_demux_state *ipds)
341146778Ssam{
342327234Semaste	const char *p_name;
343146778Ssam
344146778Ssamagain:
345146778Ssam	switch (ipds->nh) {
346146778Ssam
347146778Ssam	case IPPROTO_AH:
348313537Sglebius		if (!ND_TTEST(*ipds->cp)) {
349313537Sglebius			ND_PRINT((ndo, "[|AH]"));
350313537Sglebius			break;
351313537Sglebius		}
352146778Ssam		ipds->nh = *ipds->cp;
353276788Sdelphij		ipds->advance = ah_print(ndo, ipds->cp);
354146778Ssam		if (ipds->advance <= 0)
355146778Ssam			break;
356146778Ssam		ipds->cp += ipds->advance;
357146778Ssam		ipds->len -= ipds->advance;
358146778Ssam		goto again;
359146778Ssam
360146778Ssam	case IPPROTO_ESP:
361146778Ssam	{
362146778Ssam		int enh, padlen;
363146778Ssam		ipds->advance = esp_print(ndo, ipds->cp, ipds->len,
364146778Ssam				    (const u_char *)ipds->ip,
365146778Ssam				    &enh, &padlen);
366146778Ssam		if (ipds->advance <= 0)
367146778Ssam			break;
368146778Ssam		ipds->cp += ipds->advance;
369146778Ssam		ipds->len -= ipds->advance + padlen;
370146778Ssam		ipds->nh = enh & 0xff;
371146778Ssam		goto again;
372146778Ssam	}
373241235Sdelphij
374146778Ssam	case IPPROTO_IPCOMP:
375146778Ssam	{
376313537Sglebius		ipcomp_print(ndo, ipds->cp);
377313537Sglebius		/*
378313537Sglebius		 * Either this has decompressed the payload and
379313537Sglebius		 * printed it, in which case there's nothing more
380313537Sglebius		 * to do, or it hasn't, in which case there's
381313537Sglebius		 * nothing more to do.
382313537Sglebius		 */
383313537Sglebius		break;
384146778Ssam	}
385146778Ssam
386146778Ssam	case IPPROTO_SCTP:
387276788Sdelphij		sctp_print(ndo, ipds->cp, (const u_char *)ipds->ip, ipds->len);
388146778Ssam		break;
389162021Ssam
390162021Ssam	case IPPROTO_DCCP:
391276788Sdelphij		dccp_print(ndo, ipds->cp, (const u_char *)ipds->ip, ipds->len);
392162021Ssam		break;
393241235Sdelphij
394146778Ssam	case IPPROTO_TCP:
395172686Smlaier		/* pass on the MF bit plus the offset to detect fragments */
396276788Sdelphij		tcp_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip,
397172686Smlaier			  ipds->off & (IP_MF|IP_OFFMASK));
398146778Ssam		break;
399241235Sdelphij
400146778Ssam	case IPPROTO_UDP:
401172686Smlaier		/* pass on the MF bit plus the offset to detect fragments */
402276788Sdelphij		udp_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip,
403172686Smlaier			  ipds->off & (IP_MF|IP_OFFMASK));
404146778Ssam		break;
405241235Sdelphij
406146778Ssam	case IPPROTO_ICMP:
407146778Ssam		/* pass on the MF bit plus the offset to detect fragments */
408276788Sdelphij		icmp_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip,
409172686Smlaier			   ipds->off & (IP_MF|IP_OFFMASK));
410146778Ssam		break;
411241235Sdelphij
412146778Ssam	case IPPROTO_PIGP:
413146778Ssam		/*
414146778Ssam		 * XXX - the current IANA protocol number assignments
415146778Ssam		 * page lists 9 as "any private interior gateway
416146778Ssam		 * (used by Cisco for their IGRP)" and 88 as
417146778Ssam		 * "EIGRP" from Cisco.
418146778Ssam		 *
419146778Ssam		 * Recent BSD <netinet/in.h> headers define
420146778Ssam		 * IP_PROTO_PIGP as 9 and IP_PROTO_IGRP as 88.
421146778Ssam		 * We define IP_PROTO_PIGP as 9 and
422146778Ssam		 * IP_PROTO_EIGRP as 88; those names better
423146778Ssam		 * match was the current protocol number
424146778Ssam		 * assignments say.
425146778Ssam		 */
426276788Sdelphij		igrp_print(ndo, ipds->cp, ipds->len);
427146778Ssam		break;
428241235Sdelphij
429146778Ssam	case IPPROTO_EIGRP:
430276788Sdelphij		eigrp_print(ndo, ipds->cp, ipds->len);
431146778Ssam		break;
432241235Sdelphij
433146778Ssam	case IPPROTO_ND:
434146778Ssam		ND_PRINT((ndo, " nd %d", ipds->len));
435146778Ssam		break;
436146778Ssam
437146778Ssam	case IPPROTO_EGP:
438276788Sdelphij		egp_print(ndo, ipds->cp, ipds->len);
439146778Ssam		break;
440146778Ssam
441146778Ssam	case IPPROTO_OSPF:
442276788Sdelphij		ospf_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip);
443146778Ssam		break;
444146778Ssam
445146778Ssam	case IPPROTO_IGMP:
446276788Sdelphij		igmp_print(ndo, ipds->cp, ipds->len);
447146778Ssam		break;
448146778Ssam
449146778Ssam	case IPPROTO_IPV4:
450146778Ssam		/* DVMRP multicast tunnel (ip-in-ip encapsulation) */
451235530Sdelphij		ip_print(ndo, ipds->cp, ipds->len);
452276788Sdelphij		if (! ndo->ndo_vflag) {
453146778Ssam			ND_PRINT((ndo, " (ipip-proto-4)"));
454146778Ssam			return;
455146778Ssam		}
456146778Ssam		break;
457241235Sdelphij
458146778Ssam	case IPPROTO_IPV6:
459146778Ssam		/* ip6-in-ip encapsulation */
460235530Sdelphij		ip6_print(ndo, ipds->cp, ipds->len);
461146778Ssam		break;
462146778Ssam
463146778Ssam	case IPPROTO_RSVP:
464276788Sdelphij		rsvp_print(ndo, ipds->cp, ipds->len);
465146778Ssam		break;
466146778Ssam
467146778Ssam	case IPPROTO_GRE:
468146778Ssam		/* do it */
469276788Sdelphij		gre_print(ndo, ipds->cp, ipds->len);
470146778Ssam		break;
471146778Ssam
472146778Ssam	case IPPROTO_MOBILE:
473276788Sdelphij		mobile_print(ndo, ipds->cp, ipds->len);
474146778Ssam		break;
475146778Ssam
476146778Ssam	case IPPROTO_PIM:
477313537Sglebius		pim_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip);
478146778Ssam		break;
479146778Ssam
480146778Ssam	case IPPROTO_VRRP:
481276788Sdelphij		if (ndo->ndo_packettype == PT_CARP) {
482276788Sdelphij			if (ndo->ndo_vflag)
483276788Sdelphij				ND_PRINT((ndo, "carp %s > %s: ",
484276788Sdelphij					     ipaddr_string(ndo, &ipds->ip->ip_src),
485276788Sdelphij					     ipaddr_string(ndo, &ipds->ip->ip_dst)));
486276788Sdelphij			carp_print(ndo, ipds->cp, ipds->len, ipds->ip->ip_ttl);
487235530Sdelphij		} else {
488276788Sdelphij			if (ndo->ndo_vflag)
489276788Sdelphij				ND_PRINT((ndo, "vrrp %s > %s: ",
490276788Sdelphij					     ipaddr_string(ndo, &ipds->ip->ip_src),
491276788Sdelphij					     ipaddr_string(ndo, &ipds->ip->ip_dst)));
492276788Sdelphij			vrrp_print(ndo, ipds->cp, ipds->len,
493276788Sdelphij				(const u_char *)ipds->ip, ipds->ip->ip_ttl);
494235530Sdelphij		}
495146778Ssam		break;
496146778Ssam
497147904Ssam	case IPPROTO_PGM:
498276788Sdelphij		pgm_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip);
499147904Ssam		break;
500147904Ssam
501257349Sglebius#if defined(HAVE_NET_PFVAR_H)
502241221Sglebius	case IPPROTO_PFSYNC:
503281938Sbrooks		pfsync_ip_print(ndo, ipds->cp, ipds->len);
504241221Sglebius		break;
505257349Sglebius#endif
506241221Sglebius
507146778Ssam	default:
508327234Semaste		if (ndo->ndo_nflag==0 && (p_name = netdb_protoname(ipds->nh)) != NULL)
509327234Semaste			ND_PRINT((ndo, " %s", p_name));
510146778Ssam		else
511146778Ssam			ND_PRINT((ndo, " ip-proto-%d", ipds->nh));
512146778Ssam		ND_PRINT((ndo, " %d", ipds->len));
513146778Ssam		break;
514146778Ssam	}
515146778Ssam}
516241235Sdelphij
517146778Ssamvoid
518146778Ssamip_print_inner(netdissect_options *ndo,
519146778Ssam	       const u_char *bp,
520146778Ssam	       u_int length, u_int nh,
521146778Ssam	       const u_char *bp2)
522146778Ssam{
523146778Ssam	struct ip_print_demux_state  ipd;
524146778Ssam
525146778Ssam	ipd.ip = (const struct ip *)bp2;
526146778Ssam	ipd.cp = bp;
527146778Ssam	ipd.len  = length;
528146778Ssam	ipd.off  = 0;
529146778Ssam	ipd.nh   = nh;
530146778Ssam	ipd.advance = 0;
531146778Ssam
532146778Ssam	ip_print_demux(ndo, &ipd);
533146778Ssam}
534146778Ssam
535146778Ssam
536127675Sbms/*
53717680Spst * print an IP datagram.
53817680Spst */
53917680Spstvoid
540146778Ssamip_print(netdissect_options *ndo,
541146778Ssam	 const u_char *bp,
542146778Ssam	 u_int length)
54317680Spst{
544146778Ssam	struct ip_print_demux_state  ipd;
545146778Ssam	struct ip_print_demux_state *ipds=&ipd;
546127675Sbms	const u_char *ipend;
547146778Ssam	u_int hlen;
548235530Sdelphij	struct cksum_vec vec[1];
549276788Sdelphij	uint16_t sum, ip_sum;
550327234Semaste	const char *p_name;
55117680Spst
552146778Ssam	ipds->ip = (const struct ip *)bp;
553277783Spfg	ND_TCHECK(ipds->ip->ip_vhl);
554313537Sglebius	if (IP_V(ipds->ip) != 4) { /* print version and fail if != 4 */
555146778Ssam	    if (IP_V(ipds->ip) == 6)
556285275Spkelsey	      ND_PRINT((ndo, "IP6, wrong link-layer encapsulation "));
557285275Spkelsey	    else
558285275Spkelsey	      ND_PRINT((ndo, "IP%u ", IP_V(ipds->ip)));
559313537Sglebius	    return;
560127675Sbms	}
561313537Sglebius	if (!ndo->ndo_eflag)
562276788Sdelphij		ND_PRINT((ndo, "IP "));
56317680Spst
564277783Spfg	ND_TCHECK(*ipds->ip);
56517680Spst	if (length < sizeof (struct ip)) {
566276788Sdelphij		ND_PRINT((ndo, "truncated-ip %u", length));
56717680Spst		return;
56817680Spst	}
569146778Ssam	hlen = IP_HL(ipds->ip) * 4;
57075118Sfenner	if (hlen < sizeof (struct ip)) {
571276788Sdelphij		ND_PRINT((ndo, "bad-hlen %u", hlen));
57275118Sfenner		return;
57375118Sfenner	}
57417680Spst
575146778Ssam	ipds->len = EXTRACT_16BITS(&ipds->ip->ip_len);
576146778Ssam	if (length < ipds->len)
577276788Sdelphij		ND_PRINT((ndo, "truncated-ip - %u bytes missing! ",
578276788Sdelphij			ipds->len - length));
579146778Ssam	if (ipds->len < hlen) {
580146778Ssam#ifdef GUESS_TSO
581146778Ssam            if (ipds->len) {
582276788Sdelphij                ND_PRINT((ndo, "bad-len %u", ipds->len));
583146778Ssam                return;
584146778Ssam            }
585146778Ssam            else {
586146778Ssam                /* we guess that it is a TSO send */
587146778Ssam                ipds->len = length;
588146778Ssam            }
589146778Ssam#else
590276788Sdelphij            ND_PRINT((ndo, "bad-len %u", ipds->len));
591146778Ssam            return;
592146778Ssam#endif /* GUESS_TSO */
593127675Sbms	}
594127675Sbms
595127675Sbms	/*
596127675Sbms	 * Cut off the snapshot length to the end of the IP payload.
597127675Sbms	 */
598146778Ssam	ipend = bp + ipds->len;
599235530Sdelphij	if (ipend < ndo->ndo_snapend)
600235530Sdelphij		ndo->ndo_snapend = ipend;
601127675Sbms
602146778Ssam	ipds->len -= hlen;
60317680Spst
604146778Ssam	ipds->off = EXTRACT_16BITS(&ipds->ip->ip_off);
605127675Sbms
606276788Sdelphij        if (ndo->ndo_vflag) {
607276788Sdelphij            ND_PRINT((ndo, "(tos 0x%x", (int)ipds->ip->ip_tos));
608127675Sbms            /* ECN bits */
609313537Sglebius            switch (ipds->ip->ip_tos & 0x03) {
610313537Sglebius
611313537Sglebius            case 0:
612313537Sglebius                break;
613313537Sglebius
614313537Sglebius            case 1:
615313537Sglebius                ND_PRINT((ndo, ",ECT(1)"));
616313537Sglebius                break;
617313537Sglebius
618313537Sglebius            case 2:
619313537Sglebius                ND_PRINT((ndo, ",ECT(0)"));
620313537Sglebius                break;
621313537Sglebius
622313537Sglebius            case 3:
623313537Sglebius                ND_PRINT((ndo, ",CE"));
624313537Sglebius                break;
625127675Sbms            }
626127675Sbms
627146778Ssam            if (ipds->ip->ip_ttl >= 1)
628276788Sdelphij                ND_PRINT((ndo, ", ttl %u", ipds->ip->ip_ttl));
629127675Sbms
630127675Sbms	    /*
631127675Sbms	     * for the firewall guys, print id, offset.
632127675Sbms             * On all but the last stick a "+" in the flags portion.
633127675Sbms	     * For unfragmented datagrams, note the don't fragment flag.
634127675Sbms	     */
635127675Sbms
636276788Sdelphij	    ND_PRINT((ndo, ", id %u, offset %u, flags [%s], proto %s (%u)",
637146778Ssam                         EXTRACT_16BITS(&ipds->ip->ip_id),
638146778Ssam                         (ipds->off & 0x1fff) * 8,
639172686Smlaier                         bittok2str(ip_frag_values, "none", ipds->off&0xe000),
640146778Ssam                         tok2str(ipproto_values,"unknown",ipds->ip->ip_p),
641276788Sdelphij                         ipds->ip->ip_p));
642127675Sbms
643276788Sdelphij            ND_PRINT((ndo, ", length %u", EXTRACT_16BITS(&ipds->ip->ip_len)));
644127675Sbms
645127675Sbms            if ((hlen - sizeof(struct ip)) > 0) {
646276788Sdelphij                ND_PRINT((ndo, ", options ("));
647313537Sglebius                ip_optprint(ndo, (const u_char *)(ipds->ip + 1), hlen - sizeof(struct ip));
648276788Sdelphij                ND_PRINT((ndo, ")"));
649127675Sbms            }
650127675Sbms
651313537Sglebius	    if (!ndo->ndo_Kflag && (const u_char *)ipds->ip + hlen <= ndo->ndo_snapend) {
652313537Sglebius	        vec[0].ptr = (const uint8_t *)(const void *)ipds->ip;
653235530Sdelphij	        vec[0].len = hlen;
654235530Sdelphij	        sum = in_cksum(vec, 1);
655127675Sbms		if (sum != 0) {
656146778Ssam		    ip_sum = EXTRACT_16BITS(&ipds->ip->ip_sum);
657276788Sdelphij		    ND_PRINT((ndo, ", bad cksum %x (->%x)!", ip_sum,
658276788Sdelphij			     in_cksum_shouldbe(ip_sum, sum)));
659127675Sbms		}
660127675Sbms	    }
661127675Sbms
662276788Sdelphij		ND_PRINT((ndo, ")\n    "));
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) {
675276788Sdelphij			ND_PRINT((ndo, "%s > %s: ",
676276788Sdelphij				     ipaddr_string(ndo, &ipds->ip->ip_src),
677276788Sdelphij				     ipaddr_string(ndo, &ipds->ip->ip_dst)));
67856896Sfenner		}
679146778Ssam		ip_print_demux(ndo, ipds);
680127675Sbms	} else {
681313537Sglebius		/*
682313537Sglebius		 * Ultra quiet now means that all this stuff should be
683313537Sglebius		 * suppressed.
684313537Sglebius		 */
685313537Sglebius		if (ndo->ndo_qflag > 1)
686313537Sglebius			return;
68756896Sfenner
688313537Sglebius		/*
689313537Sglebius		 * This isn't the first frag, so we're missing the
690313537Sglebius		 * next level protocol header.  print the ip addr
691313537Sglebius		 * and the protocol.
692313537Sglebius		 */
693313537Sglebius		ND_PRINT((ndo, "%s > %s:", ipaddr_string(ndo, &ipds->ip->ip_src),
694313537Sglebius		          ipaddr_string(ndo, &ipds->ip->ip_dst)));
695327234Semaste		if (!ndo->ndo_nflag && (p_name = netdb_protoname(ipds->ip->ip_p)) != NULL)
696327234Semaste			ND_PRINT((ndo, " %s", p_name));
697313537Sglebius		else
698313537Sglebius			ND_PRINT((ndo, " ip-proto-%d", ipds->ip->ip_p));
69956896Sfenner	}
700277783Spfg	return;
701277783Spfg
702277783Spfgtrunc:
703277783Spfg	ND_PRINT((ndo, "%s", tstr));
704277783Spfg	return;
70517680Spst}
70675118Sfenner
70775118Sfennervoid
708276788SdelphijipN_print(netdissect_options *ndo, register const u_char *bp, register u_int length)
70975118Sfenner{
710313537Sglebius	if (length < 1) {
711276788Sdelphij		ND_PRINT((ndo, "truncated-ip %d", length));
71275118Sfenner		return;
71375118Sfenner	}
714313537Sglebius
715313537Sglebius	ND_TCHECK(*bp);
716313537Sglebius	switch (*bp & 0xF0) {
717313537Sglebius	case 0x40:
718276788Sdelphij		ip_print (ndo, bp, length);
719313537Sglebius		break;
720313537Sglebius	case 0x60:
721276788Sdelphij		ip6_print (ndo, bp, length);
722313537Sglebius		break;
72375118Sfenner	default:
724313537Sglebius		ND_PRINT((ndo, "unknown ip %d", (*bp & 0xF0) >> 4));
725313537Sglebius		break;
72675118Sfenner	}
727313537Sglebius	return;
728313537Sglebius
729313537Sglebiustrunc:
730313537Sglebius	ND_PRINT((ndo, "%s", tstr));
731313537Sglebius	return;
73275118Sfenner}
733127675Sbms
734146778Ssam/*
735146778Ssam * Local Variables:
736146778Ssam * c-style: whitesmith
737146778Ssam * c-basic-offset: 8
738146778Ssam * End:
739146778Ssam */
740127675Sbms
741127675Sbms
742