xref: /netbsd/external/bsd/tcpdump/dist/print-aodv.c (revision 6550d01e)
1 /*
2  * Copyright (c) 2003 Bruce M. Simpson <bms@spc.org>
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. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *        This product includes software developed by Bruce M. Simpson.
16  * 4. Neither the name of Bruce M. Simpson nor the names of co-
17  *    contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY Bruce M. Simpson AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL Bruce M. Simpson OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/cdefs.h>
34 #ifndef lint
35 #if 0
36 static const char rcsid[] _U_ =
37     "@(#) Header: /tcpdump/master/tcpdump/print-aodv.c,v 1.11 2004-03-24 00:30:19 guy Exp (LBL)";
38 #else
39 __RCSID("$NetBSD: print-aodv.c,v 1.2 2010/12/05 05:11:30 christos Exp $");
40 #endif
41 #endif
42 
43 #ifdef HAVE_CONFIG_H
44 #include "config.h"
45 #endif
46 
47 #include <tcpdump-stdinc.h>
48 
49 #include <stddef.h>
50 #include <stdio.h>
51 #include <ctype.h>
52 #include <string.h>
53 
54 #include "interface.h"
55 #include "addrtoname.h"
56 #include "extract.h"			/* must come after interface.h */
57 
58 #include "aodv.h"
59 
60 static void
61 aodv_extension(const struct aodv_ext *ep, u_int length)
62 {
63 	u_int i;
64 	const struct aodv_hello *ah;
65 
66 	switch (ep->type) {
67 	case AODV_EXT_HELLO:
68 		if (snapend < (u_char *) ep) {
69 			printf(" [|hello]");
70 			return;
71 		}
72 		i = min(length, (u_int)(snapend - (u_char *)ep));
73 		if (i < sizeof(struct aodv_hello)) {
74 			printf(" [|hello]");
75 			return;
76 		}
77 		i -= sizeof(struct aodv_hello);
78 		ah = (void *)ep;
79 		printf("\n\text HELLO %ld ms",
80 		    (unsigned long)EXTRACT_32BITS(&ah->interval));
81 		break;
82 
83 	default:
84 		printf("\n\text %u %u", ep->type, ep->length);
85 		break;
86 	}
87 }
88 
89 static void
90 aodv_rreq(const union aodv *ap, const u_char *dat, u_int length)
91 {
92 	u_int i;
93 
94 	if (snapend < dat) {
95 		printf(" [|aodv]");
96 		return;
97 	}
98 	i = min(length, (u_int)(snapend - dat));
99 	if (i < sizeof(ap->rreq)) {
100 		printf(" [|rreq]");
101 		return;
102 	}
103 	i -= sizeof(ap->rreq);
104 	printf(" rreq %u %s%s%s%s%shops %u id 0x%08lx\n"
105 	    "\tdst %s seq %lu src %s seq %lu", length,
106 	    ap->rreq.rreq_type & RREQ_JOIN ? "[J]" : "",
107 	    ap->rreq.rreq_type & RREQ_REPAIR ? "[R]" : "",
108 	    ap->rreq.rreq_type & RREQ_GRAT ? "[G]" : "",
109 	    ap->rreq.rreq_type & RREQ_DEST ? "[D]" : "",
110 	    ap->rreq.rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
111 	    ap->rreq.rreq_hops,
112 	    (unsigned long)EXTRACT_32BITS(&ap->rreq.rreq_id),
113 	    ipaddr_string(&ap->rreq.rreq_da),
114 	    (unsigned long)EXTRACT_32BITS(&ap->rreq.rreq_ds),
115 	    ipaddr_string(&ap->rreq.rreq_oa),
116 	    (unsigned long)EXTRACT_32BITS(&ap->rreq.rreq_os));
117 	if (i >= sizeof(struct aodv_ext))
118 		aodv_extension((void *)(&ap->rreq + 1), i);
119 }
120 
121 static void
122 aodv_rrep(const union aodv *ap, const u_char *dat, u_int length)
123 {
124 	u_int i;
125 
126 	if (snapend < dat) {
127 		printf(" [|aodv]");
128 		return;
129 	}
130 	i = min(length, (u_int)(snapend - dat));
131 	if (i < sizeof(ap->rrep)) {
132 		printf(" [|rrep]");
133 		return;
134 	}
135 	i -= sizeof(ap->rrep);
136 	printf(" rrep %u %s%sprefix %u hops %u\n"
137 	    "\tdst %s dseq %lu src %s %lu ms", length,
138 	    ap->rrep.rrep_type & RREP_REPAIR ? "[R]" : "",
139 	    ap->rrep.rrep_type & RREP_ACK ? "[A] " : " ",
140 	    ap->rrep.rrep_ps & RREP_PREFIX_MASK,
141 	    ap->rrep.rrep_hops,
142 	    ipaddr_string(&ap->rrep.rrep_da),
143 	    (unsigned long)EXTRACT_32BITS(&ap->rrep.rrep_ds),
144 	    ipaddr_string(&ap->rrep.rrep_oa),
145 	    (unsigned long)EXTRACT_32BITS(&ap->rrep.rrep_life));
146 	if (i >= sizeof(struct aodv_ext))
147 		aodv_extension((void *)(&ap->rrep + 1), i);
148 }
149 
150 static void
151 aodv_rerr(const union aodv *ap, const u_char *dat, u_int length)
152 {
153 	u_int i;
154 	const struct rerr_unreach *dp = NULL;
155 	int n, trunc;
156 
157 	if (snapend < dat) {
158 		printf(" [|aodv]");
159 		return;
160 	}
161 	i = min(length, (u_int)(snapend - dat));
162 	if (i < offsetof(struct aodv_rerr, r)) {
163 		printf(" [|rerr]");
164 		return;
165 	}
166 	i -= offsetof(struct aodv_rerr, r);
167 	dp = &ap->rerr.r.dest[0];
168 	n = ap->rerr.rerr_dc * sizeof(ap->rerr.r.dest[0]);
169 	printf(" rerr %s [items %u] [%u]:",
170 	    ap->rerr.rerr_flags & RERR_NODELETE ? "[D]" : "",
171 	    ap->rerr.rerr_dc, length);
172 	trunc = n - (i/sizeof(ap->rerr.r.dest[0]));
173 	for (; i >= sizeof(ap->rerr.r.dest[0]);
174 	    ++dp, i -= sizeof(ap->rerr.r.dest[0])) {
175 		printf(" {%s}(%ld)", ipaddr_string(&dp->u_da),
176 		    (unsigned long)EXTRACT_32BITS(&dp->u_ds));
177 	}
178 	if (trunc)
179 		printf("[|rerr]");
180 }
181 
182 static void
183 #ifdef INET6
184 aodv_v6_rreq(const union aodv *ap, const u_char *dat, u_int length)
185 #else
186 aodv_v6_rreq(const union aodv *ap _U_, const u_char *dat _U_, u_int length)
187 #endif
188 {
189 #ifdef INET6
190 	u_int i;
191 
192 	if (snapend < dat) {
193 		printf(" [|aodv]");
194 		return;
195 	}
196 	i = min(length, (u_int)(snapend - dat));
197 	if (i < sizeof(ap->rreq6)) {
198 		printf(" [|rreq6]");
199 		return;
200 	}
201 	i -= sizeof(ap->rreq6);
202 	printf(" v6 rreq %u %s%s%s%s%shops %u id 0x%08lx\n"
203 	    "\tdst %s seq %lu src %s seq %lu", length,
204 	    ap->rreq6.rreq_type & RREQ_JOIN ? "[J]" : "",
205 	    ap->rreq6.rreq_type & RREQ_REPAIR ? "[R]" : "",
206 	    ap->rreq6.rreq_type & RREQ_GRAT ? "[G]" : "",
207 	    ap->rreq6.rreq_type & RREQ_DEST ? "[D]" : "",
208 	    ap->rreq6.rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
209 	    ap->rreq6.rreq_hops,
210 	    (unsigned long)EXTRACT_32BITS(&ap->rreq6.rreq_id),
211 	    ip6addr_string(&ap->rreq6.rreq_da),
212 	    (unsigned long)EXTRACT_32BITS(&ap->rreq6.rreq_ds),
213 	    ip6addr_string(&ap->rreq6.rreq_oa),
214 	    (unsigned long)EXTRACT_32BITS(&ap->rreq6.rreq_os));
215 	if (i >= sizeof(struct aodv_ext))
216 		aodv_extension((void *)(&ap->rreq6 + 1), i);
217 #else
218 	printf(" v6 rreq %u", length);
219 #endif
220 }
221 
222 static void
223 #ifdef INET6
224 aodv_v6_rrep(const union aodv *ap, const u_char *dat, u_int length)
225 #else
226 aodv_v6_rrep(const union aodv *ap _U_, const u_char *dat _U_, u_int length)
227 #endif
228 {
229 #ifdef INET6
230 	u_int i;
231 
232 	if (snapend < dat) {
233 		printf(" [|aodv]");
234 		return;
235 	}
236 	i = min(length, (u_int)(snapend - dat));
237 	if (i < sizeof(ap->rrep6)) {
238 		printf(" [|rrep6]");
239 		return;
240 	}
241 	i -= sizeof(ap->rrep6);
242 	printf(" rrep %u %s%sprefix %u hops %u\n"
243 	   "\tdst %s dseq %lu src %s %lu ms", length,
244 	    ap->rrep6.rrep_type & RREP_REPAIR ? "[R]" : "",
245 	    ap->rrep6.rrep_type & RREP_ACK ? "[A] " : " ",
246 	    ap->rrep6.rrep_ps & RREP_PREFIX_MASK,
247 	    ap->rrep6.rrep_hops,
248 	    ip6addr_string(&ap->rrep6.rrep_da),
249 	    (unsigned long)EXTRACT_32BITS(&ap->rrep6.rrep_ds),
250 	    ip6addr_string(&ap->rrep6.rrep_oa),
251 	    (unsigned long)EXTRACT_32BITS(&ap->rrep6.rrep_life));
252 	if (i >= sizeof(struct aodv_ext))
253 		aodv_extension((void *)(&ap->rrep6 + 1), i);
254 #else
255 	printf(" rrep %u", length);
256 #endif
257 }
258 
259 static void
260 #ifdef INET6
261 aodv_v6_rerr(const union aodv *ap, u_int length)
262 #else
263 aodv_v6_rerr(const union aodv *ap _U_, u_int length)
264 #endif
265 {
266 #ifdef INET6
267 	const struct rerr_unreach6 *dp6 = NULL;
268 	int i, j, n, trunc;
269 
270 	i = length - offsetof(struct aodv_rerr, r);
271 	j = sizeof(ap->rerr.r.dest6[0]);
272 	dp6 = &ap->rerr.r.dest6[0];
273 	n = ap->rerr.rerr_dc * j;
274 	printf(" rerr %s [items %u] [%u]:",
275 	    ap->rerr.rerr_flags & RERR_NODELETE ? "[D]" : "",
276 	    ap->rerr.rerr_dc, length);
277 	trunc = n - (i/j);
278 	for (; i -= j >= 0; ++dp6) {
279 		printf(" {%s}(%ld)", ip6addr_string(&dp6->u_da),
280 		    (unsigned long)EXTRACT_32BITS(&dp6->u_ds));
281 	}
282 	if (trunc)
283 		printf("[|rerr]");
284 #else
285 	printf(" rerr %u", length);
286 #endif
287 }
288 
289 static void
290 #ifdef INET6
291 aodv_v6_draft_01_rreq(const union aodv *ap, const u_char *dat, u_int length)
292 #else
293 aodv_v6_draft_01_rreq(const union aodv *ap _U_, const u_char *dat _U_,
294     u_int length)
295 #endif
296 {
297 #ifdef INET6
298 	u_int i;
299 
300 	if (snapend < dat) {
301 		printf(" [|aodv]");
302 		return;
303 	}
304 	i = min(length, (u_int)(snapend - dat));
305 	if (i < sizeof(ap->rreq6_draft_01)) {
306 		printf(" [|rreq6]");
307 		return;
308 	}
309 	i -= sizeof(ap->rreq6_draft_01);
310 	printf(" rreq %u %s%s%s%s%shops %u id 0x%08lx\n"
311 	    "\tdst %s seq %lu src %s seq %lu", length,
312 	    ap->rreq6_draft_01.rreq_type & RREQ_JOIN ? "[J]" : "",
313 	    ap->rreq6_draft_01.rreq_type & RREQ_REPAIR ? "[R]" : "",
314 	    ap->rreq6_draft_01.rreq_type & RREQ_GRAT ? "[G]" : "",
315 	    ap->rreq6_draft_01.rreq_type & RREQ_DEST ? "[D]" : "",
316 	    ap->rreq6_draft_01.rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
317 	    ap->rreq6_draft_01.rreq_hops,
318 	    (unsigned long)EXTRACT_32BITS(&ap->rreq6_draft_01.rreq_id),
319 	    ip6addr_string(&ap->rreq6_draft_01.rreq_da),
320 	    (unsigned long)EXTRACT_32BITS(&ap->rreq6_draft_01.rreq_ds),
321 	    ip6addr_string(&ap->rreq6_draft_01.rreq_oa),
322 	    (unsigned long)EXTRACT_32BITS(&ap->rreq6_draft_01.rreq_os));
323 	if (i >= sizeof(struct aodv_ext))
324 		aodv_extension((void *)(&ap->rreq6_draft_01 + 1), i);
325 #else
326 	printf(" rreq %u", length);
327 #endif
328 }
329 
330 static void
331 #ifdef INET6
332 aodv_v6_draft_01_rrep(const union aodv *ap, const u_char *dat, u_int length)
333 #else
334 aodv_v6_draft_01_rrep(const union aodv *ap _U_, const u_char *dat _U_,
335     u_int length)
336 #endif
337 {
338 #ifdef INET6
339 	u_int i;
340 
341 	if (snapend < dat) {
342 		printf(" [|aodv]");
343 		return;
344 	}
345 	i = min(length, (u_int)(snapend - dat));
346 	if (i < sizeof(ap->rrep6_draft_01)) {
347 		printf(" [|rrep6]");
348 		return;
349 	}
350 	i -= sizeof(ap->rrep6_draft_01);
351 	printf(" rrep %u %s%sprefix %u hops %u\n"
352 	   "\tdst %s dseq %lu src %s %lu ms", length,
353 	    ap->rrep6_draft_01.rrep_type & RREP_REPAIR ? "[R]" : "",
354 	    ap->rrep6_draft_01.rrep_type & RREP_ACK ? "[A] " : " ",
355 	    ap->rrep6_draft_01.rrep_ps & RREP_PREFIX_MASK,
356 	    ap->rrep6_draft_01.rrep_hops,
357 	    ip6addr_string(&ap->rrep6_draft_01.rrep_da),
358 	    (unsigned long)EXTRACT_32BITS(&ap->rrep6_draft_01.rrep_ds),
359 	    ip6addr_string(&ap->rrep6_draft_01.rrep_oa),
360 	    (unsigned long)EXTRACT_32BITS(&ap->rrep6_draft_01.rrep_life));
361 	if (i >= sizeof(struct aodv_ext))
362 		aodv_extension((void *)(&ap->rrep6_draft_01 + 1), i);
363 #else
364 	printf(" rrep %u", length);
365 #endif
366 }
367 
368 static void
369 #ifdef INET6
370 aodv_v6_draft_01_rerr(const union aodv *ap, u_int length)
371 #else
372 aodv_v6_draft_01_rerr(const union aodv *ap _U_, u_int length)
373 #endif
374 {
375 #ifdef INET6
376 	const struct rerr_unreach6_draft_01 *dp6 = NULL;
377 	int i, j, n, trunc;
378 
379 	i = length - offsetof(struct aodv_rerr, r);
380 	j = sizeof(ap->rerr.r.dest6_draft_01[0]);
381 	dp6 = &ap->rerr.r.dest6_draft_01[0];
382 	n = ap->rerr.rerr_dc * j;
383 	printf(" rerr %s [items %u] [%u]:",
384 	    ap->rerr.rerr_flags & RERR_NODELETE ? "[D]" : "",
385 	    ap->rerr.rerr_dc, length);
386 	trunc = n - (i/j);
387 	for (; i -= j >= 0; ++dp6) {
388 		printf(" {%s}(%ld)", ip6addr_string(&dp6->u_da),
389 		    (unsigned long)EXTRACT_32BITS(&dp6->u_ds));
390 	}
391 	if (trunc)
392 		printf("[|rerr]");
393 #else
394 	printf(" rerr %u", length);
395 #endif
396 }
397 
398 void
399 aodv_print(const u_char *dat, u_int length, int is_ip6)
400 {
401 	const union aodv *ap;
402 
403 	ap = (union aodv *)dat;
404 	if (snapend < dat) {
405 		printf(" [|aodv]");
406 		return;
407 	}
408 	if (min(length, (u_int)(snapend - dat)) < sizeof(ap->rrep_ack)) {
409 		printf(" [|aodv]");
410 		return;
411 	}
412 	printf(" aodv");
413 
414 	switch (ap->rerr.rerr_type) {
415 
416 	case AODV_RREQ:
417 		if (is_ip6)
418 			aodv_v6_rreq(ap, dat, length);
419 		else
420 			aodv_rreq(ap, dat, length);
421 		break;
422 
423 	case AODV_RREP:
424 		if (is_ip6)
425 			aodv_v6_rrep(ap, dat, length);
426 		else
427 			aodv_rrep(ap, dat, length);
428 		break;
429 
430 	case AODV_RERR:
431 		if (is_ip6)
432 			aodv_v6_rerr(ap, length);
433 		else
434 			aodv_rerr(ap, dat, length);
435 		break;
436 
437 	case AODV_RREP_ACK:
438 		printf(" rrep-ack %u", length);
439 		break;
440 
441 	case AODV_V6_DRAFT_01_RREQ:
442 		aodv_v6_draft_01_rreq(ap, dat, length);
443 		break;
444 
445 	case AODV_V6_DRAFT_01_RREP:
446 		aodv_v6_draft_01_rrep(ap, dat, length);
447 		break;
448 
449 	case AODV_V6_DRAFT_01_RERR:
450 		aodv_v6_draft_01_rerr(ap, length);
451 		break;
452 
453 	case AODV_V6_DRAFT_01_RREP_ACK:
454 		printf(" rrep-ack %u", length);
455 		break;
456 
457 	default:
458 		printf(" %u %u", ap->rreq.rreq_type, length);
459 	}
460 }
461