1/*
2 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 */
21
22#ifndef lint
23static const char rcsid[] _U_ =
24    "@(#) $Header: /tcpdump/master/tcpdump/print-ip6.c,v 1.47.2.5 2007/09/21 07:07:52 hannes Exp $";
25#endif
26
27#ifdef HAVE_CONFIG_H
28#include "config.h"
29#endif
30
31#ifdef INET6
32
33#include <tcpdump-stdinc.h>
34
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38
39#include "interface.h"
40#include "addrtoname.h"
41#include "extract.h"
42
43#include "ip6.h"
44#include "ipproto.h"
45
46/*
47 * print an IP6 datagram.
48 */
49void
50ip6_print(register const u_char *bp, register u_int length)
51{
52	register const struct ip6_hdr *ip6;
53	register int advance;
54	u_int len;
55	const u_char *ipend;
56	register const u_char *cp;
57	register u_int payload_len;
58	int nh;
59	int fragmented = 0;
60	u_int flow;
61
62	ip6 = (const struct ip6_hdr *)bp;
63
64	TCHECK(*ip6);
65	if (length < sizeof (struct ip6_hdr)) {
66		(void)printf("truncated-ip6 %u", length);
67		return;
68	}
69
70        if (!eflag)
71            printf("IP6 ");
72
73	payload_len = EXTRACT_16BITS(&ip6->ip6_plen);
74	len = payload_len + sizeof(struct ip6_hdr);
75	if (length < len)
76		(void)printf("truncated-ip6 - %u bytes missing!",
77			len - length);
78
79        if (vflag) {
80            flow = EXTRACT_32BITS(&ip6->ip6_flow);
81            printf("(");
82#if 0
83            /* rfc1883 */
84            if (flow & 0x0f000000)
85		(void)printf("pri 0x%02x, ", (flow & 0x0f000000) >> 24);
86            if (flow & 0x00ffffff)
87		(void)printf("flowlabel 0x%06x, ", flow & 0x00ffffff);
88#else
89            /* RFC 2460 */
90            if (flow & 0x0ff00000)
91		(void)printf("class 0x%02x, ", (flow & 0x0ff00000) >> 20);
92            if (flow & 0x000fffff)
93		(void)printf("flowlabel 0x%05x, ", flow & 0x000fffff);
94#endif
95
96            (void)printf("hlim %u, next-header %s (%u) payload length: %u) ",
97                         ip6->ip6_hlim,
98                         tok2str(ipproto_values,"unknown",ip6->ip6_nxt),
99                         ip6->ip6_nxt,
100                         payload_len);
101        }
102
103	/*
104	 * Cut off the snapshot length to the end of the IP payload.
105	 */
106	ipend = bp + len;
107	if (ipend < snapend)
108		snapend = ipend;
109
110	cp = (const u_char *)ip6;
111	advance = sizeof(struct ip6_hdr);
112	nh = ip6->ip6_nxt;
113	while (cp < snapend && advance > 0) {
114		cp += advance;
115		len -= advance;
116
117		if (cp == (const u_char *)(ip6 + 1) &&
118		    nh != IPPROTO_TCP && nh != IPPROTO_UDP &&
119		    nh != IPPROTO_DCCP && nh != IPPROTO_SCTP) {
120			(void)printf("%s > %s: ", ip6addr_string(&ip6->ip6_src),
121				     ip6addr_string(&ip6->ip6_dst));
122		}
123
124		switch (nh) {
125		case IPPROTO_HOPOPTS:
126			advance = hbhopt_print(cp);
127			nh = *cp;
128			break;
129		case IPPROTO_DSTOPTS:
130			advance = dstopt_print(cp);
131			nh = *cp;
132			break;
133		case IPPROTO_FRAGMENT:
134			advance = frag6_print(cp, (const u_char *)ip6);
135			if (snapend <= cp + advance)
136				return;
137			nh = *cp;
138			fragmented = 1;
139			break;
140
141		case IPPROTO_MOBILITY_OLD:
142		case IPPROTO_MOBILITY:
143			/*
144			 * XXX - we don't use "advance"; the current
145			 * "Mobility Support in IPv6" draft
146			 * (draft-ietf-mobileip-ipv6-24) says that
147			 * the next header field in a mobility header
148			 * should be IPPROTO_NONE, but speaks of
149			 * the possiblity of a future extension in
150			 * which payload can be piggybacked atop a
151			 * mobility header.
152			 */
153			advance = mobility_print(cp, (const u_char *)ip6);
154			nh = *cp;
155			return;
156		case IPPROTO_ROUTING:
157			advance = rt6_print(cp, (const u_char *)ip6);
158			nh = *cp;
159			break;
160		case IPPROTO_SCTP:
161			sctp_print(cp, (const u_char *)ip6, len);
162			return;
163		case IPPROTO_DCCP:
164			dccp_print(cp, (const u_char *)ip6, len);
165			return;
166		case IPPROTO_TCP:
167			tcp_print(cp, len, (const u_char *)ip6, fragmented);
168			return;
169		case IPPROTO_UDP:
170			udp_print(cp, len, (const u_char *)ip6, fragmented);
171			return;
172		case IPPROTO_ICMPV6:
173			icmp6_print(cp, len, (const u_char *)ip6, fragmented);
174			return;
175		case IPPROTO_AH:
176			advance = ah_print(cp);
177			nh = *cp;
178			break;
179		case IPPROTO_ESP:
180		    {
181			int enh, padlen;
182			advance = esp_print(gndo, cp, len, (const u_char *)ip6, &enh, &padlen);
183			nh = enh & 0xff;
184			len -= padlen;
185			break;
186		    }
187		case IPPROTO_IPCOMP:
188		    {
189			int enh;
190			advance = ipcomp_print(cp, &enh);
191			nh = enh & 0xff;
192			break;
193		    }
194
195		case IPPROTO_PIM:
196			pim_print(cp, len);
197			return;
198
199		case IPPROTO_OSPF:
200			ospf6_print(cp, len);
201			return;
202
203		case IPPROTO_IPV6:
204			ip6_print(cp, len);
205			return;
206
207		case IPPROTO_IPV4:
208		        ip_print(gndo, cp, len);
209			return;
210
211                case IPPROTO_PGM:
212                        pgm_print(cp, len, (const u_char *)ip6);
213                        return;
214
215		case IPPROTO_GRE:
216			gre_print(cp, len);
217			return;
218
219		case IPPROTO_RSVP:
220			rsvp_print(cp, len);
221			return;
222
223		case IPPROTO_NONE:
224			(void)printf("no next header");
225			return;
226
227		default:
228			(void)printf("ip-proto-%d %d", nh, len);
229			return;
230		}
231	}
232
233	return;
234trunc:
235	(void)printf("[|ip6]");
236}
237
238#endif /* INET6 */
239