1127668Sbms/*
2127668Sbms * Copyright (C) 2002 WIDE Project.
3127668Sbms * All rights reserved.
4127668Sbms *
5127668Sbms * Redistribution and use in source and binary forms, with or without
6127668Sbms * modification, are permitted provided that the following conditions
7127668Sbms * are met:
8127668Sbms * 1. Redistributions of source code must retain the above copyright
9127668Sbms *    notice, this list of conditions and the following disclaimer.
10127668Sbms * 2. Redistributions in binary form must reproduce the above copyright
11127668Sbms *    notice, this list of conditions and the following disclaimer in the
12127668Sbms *    documentation and/or other materials provided with the distribution.
13127668Sbms * 3. Neither the name of the project nor the names of its contributors
14127668Sbms *    may be used to endorse or promote products derived from this software
15127668Sbms *    without specific prior written permission.
16127668Sbms *
17127668Sbms * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18127668Sbms * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19127668Sbms * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20127668Sbms * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21127668Sbms * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22127668Sbms * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23127668Sbms * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24127668Sbms * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25127668Sbms * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26127668Sbms * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27127668Sbms * SUCH DAMAGE.
28127668Sbms */
29127668Sbms
30127668Sbms#ifdef HAVE_CONFIG_H
31127668Sbms#include "config.h"
32127668Sbms#endif
33127668Sbms
34127668Sbms#ifndef lint
35127668Sbmsstatic const char rcsid[] _U_ =
36190207Srpaulo     "@(#) $Header: /tcpdump/master/tcpdump/print-mobility.c,v 1.12 2005-04-20 22:21:00 guy Exp $";
37127668Sbms#endif
38127668Sbms
39127668Sbms#ifdef INET6
40127668Sbms#include <tcpdump-stdinc.h>
41127668Sbms
42127668Sbms#include <stdio.h>
43127668Sbms
44127668Sbms#include "ip6.h"
45127668Sbms
46127668Sbms#include "interface.h"
47127668Sbms#include "addrtoname.h"
48127668Sbms#include "extract.h"		/* must come after interface.h */
49127668Sbms
50127668Sbms/* Mobility header */
51127668Sbmsstruct ip6_mobility {
52127668Sbms	u_int8_t ip6m_pproto;	/* following payload protocol (for PG) */
53127668Sbms	u_int8_t ip6m_len;	/* length in units of 8 octets */
54127668Sbms	u_int8_t ip6m_type;	/* message type */
55127668Sbms	u_int8_t reserved;	/* reserved */
56127668Sbms	u_int16_t ip6m_cksum;	/* sum of IPv6 pseudo-header and MH */
57127668Sbms	union {
58127668Sbms		u_int16_t	ip6m_un_data16[1]; /* type-specific field */
59127668Sbms		u_int8_t	ip6m_un_data8[2];  /* type-specific fiedl */
60127668Sbms	} ip6m_dataun;
61127668Sbms};
62127668Sbms
63127668Sbms#define ip6m_data16	ip6m_dataun.ip6m_un_data16
64127668Sbms#define ip6m_data8	ip6m_dataun.ip6m_un_data8
65127668Sbms
66127668Sbms#define IP6M_MINLEN	8
67127668Sbms
68127668Sbms/* message type */
69127668Sbms#define IP6M_BINDING_REQUEST	0	/* Binding Refresh Request */
70127668Sbms#define IP6M_HOME_TEST_INIT	1	/* Home Test Init */
71127668Sbms#define IP6M_CAREOF_TEST_INIT	2	/* Care-of Test Init */
72127668Sbms#define IP6M_HOME_TEST		3	/* Home Test */
73127668Sbms#define IP6M_CAREOF_TEST	4	/* Care-of Test */
74127668Sbms#define IP6M_BINDING_UPDATE	5	/* Binding Update */
75127668Sbms#define IP6M_BINDING_ACK	6	/* Binding Acknowledgement */
76127668Sbms#define IP6M_BINDING_ERROR	7	/* Binding Error */
77127668Sbms
78127668Sbms/* Mobility Header Options */
79127668Sbms#define IP6MOPT_MINLEN		2
80127668Sbms#define IP6MOPT_PAD1          0x0	/* Pad1 */
81127668Sbms#define IP6MOPT_PADN          0x1	/* PadN */
82127668Sbms#define IP6MOPT_REFRESH	      0x2	/* Binding Refresh Advice */
83127668Sbms#define IP6MOPT_REFRESH_MINLEN  4
84127668Sbms#define IP6MOPT_ALTCOA        0x3	/* Alternate Care-of Address */
85127668Sbms#define IP6MOPT_ALTCOA_MINLEN  18
86127668Sbms#define IP6MOPT_NONCEID       0x4	/* Nonce Indices */
87127668Sbms#define IP6MOPT_NONCEID_MINLEN  6
88127668Sbms#define IP6MOPT_AUTH          0x5	/* Binding Authorization Data */
89127668Sbms#define IP6MOPT_AUTH_MINLEN    12
90127668Sbms
91127668Sbmsstatic void
92127668Sbmsmobility_opt_print(const u_char *bp, int len)
93127668Sbms{
94127668Sbms	int i;
95127668Sbms	int optlen;
96127668Sbms
97127668Sbms	for (i = 0; i < len; i += optlen) {
98127668Sbms		if (bp[i] == IP6MOPT_PAD1)
99127668Sbms			optlen = 1;
100127668Sbms		else {
101127668Sbms			if (i + 1 < len)
102127668Sbms				optlen = bp[i + 1] + 2;
103127668Sbms			else
104127668Sbms				goto trunc;
105127668Sbms		}
106127668Sbms		if (i + optlen > len)
107127668Sbms			goto trunc;
108127668Sbms
109127668Sbms		switch (bp[i]) {
110127668Sbms		case IP6MOPT_PAD1:
111127668Sbms			printf("(pad1)");
112127668Sbms			break;
113127668Sbms		case IP6MOPT_PADN:
114127668Sbms			if (len - i < IP6MOPT_MINLEN) {
115127668Sbms				printf("(padn: trunc)");
116127668Sbms				goto trunc;
117127668Sbms			}
118127668Sbms			printf("(padn)");
119127668Sbms			break;
120127668Sbms		case IP6MOPT_REFRESH:
121127668Sbms			if (len - i < IP6MOPT_REFRESH_MINLEN) {
122127668Sbms				printf("(refresh: trunc)");
123127668Sbms				goto trunc;
124127668Sbms			}
125127668Sbms			/* units of 4 secs */
126127668Sbms			printf("(refresh: %d)",
127127668Sbms				EXTRACT_16BITS(&bp[i+2]) << 2);
128127668Sbms			break;
129127668Sbms		case IP6MOPT_ALTCOA:
130127668Sbms			if (len - i < IP6MOPT_ALTCOA_MINLEN) {
131127668Sbms				printf("(altcoa: trunc)");
132127668Sbms				goto trunc;
133127668Sbms			}
134127668Sbms			printf("(alt-CoA: %s)", ip6addr_string(&bp[i+2]));
135127668Sbms			break;
136127668Sbms		case IP6MOPT_NONCEID:
137127668Sbms			if (len - i < IP6MOPT_NONCEID_MINLEN) {
138127668Sbms				printf("(ni: trunc)");
139127668Sbms				goto trunc;
140127668Sbms			}
141127668Sbms			printf("(ni: ho=0x%04x co=0x%04x)",
142127668Sbms				EXTRACT_16BITS(&bp[i+2]),
143127668Sbms				EXTRACT_16BITS(&bp[i+4]));
144127668Sbms			break;
145127668Sbms		case IP6MOPT_AUTH:
146127668Sbms			if (len - i < IP6MOPT_AUTH_MINLEN) {
147127668Sbms				printf("(auth: trunc)");
148127668Sbms				goto trunc;
149127668Sbms			}
150127668Sbms			printf("(auth)");
151127668Sbms			break;
152127668Sbms		default:
153127668Sbms			if (len - i < IP6MOPT_MINLEN) {
154127668Sbms				printf("(sopt_type %d: trunc)", bp[i]);
155127668Sbms				goto trunc;
156127668Sbms			}
157127668Sbms			printf("(type-0x%02x: len=%d)", bp[i], bp[i + 1]);
158127668Sbms			break;
159127668Sbms		}
160127668Sbms	}
161127668Sbms	return;
162127668Sbms
163127668Sbmstrunc:
164127668Sbms	printf("[trunc] ");
165127668Sbms}
166127668Sbms
167127668Sbms/*
168127668Sbms * Mobility Header
169127668Sbms */
170127668Sbmsint
171147899Ssammobility_print(const u_char *bp, const u_char *bp2 _U_)
172127668Sbms{
173127668Sbms	const struct ip6_mobility *mh;
174127668Sbms	const u_char *ep;
175127668Sbms	int mhlen, hlen, type;
176127668Sbms
177127668Sbms	mh = (struct ip6_mobility *)bp;
178127668Sbms
179127668Sbms	/* 'ep' points to the end of available data. */
180127668Sbms	ep = snapend;
181127668Sbms
182127668Sbms	if (!TTEST(mh->ip6m_len)) {
183127668Sbms		/*
184127668Sbms		 * There's not enough captured data to include the
185127668Sbms		 * mobility header length.
186127668Sbms		 *
187127668Sbms		 * Our caller expects us to return the length, however,
188127668Sbms		 * so return a value that will run to the end of the
189127668Sbms		 * captured data.
190127668Sbms		 *
191127668Sbms		 * XXX - "ip6_print()" doesn't do anything with the
192127668Sbms		 * returned length, however, as it breaks out of the
193127668Sbms		 * header-processing loop.
194127668Sbms		 */
195127668Sbms		mhlen = ep - bp;
196127668Sbms		goto trunc;
197127668Sbms	}
198127668Sbms	mhlen = (int)((mh->ip6m_len + 1) << 3);
199127668Sbms
200127668Sbms	/* XXX ip6m_cksum */
201127668Sbms
202127668Sbms	TCHECK(mh->ip6m_type);
203127668Sbms	type = mh->ip6m_type;
204127668Sbms	switch (type) {
205127668Sbms	case IP6M_BINDING_REQUEST:
206127668Sbms		printf("mobility: BRR");
207127668Sbms		hlen = IP6M_MINLEN;
208127668Sbms		break;
209127668Sbms	case IP6M_HOME_TEST_INIT:
210127668Sbms	case IP6M_CAREOF_TEST_INIT:
211127668Sbms		printf("mobility: %soTI",
212127668Sbms			type == IP6M_HOME_TEST_INIT ? "H" : "C");
213127668Sbms		hlen = IP6M_MINLEN;
214127668Sbms    		if (vflag) {
215127668Sbms			TCHECK2(*mh, hlen + 8);
216127668Sbms			printf(" %s Init Cookie=%08x:%08x",
217127668Sbms			       type == IP6M_HOME_TEST_INIT ? "Home" : "Care-of",
218127668Sbms			       EXTRACT_32BITS(&bp[hlen]),
219127668Sbms			       EXTRACT_32BITS(&bp[hlen + 4]));
220127668Sbms		}
221127668Sbms		hlen += 8;
222127668Sbms		break;
223127668Sbms	case IP6M_HOME_TEST:
224127668Sbms	case IP6M_CAREOF_TEST:
225127668Sbms		printf("mobility: %soT",
226127668Sbms			type == IP6M_HOME_TEST ? "H" : "C");
227127668Sbms		TCHECK(mh->ip6m_data16[0]);
228127668Sbms		printf(" nonce id=0x%x", EXTRACT_16BITS(&mh->ip6m_data16[0]));
229127668Sbms		hlen = IP6M_MINLEN;
230127668Sbms    		if (vflag) {
231127668Sbms			TCHECK2(*mh, hlen + 8);
232127668Sbms			printf(" %s Init Cookie=%08x:%08x",
233127668Sbms			       type == IP6M_HOME_TEST ? "Home" : "Care-of",
234127668Sbms			       EXTRACT_32BITS(&bp[hlen]),
235127668Sbms			       EXTRACT_32BITS(&bp[hlen + 4]));
236127668Sbms		}
237127668Sbms		hlen += 8;
238127668Sbms    		if (vflag) {
239127668Sbms			TCHECK2(*mh, hlen + 8);
240127668Sbms			printf(" %s Keygen Token=%08x:%08x",
241127668Sbms			       type == IP6M_HOME_TEST ? "Home" : "Care-of",
242127668Sbms			       EXTRACT_32BITS(&bp[hlen]),
243127668Sbms			       EXTRACT_32BITS(&bp[hlen + 4]));
244127668Sbms		}
245127668Sbms		hlen += 8;
246127668Sbms		break;
247127668Sbms	case IP6M_BINDING_UPDATE:
248127668Sbms		printf("mobility: BU");
249127668Sbms		TCHECK(mh->ip6m_data16[0]);
250127668Sbms		printf(" seq#=%d", EXTRACT_16BITS(&mh->ip6m_data16[0]));
251127668Sbms		hlen = IP6M_MINLEN;
252127668Sbms		TCHECK2(*mh, hlen + 1);
253127668Sbms		if (bp[hlen] & 0xf0)
254127668Sbms			printf(" ");
255127668Sbms		if (bp[hlen] & 0x80)
256127668Sbms			printf("A");
257127668Sbms		if (bp[hlen] & 0x40)
258127668Sbms			printf("H");
259127668Sbms		if (bp[hlen] & 0x20)
260127668Sbms			printf("L");
261127668Sbms		if (bp[hlen] & 0x10)
262127668Sbms			printf("K");
263127668Sbms		/* Reserved (4bits) */
264127668Sbms		hlen += 1;
265127668Sbms		/* Reserved (8bits) */
266127668Sbms		hlen += 1;
267127668Sbms		TCHECK2(*mh, hlen + 2);
268127668Sbms		/* units of 4 secs */
269127668Sbms		printf(" lifetime=%d", EXTRACT_16BITS(&bp[hlen]) << 2);
270127668Sbms		hlen += 2;
271127668Sbms		break;
272127668Sbms	case IP6M_BINDING_ACK:
273127668Sbms		printf("mobility: BA");
274127668Sbms		TCHECK(mh->ip6m_data8[0]);
275127668Sbms		printf(" status=%d", mh->ip6m_data8[0]);
276127668Sbms		if (mh->ip6m_data8[1] & 0x80)
277127668Sbms			printf(" K");
278127668Sbms		/* Reserved (7bits) */
279127668Sbms		hlen = IP6M_MINLEN;
280127668Sbms		TCHECK2(*mh, hlen + 2);
281127668Sbms		printf(" seq#=%d", EXTRACT_16BITS(&bp[hlen]));
282127668Sbms		hlen += 2;
283127668Sbms		TCHECK2(*mh, hlen + 2);
284127668Sbms		/* units of 4 secs */
285127668Sbms		printf(" lifetime=%d", EXTRACT_16BITS(&bp[hlen]) << 2);
286127668Sbms		hlen += 2;
287127668Sbms		break;
288127668Sbms	case IP6M_BINDING_ERROR:
289127668Sbms		printf("mobility: BE");
290127668Sbms		TCHECK(mh->ip6m_data8[0]);
291127668Sbms		printf(" status=%d", mh->ip6m_data8[0]);
292127668Sbms		/* Reserved */
293127668Sbms		hlen = IP6M_MINLEN;
294127668Sbms		TCHECK2(*mh, hlen + 16);
295127668Sbms		printf(" homeaddr %s", ip6addr_string(&bp[hlen]));
296127668Sbms		hlen += 16;
297127668Sbms		break;
298127668Sbms	default:
299127668Sbms		printf("mobility: type-#%d len=%d", type, mh->ip6m_len);
300127668Sbms		return(mhlen);
301127668Sbms		break;
302127668Sbms	}
303127668Sbms    	if (vflag)
304127668Sbms		mobility_opt_print(&bp[hlen], mhlen - hlen);
305127668Sbms
306127668Sbms	return(mhlen);
307127668Sbms
308127668Sbms trunc:
309127668Sbms	fputs("[|MOBILITY]", stdout);
310127668Sbms	return(mhlen);
311127668Sbms}
312127668Sbms#endif /* INET6 */
313