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