1 /*
2  * Copyright (C) 2002 WIDE Project.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the project nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33 
34 #include <sys/cdefs.h>
35 #ifndef lint
36 #if 0
37 static const char rcsid[] _U_ =
38      "@(#) Header: /tcpdump/master/tcpdump/print-mobility.c,v 1.12 2005-04-20 22:21:00 guy Exp";
39 #else
40 __RCSID("$NetBSD: print-mobility.c,v 1.2 2010/12/05 05:11:30 christos Exp $");
41 #endif
42 #endif
43 
44 #ifdef INET6
45 #include <tcpdump-stdinc.h>
46 
47 #include <stdio.h>
48 
49 #include "ip6.h"
50 
51 #include "interface.h"
52 #include "addrtoname.h"
53 #include "extract.h"		/* must come after interface.h */
54 
55 /* Mobility header */
56 struct ip6_mobility {
57 	u_int8_t ip6m_pproto;	/* following payload protocol (for PG) */
58 	u_int8_t ip6m_len;	/* length in units of 8 octets */
59 	u_int8_t ip6m_type;	/* message type */
60 	u_int8_t reserved;	/* reserved */
61 	u_int16_t ip6m_cksum;	/* sum of IPv6 pseudo-header and MH */
62 	union {
63 		u_int16_t	ip6m_un_data16[1]; /* type-specific field */
64 		u_int8_t	ip6m_un_data8[2];  /* type-specific fiedl */
65 	} ip6m_dataun;
66 };
67 
68 #define ip6m_data16	ip6m_dataun.ip6m_un_data16
69 #define ip6m_data8	ip6m_dataun.ip6m_un_data8
70 
71 #define IP6M_MINLEN	8
72 
73 /* message type */
74 #define IP6M_BINDING_REQUEST	0	/* Binding Refresh Request */
75 #define IP6M_HOME_TEST_INIT	1	/* Home Test Init */
76 #define IP6M_CAREOF_TEST_INIT	2	/* Care-of Test Init */
77 #define IP6M_HOME_TEST		3	/* Home Test */
78 #define IP6M_CAREOF_TEST	4	/* Care-of Test */
79 #define IP6M_BINDING_UPDATE	5	/* Binding Update */
80 #define IP6M_BINDING_ACK	6	/* Binding Acknowledgement */
81 #define IP6M_BINDING_ERROR	7	/* Binding Error */
82 
83 /* Mobility Header Options */
84 #define IP6MOPT_MINLEN		2
85 #define IP6MOPT_PAD1          0x0	/* Pad1 */
86 #define IP6MOPT_PADN          0x1	/* PadN */
87 #define IP6MOPT_REFRESH	      0x2	/* Binding Refresh Advice */
88 #define IP6MOPT_REFRESH_MINLEN  4
89 #define IP6MOPT_ALTCOA        0x3	/* Alternate Care-of Address */
90 #define IP6MOPT_ALTCOA_MINLEN  18
91 #define IP6MOPT_NONCEID       0x4	/* Nonce Indices */
92 #define IP6MOPT_NONCEID_MINLEN  6
93 #define IP6MOPT_AUTH          0x5	/* Binding Authorization Data */
94 #define IP6MOPT_AUTH_MINLEN    12
95 
96 static void
97 mobility_opt_print(const u_char *bp, int len)
98 {
99 	int i;
100 	int optlen;
101 
102 	for (i = 0; i < len; i += optlen) {
103 		if (bp[i] == IP6MOPT_PAD1)
104 			optlen = 1;
105 		else {
106 			if (i + 1 < len)
107 				optlen = bp[i + 1] + 2;
108 			else
109 				goto trunc;
110 		}
111 		if (i + optlen > len)
112 			goto trunc;
113 
114 		switch (bp[i]) {
115 		case IP6MOPT_PAD1:
116 			printf("(pad1)");
117 			break;
118 		case IP6MOPT_PADN:
119 			if (len - i < IP6MOPT_MINLEN) {
120 				printf("(padn: trunc)");
121 				goto trunc;
122 			}
123 			printf("(padn)");
124 			break;
125 		case IP6MOPT_REFRESH:
126 			if (len - i < IP6MOPT_REFRESH_MINLEN) {
127 				printf("(refresh: trunc)");
128 				goto trunc;
129 			}
130 			/* units of 4 secs */
131 			printf("(refresh: %d)",
132 				EXTRACT_16BITS(&bp[i+2]) << 2);
133 			break;
134 		case IP6MOPT_ALTCOA:
135 			if (len - i < IP6MOPT_ALTCOA_MINLEN) {
136 				printf("(altcoa: trunc)");
137 				goto trunc;
138 			}
139 			printf("(alt-CoA: %s)", ip6addr_string(&bp[i+2]));
140 			break;
141 		case IP6MOPT_NONCEID:
142 			if (len - i < IP6MOPT_NONCEID_MINLEN) {
143 				printf("(ni: trunc)");
144 				goto trunc;
145 			}
146 			printf("(ni: ho=0x%04x co=0x%04x)",
147 				EXTRACT_16BITS(&bp[i+2]),
148 				EXTRACT_16BITS(&bp[i+4]));
149 			break;
150 		case IP6MOPT_AUTH:
151 			if (len - i < IP6MOPT_AUTH_MINLEN) {
152 				printf("(auth: trunc)");
153 				goto trunc;
154 			}
155 			printf("(auth)");
156 			break;
157 		default:
158 			if (len - i < IP6MOPT_MINLEN) {
159 				printf("(sopt_type %d: trunc)", bp[i]);
160 				goto trunc;
161 			}
162 			printf("(type-0x%02x: len=%d)", bp[i], bp[i + 1]);
163 			break;
164 		}
165 	}
166 	return;
167 
168 trunc:
169 	printf("[trunc] ");
170 }
171 
172 /*
173  * Mobility Header
174  */
175 int
176 mobility_print(const u_char *bp, const u_char *bp2 _U_)
177 {
178 	const struct ip6_mobility *mh;
179 	const u_char *ep;
180 	int mhlen, hlen, type;
181 
182 	mh = (struct ip6_mobility *)bp;
183 
184 	/* 'ep' points to the end of available data. */
185 	ep = snapend;
186 
187 	if (!TTEST(mh->ip6m_len)) {
188 		/*
189 		 * There's not enough captured data to include the
190 		 * mobility header length.
191 		 *
192 		 * Our caller expects us to return the length, however,
193 		 * so return a value that will run to the end of the
194 		 * captured data.
195 		 *
196 		 * XXX - "ip6_print()" doesn't do anything with the
197 		 * returned length, however, as it breaks out of the
198 		 * header-processing loop.
199 		 */
200 		mhlen = ep - bp;
201 		goto trunc;
202 	}
203 	mhlen = (int)((mh->ip6m_len + 1) << 3);
204 
205 	/* XXX ip6m_cksum */
206 
207 	TCHECK(mh->ip6m_type);
208 	type = mh->ip6m_type;
209 	switch (type) {
210 	case IP6M_BINDING_REQUEST:
211 		printf("mobility: BRR");
212 		hlen = IP6M_MINLEN;
213 		break;
214 	case IP6M_HOME_TEST_INIT:
215 	case IP6M_CAREOF_TEST_INIT:
216 		printf("mobility: %soTI",
217 			type == IP6M_HOME_TEST_INIT ? "H" : "C");
218 		hlen = IP6M_MINLEN;
219     		if (vflag) {
220 			TCHECK2(*mh, hlen + 8);
221 			printf(" %s Init Cookie=%08x:%08x",
222 			       type == IP6M_HOME_TEST_INIT ? "Home" : "Care-of",
223 			       EXTRACT_32BITS(&bp[hlen]),
224 			       EXTRACT_32BITS(&bp[hlen + 4]));
225 		}
226 		hlen += 8;
227 		break;
228 	case IP6M_HOME_TEST:
229 	case IP6M_CAREOF_TEST:
230 		printf("mobility: %soT",
231 			type == IP6M_HOME_TEST ? "H" : "C");
232 		TCHECK(mh->ip6m_data16[0]);
233 		printf(" nonce id=0x%x", EXTRACT_16BITS(&mh->ip6m_data16[0]));
234 		hlen = IP6M_MINLEN;
235     		if (vflag) {
236 			TCHECK2(*mh, hlen + 8);
237 			printf(" %s Init Cookie=%08x:%08x",
238 			       type == IP6M_HOME_TEST ? "Home" : "Care-of",
239 			       EXTRACT_32BITS(&bp[hlen]),
240 			       EXTRACT_32BITS(&bp[hlen + 4]));
241 		}
242 		hlen += 8;
243     		if (vflag) {
244 			TCHECK2(*mh, hlen + 8);
245 			printf(" %s Keygen Token=%08x:%08x",
246 			       type == IP6M_HOME_TEST ? "Home" : "Care-of",
247 			       EXTRACT_32BITS(&bp[hlen]),
248 			       EXTRACT_32BITS(&bp[hlen + 4]));
249 		}
250 		hlen += 8;
251 		break;
252 	case IP6M_BINDING_UPDATE:
253 		printf("mobility: BU");
254 		TCHECK(mh->ip6m_data16[0]);
255 		printf(" seq#=%d", EXTRACT_16BITS(&mh->ip6m_data16[0]));
256 		hlen = IP6M_MINLEN;
257 		TCHECK2(*mh, hlen + 1);
258 		if (bp[hlen] & 0xf0)
259 			printf(" ");
260 		if (bp[hlen] & 0x80)
261 			printf("A");
262 		if (bp[hlen] & 0x40)
263 			printf("H");
264 		if (bp[hlen] & 0x20)
265 			printf("L");
266 		if (bp[hlen] & 0x10)
267 			printf("K");
268 		/* Reserved (4bits) */
269 		hlen += 1;
270 		/* Reserved (8bits) */
271 		hlen += 1;
272 		TCHECK2(*mh, hlen + 2);
273 		/* units of 4 secs */
274 		printf(" lifetime=%d", EXTRACT_16BITS(&bp[hlen]) << 2);
275 		hlen += 2;
276 		break;
277 	case IP6M_BINDING_ACK:
278 		printf("mobility: BA");
279 		TCHECK(mh->ip6m_data8[0]);
280 		printf(" status=%d", mh->ip6m_data8[0]);
281 		if (mh->ip6m_data8[1] & 0x80)
282 			printf(" K");
283 		/* Reserved (7bits) */
284 		hlen = IP6M_MINLEN;
285 		TCHECK2(*mh, hlen + 2);
286 		printf(" seq#=%d", EXTRACT_16BITS(&bp[hlen]));
287 		hlen += 2;
288 		TCHECK2(*mh, hlen + 2);
289 		/* units of 4 secs */
290 		printf(" lifetime=%d", EXTRACT_16BITS(&bp[hlen]) << 2);
291 		hlen += 2;
292 		break;
293 	case IP6M_BINDING_ERROR:
294 		printf("mobility: BE");
295 		TCHECK(mh->ip6m_data8[0]);
296 		printf(" status=%d", mh->ip6m_data8[0]);
297 		/* Reserved */
298 		hlen = IP6M_MINLEN;
299 		TCHECK2(*mh, hlen + 16);
300 		printf(" homeaddr %s", ip6addr_string(&bp[hlen]));
301 		hlen += 16;
302 		break;
303 	default:
304 		printf("mobility: type-#%d len=%d", type, mh->ip6m_len);
305 		return(mhlen);
306 		break;
307 	}
308     	if (vflag)
309 		mobility_opt_print(&bp[hlen], mhlen - hlen);
310 
311 	return(mhlen);
312 
313  trunc:
314 	fputs("[|MOBILITY]", stdout);
315 	return(mhlen);
316 }
317 #endif /* INET6 */
318