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