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#include <sys/cdefs.h>
23#ifndef lint
24#if 0
25static const char rcsid[] _U_ =
26    "@(#) Header: /tcpdump/master/tcpdump/print-ip6.c,v 1.52 2007-09-21 07:05:33 hannes Exp";
27#else
28__RCSID("$NetBSD: print-ip6.c,v 1.2 2010/12/05 05:11:30 christos Exp $");
29#endif
30#endif
31
32#ifdef HAVE_CONFIG_H
33#include "config.h"
34#endif
35
36#ifdef INET6
37
38#include <tcpdump-stdinc.h>
39
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43
44#include "netdissect.h"
45#include "interface.h"
46#include "addrtoname.h"
47#include "extract.h"
48
49#include "ip6.h"
50#include "ipproto.h"
51
52/*
53 * Compute a V6-style checksum by building a pseudoheader.
54 */
55int
56nextproto6_cksum(const struct ip6_hdr *ip6, const u_short *data,
57		 u_int len, u_int next_proto)
58{
59        size_t i;
60        u_int32_t sum = 0;
61	union ip6_pseudo_hdr phu;
62
63        /* pseudo-header */
64        memset(&phu, 0, sizeof(phu));
65        phu.ph.ph_src = ip6->ip6_src;
66        phu.ph.ph_dst = ip6->ip6_dst;
67        phu.ph.ph_len = htonl(len);
68        phu.ph.ph_nxt = next_proto;
69
70        for (i = 0; i < sizeof(phu.pa) / sizeof(phu.pa[0]); i++) {
71                sum += phu.pa[i];
72	}
73
74        return in_cksum(data, len, sum);
75}
76
77/*
78 * print an IP6 datagram.
79 */
80void
81ip6_print(register const u_char *bp, register u_int length)
82{
83	register const struct ip6_hdr *ip6;
84	register int advance;
85	u_int len;
86	const u_char *ipend;
87	register const u_char *cp;
88	register u_int payload_len;
89	int nh;
90	int fragmented = 0;
91	u_int flow;
92
93	ip6 = (const struct ip6_hdr *)bp;
94
95	TCHECK(*ip6);
96	if (length < sizeof (struct ip6_hdr)) {
97		(void)printf("truncated-ip6 %u", length);
98		return;
99	}
100
101        if (!eflag)
102            printf("IP6 ");
103
104	payload_len = EXTRACT_16BITS(&ip6->ip6_plen);
105	len = payload_len + sizeof(struct ip6_hdr);
106	if (length < len)
107		(void)printf("truncated-ip6 - %u bytes missing!",
108			len - length);
109
110        if (vflag) {
111            flow = EXTRACT_32BITS(&ip6->ip6_flow);
112            printf("(");
113#if 0
114            /* rfc1883 */
115            if (flow & 0x0f000000)
116		(void)printf("pri 0x%02x, ", (flow & 0x0f000000) >> 24);
117            if (flow & 0x00ffffff)
118		(void)printf("flowlabel 0x%06x, ", flow & 0x00ffffff);
119#else
120            /* RFC 2460 */
121            if (flow & 0x0ff00000)
122		(void)printf("class 0x%02x, ", (flow & 0x0ff00000) >> 20);
123            if (flow & 0x000fffff)
124		(void)printf("flowlabel 0x%05x, ", flow & 0x000fffff);
125#endif
126
127            (void)printf("hlim %u, next-header %s (%u) payload length: %u) ",
128                         ip6->ip6_hlim,
129                         tok2str(ipproto_values,"unknown",ip6->ip6_nxt),
130                         ip6->ip6_nxt,
131                         payload_len);
132        }
133
134	/*
135	 * Cut off the snapshot length to the end of the IP payload.
136	 */
137	ipend = bp + len;
138	if (ipend < snapend)
139		snapend = ipend;
140
141	cp = (const u_char *)ip6;
142	advance = sizeof(struct ip6_hdr);
143	nh = ip6->ip6_nxt;
144	while (cp < snapend && advance > 0) {
145		cp += advance;
146		len -= advance;
147
148		if (cp == (const u_char *)(ip6 + 1) &&
149		    nh != IPPROTO_TCP && nh != IPPROTO_UDP &&
150		    nh != IPPROTO_DCCP && nh != IPPROTO_SCTP) {
151			(void)printf("%s > %s: ", ip6addr_string(&ip6->ip6_src),
152				     ip6addr_string(&ip6->ip6_dst));
153		}
154
155		switch (nh) {
156		case IPPROTO_HOPOPTS:
157			advance = hbhopt_print(cp);
158			nh = *cp;
159			break;
160		case IPPROTO_DSTOPTS:
161			advance = dstopt_print(cp);
162			nh = *cp;
163			break;
164		case IPPROTO_FRAGMENT:
165			advance = frag6_print(cp, (const u_char *)ip6);
166			if (snapend <= cp + advance)
167				return;
168			nh = *cp;
169			fragmented = 1;
170			break;
171
172		case IPPROTO_MOBILITY_OLD:
173		case IPPROTO_MOBILITY:
174			/*
175			 * XXX - we don't use "advance"; the current
176			 * "Mobility Support in IPv6" draft
177			 * (draft-ietf-mobileip-ipv6-24) says that
178			 * the next header field in a mobility header
179			 * should be IPPROTO_NONE, but speaks of
180			 * the possiblity of a future extension in
181			 * which payload can be piggybacked atop a
182			 * mobility header.
183			 */
184			advance = mobility_print(cp, (const u_char *)ip6);
185			nh = *cp;
186			return;
187		case IPPROTO_ROUTING:
188			advance = rt6_print(cp, (const u_char *)ip6);
189			nh = *cp;
190			break;
191		case IPPROTO_SCTP:
192			sctp_print(cp, (const u_char *)ip6, len);
193			return;
194		case IPPROTO_DCCP:
195			dccp_print(cp, (const u_char *)ip6, len);
196			return;
197		case IPPROTO_TCP:
198			tcp_print(cp, len, (const u_char *)ip6, fragmented);
199			return;
200		case IPPROTO_UDP:
201			udp_print(cp, len, (const u_char *)ip6, fragmented);
202			return;
203		case IPPROTO_ICMPV6:
204			icmp6_print(gndo, cp, len, (const u_char *)ip6, fragmented);
205			return;
206		case IPPROTO_AH:
207			advance = ah_print(cp);
208			nh = *cp;
209			break;
210		case IPPROTO_ESP:
211		    {
212			int enh, padlen;
213			advance = esp_print(gndo, cp, len, (const u_char *)ip6, &enh, &padlen);
214			nh = enh & 0xff;
215			len -= padlen;
216			break;
217		    }
218		case IPPROTO_IPCOMP:
219		    {
220			int enh;
221			advance = ipcomp_print(cp, &enh);
222			nh = enh & 0xff;
223			break;
224		    }
225
226		case IPPROTO_PIM:
227			pim_print(cp, len, nextproto6_cksum(ip6, (u_short *)cp, len,
228							    IPPROTO_PIM));
229			return;
230
231		case IPPROTO_OSPF:
232			ospf6_print(cp, len);
233			return;
234
235		case IPPROTO_IPV6:
236			ip6_print(cp, len);
237			return;
238
239		case IPPROTO_IPV4:
240		        ip_print(gndo, cp, len);
241			return;
242
243                case IPPROTO_PGM:
244                        pgm_print(cp, len, (const u_char *)ip6);
245                        return;
246
247		case IPPROTO_GRE:
248			gre_print(cp, len);
249			return;
250
251		case IPPROTO_RSVP:
252			rsvp_print(cp, len);
253			return;
254
255		case IPPROTO_NONE:
256			(void)printf("no next header");
257			return;
258
259		default:
260			(void)printf("ip-proto-%d %d", nh, len);
261			return;
262		}
263	}
264
265	return;
266trunc:
267	(void)printf("[|ip6]");
268}
269
270#endif /* INET6 */
271