xref: /minix/external/bsd/tcpdump/dist/print-aodv.c (revision fb9c64b2)
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 __RCSID("$NetBSD: print-aodv.c,v 1.5 2015/03/31 21:59:35 christos Exp $");
36 #endif
37 
38 #define NETDISSECT_REWORKED
39 #ifdef HAVE_CONFIG_H
40 #include "config.h"
41 #endif
42 
43 #include <tcpdump-stdinc.h>
44 
45 #include "interface.h"
46 #include "addrtoname.h"
47 #include "extract.h"			/* must come after interface.h */
48 
49 
50 struct aodv_rreq {
51 	uint8_t		rreq_type;	/* AODV message type (1) */
52 	uint8_t		rreq_flags;	/* various flags */
53 	uint8_t		rreq_zero0;	/* reserved, set to zero */
54 	uint8_t		rreq_hops;	/* number of hops from originator */
55 	uint32_t	rreq_id;	/* request ID */
56 	uint32_t	rreq_da;	/* destination IPv4 address */
57 	uint32_t	rreq_ds;	/* destination sequence number */
58 	uint32_t	rreq_oa;	/* originator IPv4 address */
59 	uint32_t	rreq_os;	/* originator sequence number */
60 };
61 #ifdef INET6
62 struct aodv_rreq6 {
63 	uint8_t		rreq_type;	/* AODV message type (1) */
64 	uint8_t		rreq_flags;	/* various flags */
65 	uint8_t		rreq_zero0;	/* reserved, set to zero */
66 	uint8_t		rreq_hops;	/* number of hops from originator */
67 	uint32_t	rreq_id;	/* request ID */
68 	struct in6_addr	rreq_da;	/* destination IPv6 address */
69 	uint32_t	rreq_ds;	/* destination sequence number */
70 	struct in6_addr	rreq_oa;	/* originator IPv6 address */
71 	uint32_t	rreq_os;	/* originator sequence number */
72 };
73 struct aodv_rreq6_draft_01 {
74 	uint8_t		rreq_type;	/* AODV message type (16) */
75 	uint8_t		rreq_flags;	/* various flags */
76 	uint8_t		rreq_zero0;	/* reserved, set to zero */
77 	uint8_t		rreq_hops;	/* number of hops from originator */
78 	uint32_t	rreq_id;	/* request ID */
79 	uint32_t	rreq_ds;	/* destination sequence number */
80 	uint32_t	rreq_os;	/* originator sequence number */
81 	struct in6_addr	rreq_da;	/* destination IPv6 address */
82 	struct in6_addr	rreq_oa;	/* originator IPv6 address */
83 };
84 #endif
85 
86 #define	RREQ_JOIN	0x80		/* join (reserved for multicast */
87 #define	RREQ_REPAIR	0x40		/* repair (reserved for multicast */
88 #define	RREQ_GRAT	0x20		/* gratuitous RREP */
89 #define	RREQ_DEST	0x10		/* destination only */
90 #define	RREQ_UNKNOWN	0x08		/* unknown destination sequence num */
91 #define	RREQ_FLAGS_MASK	0xF8		/* mask for rreq_flags */
92 
93 struct aodv_rrep {
94 	uint8_t		rrep_type;	/* AODV message type (2) */
95 	uint8_t		rrep_flags;	/* various flags */
96 	uint8_t		rrep_ps;	/* prefix size */
97 	uint8_t		rrep_hops;	/* number of hops from o to d */
98 	uint32_t	rrep_da;	/* destination IPv4 address */
99 	uint32_t	rrep_ds;	/* destination sequence number */
100 	uint32_t	rrep_oa;	/* originator IPv4 address */
101 	uint32_t	rrep_life;	/* lifetime of this route */
102 };
103 #ifdef INET6
104 struct aodv_rrep6 {
105 	uint8_t		rrep_type;	/* AODV message type (2) */
106 	uint8_t		rrep_flags;	/* various flags */
107 	uint8_t		rrep_ps;	/* prefix size */
108 	uint8_t		rrep_hops;	/* number of hops from o to d */
109 	struct in6_addr	rrep_da;	/* destination IPv6 address */
110 	uint32_t	rrep_ds;	/* destination sequence number */
111 	struct in6_addr	rrep_oa;	/* originator IPv6 address */
112 	uint32_t	rrep_life;	/* lifetime of this route */
113 };
114 struct aodv_rrep6_draft_01 {
115 	uint8_t		rrep_type;	/* AODV message type (17) */
116 	uint8_t		rrep_flags;	/* various flags */
117 	uint8_t		rrep_ps;	/* prefix size */
118 	uint8_t		rrep_hops;	/* number of hops from o to d */
119 	uint32_t	rrep_ds;	/* destination sequence number */
120 	struct in6_addr	rrep_da;	/* destination IPv6 address */
121 	struct in6_addr	rrep_oa;	/* originator IPv6 address */
122 	uint32_t	rrep_life;	/* lifetime of this route */
123 };
124 #endif
125 
126 #define	RREP_REPAIR		0x80	/* repair (reserved for multicast */
127 #define	RREP_ACK		0x40	/* acknowledgement required */
128 #define	RREP_FLAGS_MASK		0xC0	/* mask for rrep_flags */
129 #define	RREP_PREFIX_MASK	0x1F	/* mask for prefix size */
130 
131 struct rerr_unreach {
132 	uint32_t	u_da;	/* IPv4 address */
133 	uint32_t	u_ds;	/* sequence number */
134 };
135 #ifdef INET6
136 struct rerr_unreach6 {
137 	struct in6_addr	u_da;	/* IPv6 address */
138 	uint32_t	u_ds;	/* sequence number */
139 };
140 struct rerr_unreach6_draft_01 {
141 	struct in6_addr	u_da;	/* IPv6 address */
142 	uint32_t	u_ds;	/* sequence number */
143 };
144 #endif
145 
146 struct aodv_rerr {
147 	uint8_t		rerr_type;	/* AODV message type (3 or 18) */
148 	uint8_t		rerr_flags;	/* various flags */
149 	uint8_t		rerr_zero0;	/* reserved, set to zero */
150 	uint8_t		rerr_dc;	/* destination count */
151 };
152 
153 #define RERR_NODELETE		0x80	/* don't delete the link */
154 #define RERR_FLAGS_MASK		0x80	/* mask for rerr_flags */
155 
156 struct aodv_rrep_ack {
157 	uint8_t		ra_type;
158 	uint8_t		ra_zero0;
159 };
160 
161 #define	AODV_RREQ		1	/* route request */
162 #define	AODV_RREP		2	/* route response */
163 #define	AODV_RERR		3	/* error report */
164 #define	AODV_RREP_ACK		4	/* route response acknowledgement */
165 
166 #define AODV_V6_DRAFT_01_RREQ		16	/* IPv6 route request */
167 #define AODV_V6_DRAFT_01_RREP		17	/* IPv6 route response */
168 #define AODV_V6_DRAFT_01_RERR		18	/* IPv6 error report */
169 #define AODV_V6_DRAFT_01_RREP_ACK	19	/* IPV6 route response acknowledgment */
170 
171 struct aodv_ext {
172 	uint8_t		type;		/* extension type */
173 	uint8_t		length;		/* extension length */
174 };
175 
176 struct aodv_hello {
177 	struct	aodv_ext	eh;		/* extension header */
178 	uint8_t			interval[4];	/* expect my next hello in
179 						 * (n) ms
180 						 * NOTE: this is not aligned */
181 };
182 
183 #define	AODV_EXT_HELLO	1
184 
185 static void
186 aodv_extension(netdissect_options *ndo,
187                const struct aodv_ext *ep, u_int length)
188 {
189 	const struct aodv_hello *ah;
190 
191 	switch (ep->type) {
192 	case AODV_EXT_HELLO:
193 		ah = (const struct aodv_hello *)(const void *)ep;
194 		ND_TCHECK(*ah);
195 		if (length < sizeof(struct aodv_hello))
196 			goto trunc;
197 		ND_PRINT((ndo, "\n\text HELLO %ld ms",
198 		    (unsigned long)EXTRACT_32BITS(&ah->interval)));
199 		break;
200 
201 	default:
202 		ND_PRINT((ndo, "\n\text %u %u", ep->type, ep->length));
203 		break;
204 	}
205 	return;
206 
207 trunc:
208 	ND_PRINT((ndo, " [|hello]"));
209 }
210 
211 static void
212 aodv_rreq(netdissect_options *ndo, const u_char *dat, u_int length)
213 {
214 	u_int i;
215 	const struct aodv_rreq *ap = (const struct aodv_rreq *)dat;
216 
217 	ND_TCHECK(*ap);
218 	if (length < sizeof(*ap))
219 		goto trunc;
220 	ND_PRINT((ndo, " rreq %u %s%s%s%s%shops %u id 0x%08lx\n"
221 	    "\tdst %s seq %lu src %s seq %lu", length,
222 	    ap->rreq_type & RREQ_JOIN ? "[J]" : "",
223 	    ap->rreq_type & RREQ_REPAIR ? "[R]" : "",
224 	    ap->rreq_type & RREQ_GRAT ? "[G]" : "",
225 	    ap->rreq_type & RREQ_DEST ? "[D]" : "",
226 	    ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
227 	    ap->rreq_hops,
228 	    (unsigned long)EXTRACT_32BITS(&ap->rreq_id),
229 	    ipaddr_string(ndo, &ap->rreq_da),
230 	    (unsigned long)EXTRACT_32BITS(&ap->rreq_ds),
231 	    ipaddr_string(ndo, &ap->rreq_oa),
232 	    (unsigned long)EXTRACT_32BITS(&ap->rreq_os)));
233 	i = length - sizeof(*ap);
234 	if (i >= sizeof(struct aodv_ext))
235 		aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
236 	return;
237 
238 trunc:
239 	ND_PRINT((ndo, " [|rreq"));
240 }
241 
242 static void
243 aodv_rrep(netdissect_options *ndo, const u_char *dat, u_int length)
244 {
245 	u_int i;
246 	const struct aodv_rrep *ap = (const struct aodv_rrep *)dat;
247 
248 	ND_TCHECK(*ap);
249 	if (length < sizeof(*ap))
250 		goto trunc;
251 	ND_PRINT((ndo, " rrep %u %s%sprefix %u hops %u\n"
252 	    "\tdst %s dseq %lu src %s %lu ms", length,
253 	    ap->rrep_type & RREP_REPAIR ? "[R]" : "",
254 	    ap->rrep_type & RREP_ACK ? "[A] " : " ",
255 	    ap->rrep_ps & RREP_PREFIX_MASK,
256 	    ap->rrep_hops,
257 	    ipaddr_string(ndo, &ap->rrep_da),
258 	    (unsigned long)EXTRACT_32BITS(&ap->rrep_ds),
259 	    ipaddr_string(ndo, &ap->rrep_oa),
260 	    (unsigned long)EXTRACT_32BITS(&ap->rrep_life)));
261 	i = length - sizeof(*ap);
262 	if (i >= sizeof(struct aodv_ext))
263 		aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
264 	return;
265 
266 trunc:
267 	ND_PRINT((ndo, " [|rreq"));
268 }
269 
270 static void
271 aodv_rerr(netdissect_options *ndo, const u_char *dat, u_int length)
272 {
273 	u_int i, dc;
274 	const struct aodv_rerr *ap = (const struct aodv_rerr *)dat;
275 	const struct rerr_unreach *dp;
276 
277 	ND_TCHECK(*ap);
278 	if (length < sizeof(*ap))
279 		goto trunc;
280 	ND_PRINT((ndo, " rerr %s [items %u] [%u]:",
281 	    ap->rerr_flags & RERR_NODELETE ? "[D]" : "",
282 	    ap->rerr_dc, length));
283 	dp = (struct rerr_unreach *)(dat + sizeof(*ap));
284 	i = length - sizeof(*ap);
285 	for (dc = ap->rerr_dc; dc != 0; dc--) {
286 		ND_TCHECK(*dp);
287 		if (i < sizeof(*dp))
288 			goto trunc;
289 		ND_PRINT((ndo, " {%s}(%ld)", ipaddr_string(ndo, &dp->u_da),
290 		    (unsigned long)EXTRACT_32BITS(&dp->u_ds)));
291 		dp++;
292 		i -= sizeof(*dp);
293 	}
294 	return;
295 
296 trunc:
297 	ND_PRINT((ndo, "[|rerr]"));
298 }
299 
300 static void
301 #ifdef INET6
302 aodv_v6_rreq(netdissect_options *ndo, const u_char *dat, u_int length)
303 #else
304 aodv_v6_rreq(netdissect_options *ndo, const u_char *dat _U_, u_int length)
305 #endif
306 {
307 #ifdef INET6
308 	u_int i;
309 	const struct aodv_rreq6 *ap = (const struct aodv_rreq6 *)dat;
310 
311 	ND_TCHECK(*ap);
312 	if (length < sizeof(*ap))
313 		goto trunc;
314 	ND_PRINT((ndo, " v6 rreq %u %s%s%s%s%shops %u id 0x%08lx\n"
315 	    "\tdst %s seq %lu src %s seq %lu", length,
316 	    ap->rreq_type & RREQ_JOIN ? "[J]" : "",
317 	    ap->rreq_type & RREQ_REPAIR ? "[R]" : "",
318 	    ap->rreq_type & RREQ_GRAT ? "[G]" : "",
319 	    ap->rreq_type & RREQ_DEST ? "[D]" : "",
320 	    ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
321 	    ap->rreq_hops,
322 	    (unsigned long)EXTRACT_32BITS(&ap->rreq_id),
323 	    ip6addr_string(ndo, &ap->rreq_da),
324 	    (unsigned long)EXTRACT_32BITS(&ap->rreq_ds),
325 	    ip6addr_string(ndo, &ap->rreq_oa),
326 	    (unsigned long)EXTRACT_32BITS(&ap->rreq_os)));
327 	i = length - sizeof(*ap);
328 	if (i >= sizeof(struct aodv_ext))
329 		aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
330 	return;
331 
332 trunc:
333 	ND_PRINT((ndo, " [|rreq"));
334 #else
335 	ND_PRINT((ndo, " v6 rreq %u", length));
336 #endif
337 }
338 
339 static void
340 #ifdef INET6
341 aodv_v6_rrep(netdissect_options *ndo, const u_char *dat, u_int length)
342 #else
343 aodv_v6_rrep(netdissect_options *ndo, const u_char *dat _U_, u_int length)
344 #endif
345 {
346 #ifdef INET6
347 	u_int i;
348 	const struct aodv_rrep6 *ap = (const struct aodv_rrep6 *)dat;
349 
350 	ND_TCHECK(*ap);
351 	if (length < sizeof(*ap))
352 		goto trunc;
353 	ND_PRINT((ndo, " rrep %u %s%sprefix %u hops %u\n"
354 	   "\tdst %s dseq %lu src %s %lu ms", length,
355 	    ap->rrep_type & RREP_REPAIR ? "[R]" : "",
356 	    ap->rrep_type & RREP_ACK ? "[A] " : " ",
357 	    ap->rrep_ps & RREP_PREFIX_MASK,
358 	    ap->rrep_hops,
359 	    ip6addr_string(ndo, &ap->rrep_da),
360 	    (unsigned long)EXTRACT_32BITS(&ap->rrep_ds),
361 	    ip6addr_string(ndo, &ap->rrep_oa),
362 	    (unsigned long)EXTRACT_32BITS(&ap->rrep_life)));
363 	i = length - sizeof(*ap);
364 	if (i >= sizeof(struct aodv_ext))
365 		aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
366 	return;
367 
368 trunc:
369 	ND_PRINT((ndo, " [|rreq"));
370 #else
371 	ND_PRINT((ndo, " rrep %u", length));
372 #endif
373 }
374 
375 static void
376 #ifdef INET6
377 aodv_v6_rerr(netdissect_options *ndo, const u_char *dat, u_int length)
378 #else
379 aodv_v6_rerr(netdissect_options *ndo, const u_char *dat _U_, u_int length)
380 #endif
381 {
382 #ifdef INET6
383 	u_int i, dc;
384 	const struct aodv_rerr *ap = (const struct aodv_rerr *)dat;
385 	const struct rerr_unreach6 *dp6;
386 
387 	ND_TCHECK(*ap);
388 	if (length < sizeof(*ap))
389 		goto trunc;
390 	ND_PRINT((ndo, " rerr %s [items %u] [%u]:",
391 	    ap->rerr_flags & RERR_NODELETE ? "[D]" : "",
392 	    ap->rerr_dc, length));
393 	dp6 = (struct rerr_unreach6 *)(void *)(ap + 1);
394 	i = length - sizeof(*ap);
395 	for (dc = ap->rerr_dc; dc != 0; dc--) {
396 		ND_TCHECK(*dp6);
397 		if (i < sizeof(*dp6))
398 			goto trunc;
399 		ND_PRINT((ndo, " {%s}(%ld)", ip6addr_string(ndo, &dp6->u_da),
400 		    (unsigned long)EXTRACT_32BITS(&dp6->u_ds)));
401 		dp6++;
402 		i -= sizeof(*dp6);
403 	}
404 	return;
405 
406 trunc:
407 	ND_PRINT((ndo, "[|rerr]"));
408 #else
409 	ND_PRINT((ndo, " rerr %u", length));
410 #endif
411 }
412 
413 static void
414 #ifdef INET6
415 aodv_v6_draft_01_rreq(netdissect_options *ndo, const u_char *dat, u_int length)
416 #else
417 aodv_v6_draft_01_rreq(netdissect_options *ndo, const u_char *dat _U_, u_int length)
418 #endif
419 {
420 #ifdef INET6
421 	u_int i;
422 	const struct aodv_rreq6_draft_01 *ap = (const struct aodv_rreq6_draft_01 *)dat;
423 
424 	ND_TCHECK(*ap);
425 	if (length < sizeof(*ap))
426 		goto trunc;
427 	ND_PRINT((ndo, " rreq %u %s%s%s%s%shops %u id 0x%08lx\n"
428 	    "\tdst %s seq %lu src %s seq %lu", length,
429 	    ap->rreq_type & RREQ_JOIN ? "[J]" : "",
430 	    ap->rreq_type & RREQ_REPAIR ? "[R]" : "",
431 	    ap->rreq_type & RREQ_GRAT ? "[G]" : "",
432 	    ap->rreq_type & RREQ_DEST ? "[D]" : "",
433 	    ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
434 	    ap->rreq_hops,
435 	    (unsigned long)EXTRACT_32BITS(&ap->rreq_id),
436 	    ip6addr_string(ndo, &ap->rreq_da),
437 	    (unsigned long)EXTRACT_32BITS(&ap->rreq_ds),
438 	    ip6addr_string(ndo, &ap->rreq_oa),
439 	    (unsigned long)EXTRACT_32BITS(&ap->rreq_os)));
440 	i = length - sizeof(*ap);
441 	if (i >= sizeof(struct aodv_ext))
442 		aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
443 	return;
444 
445 trunc:
446 	ND_PRINT((ndo, " [|rreq"));
447 #else
448 	ND_PRINT((ndo, " rreq %u", length));
449 #endif
450 }
451 
452 static void
453 #ifdef INET6
454 aodv_v6_draft_01_rrep(netdissect_options *ndo, const u_char *dat, u_int length)
455 #else
456 aodv_v6_draft_01_rrep(netdissect_options *ndo, const u_char *dat _U_, u_int length)
457 #endif
458 {
459 #ifdef INET6
460 	u_int i;
461 	const struct aodv_rrep6_draft_01 *ap = (const struct aodv_rrep6_draft_01 *)dat;
462 
463 	ND_TCHECK(*ap);
464 	if (length < sizeof(*ap))
465 		goto trunc;
466 	ND_PRINT((ndo, " rrep %u %s%sprefix %u hops %u\n"
467 	   "\tdst %s dseq %lu src %s %lu ms", length,
468 	    ap->rrep_type & RREP_REPAIR ? "[R]" : "",
469 	    ap->rrep_type & RREP_ACK ? "[A] " : " ",
470 	    ap->rrep_ps & RREP_PREFIX_MASK,
471 	    ap->rrep_hops,
472 	    ip6addr_string(ndo, &ap->rrep_da),
473 	    (unsigned long)EXTRACT_32BITS(&ap->rrep_ds),
474 	    ip6addr_string(ndo, &ap->rrep_oa),
475 	    (unsigned long)EXTRACT_32BITS(&ap->rrep_life)));
476 	i = length - sizeof(*ap);
477 	if (i >= sizeof(struct aodv_ext))
478 		aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
479 	return;
480 
481 trunc:
482 	ND_PRINT((ndo, " [|rreq"));
483 #else
484 	ND_PRINT((ndo, " rrep %u", length));
485 #endif
486 }
487 
488 static void
489 #ifdef INET6
490 aodv_v6_draft_01_rerr(netdissect_options *ndo, const u_char *dat, u_int length)
491 #else
492 aodv_v6_draft_01_rerr(netdissect_options *ndo, const u_char *dat _U_, u_int length)
493 #endif
494 {
495 #ifdef INET6
496 	u_int i, dc;
497 	const struct aodv_rerr *ap = (const struct aodv_rerr *)dat;
498 	const struct rerr_unreach6_draft_01 *dp6;
499 
500 	ND_TCHECK(*ap);
501 	if (length < sizeof(*ap))
502 		goto trunc;
503 	ND_PRINT((ndo, " rerr %s [items %u] [%u]:",
504 	    ap->rerr_flags & RERR_NODELETE ? "[D]" : "",
505 	    ap->rerr_dc, length));
506 	dp6 = (struct rerr_unreach6_draft_01 *)(void *)(ap + 1);
507 	i = length - sizeof(*ap);
508 	for (dc = ap->rerr_dc; dc != 0; dc--) {
509 		ND_TCHECK(*dp6);
510 		if (i < sizeof(*dp6))
511 			goto trunc;
512 		ND_PRINT((ndo, " {%s}(%ld)", ip6addr_string(ndo, &dp6->u_da),
513 		    (unsigned long)EXTRACT_32BITS(&dp6->u_ds)));
514 		dp6++;
515 		i -= sizeof(*dp6);
516 	}
517 	return;
518 
519 trunc:
520 	ND_PRINT((ndo, "[|rerr]"));
521 #else
522 	ND_PRINT((ndo, " rerr %u", length));
523 #endif
524 }
525 
526 void
527 aodv_print(netdissect_options *ndo,
528            const u_char *dat, u_int length, int is_ip6)
529 {
530 	uint8_t msg_type;
531 
532 	/*
533 	 * The message type is the first byte; make sure we have it
534 	 * and then fetch it.
535 	 */
536 	ND_TCHECK(*dat);
537 	msg_type = *dat;
538 	ND_PRINT((ndo, " aodv"));
539 
540 	switch (msg_type) {
541 
542 	case AODV_RREQ:
543 		if (is_ip6)
544 			aodv_v6_rreq(ndo, dat, length);
545 		else
546 			aodv_rreq(ndo, dat, length);
547 		break;
548 
549 	case AODV_RREP:
550 		if (is_ip6)
551 			aodv_v6_rrep(ndo, dat, length);
552 		else
553 			aodv_rrep(ndo, dat, length);
554 		break;
555 
556 	case AODV_RERR:
557 		if (is_ip6)
558 			aodv_v6_rerr(ndo, dat, length);
559 		else
560 			aodv_rerr(ndo, dat, length);
561 		break;
562 
563 	case AODV_RREP_ACK:
564 		ND_PRINT((ndo, " rrep-ack %u", length));
565 		break;
566 
567 	case AODV_V6_DRAFT_01_RREQ:
568 		aodv_v6_draft_01_rreq(ndo, dat, length);
569 		break;
570 
571 	case AODV_V6_DRAFT_01_RREP:
572 		aodv_v6_draft_01_rrep(ndo, dat, length);
573 		break;
574 
575 	case AODV_V6_DRAFT_01_RERR:
576 		aodv_v6_draft_01_rerr(ndo, dat, length);
577 		break;
578 
579 	case AODV_V6_DRAFT_01_RREP_ACK:
580 		ND_PRINT((ndo, " rrep-ack %u", length));
581 		break;
582 
583 	default:
584 		ND_PRINT((ndo, " type %u %u", msg_type, length));
585 	}
586 	return;
587 
588 trunc:
589 	ND_PRINT((ndo, " [|aodv]"));
590 }
591