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