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