xref: /freebsd/contrib/tcpdump/print-aodv.c (revision 7937bfbc0ca53fe7cdd0d54414f9296e273a518e)
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 #include <config.h>
36 
37 #include "netdissect-stdinc.h"
38 
39 #include "netdissect.h"
40 #include "addrtoname.h"
41 #include "extract.h"
42 
43 /*
44  * RFC 3561
45  */
46 struct aodv_rreq {
47 	nd_uint8_t	rreq_type;	/* AODV message type (1) */
48 	nd_uint8_t	rreq_flags;	/* various flags */
49 	nd_uint8_t	rreq_zero0;	/* reserved, set to zero */
50 	nd_uint8_t	rreq_hops;	/* number of hops from originator */
51 	nd_uint32_t	rreq_id;	/* request ID */
52 	nd_ipv4		rreq_da;	/* destination IPv4 address */
53 	nd_uint32_t	rreq_ds;	/* destination sequence number */
54 	nd_ipv4		rreq_oa;	/* originator IPv4 address */
55 	nd_uint32_t	rreq_os;	/* originator sequence number */
56 };
57 struct aodv_rreq6 {
58 	nd_uint8_t	rreq_type;	/* AODV message type (1) */
59 	nd_uint8_t	rreq_flags;	/* various flags */
60 	nd_uint8_t	rreq_zero0;	/* reserved, set to zero */
61 	nd_uint8_t	rreq_hops;	/* number of hops from originator */
62 	nd_uint32_t	rreq_id;	/* request ID */
63 	nd_ipv6		rreq_da;	/* destination IPv6 address */
64 	nd_uint32_t	rreq_ds;	/* destination sequence number */
65 	nd_ipv6		rreq_oa;	/* originator IPv6 address */
66 	nd_uint32_t	rreq_os;	/* originator sequence number */
67 };
68 struct aodv_rreq6_draft_01 {
69 	nd_uint8_t	rreq_type;	/* AODV message type (16) */
70 	nd_uint8_t	rreq_flags;	/* various flags */
71 	nd_uint8_t	rreq_zero0;	/* reserved, set to zero */
72 	nd_uint8_t	rreq_hops;	/* number of hops from originator */
73 	nd_uint32_t	rreq_id;	/* request ID */
74 	nd_uint32_t	rreq_ds;	/* destination sequence number */
75 	nd_uint32_t	rreq_os;	/* originator sequence number */
76 	nd_ipv6		rreq_da;	/* destination IPv6 address */
77 	nd_ipv6		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 	nd_uint8_t	rrep_type;	/* AODV message type (2) */
89 	nd_uint8_t	rrep_flags;	/* various flags */
90 	nd_uint8_t	rrep_ps;	/* prefix size */
91 	nd_uint8_t	rrep_hops;	/* number of hops from o to d */
92 	nd_ipv4		rrep_da;	/* destination IPv4 address */
93 	nd_uint32_t	rrep_ds;	/* destination sequence number */
94 	nd_ipv4		rrep_oa;	/* originator IPv4 address */
95 	nd_uint32_t	rrep_life;	/* lifetime of this route */
96 };
97 struct aodv_rrep6 {
98 	nd_uint8_t	rrep_type;	/* AODV message type (2) */
99 	nd_uint8_t	rrep_flags;	/* various flags */
100 	nd_uint8_t	rrep_ps;	/* prefix size */
101 	nd_uint8_t	rrep_hops;	/* number of hops from o to d */
102 	nd_ipv6		rrep_da;	/* destination IPv6 address */
103 	nd_uint32_t	rrep_ds;	/* destination sequence number */
104 	nd_ipv6		rrep_oa;	/* originator IPv6 address */
105 	nd_uint32_t	rrep_life;	/* lifetime of this route */
106 };
107 struct aodv_rrep6_draft_01 {
108 	nd_uint8_t	rrep_type;	/* AODV message type (17) */
109 	nd_uint8_t	rrep_flags;	/* various flags */
110 	nd_uint8_t	rrep_ps;	/* prefix size */
111 	nd_uint8_t	rrep_hops;	/* number of hops from o to d */
112 	nd_uint32_t	rrep_ds;	/* destination sequence number */
113 	nd_ipv6		rrep_da;	/* destination IPv6 address */
114 	nd_ipv6		rrep_oa;	/* originator IPv6 address */
115 	nd_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 	nd_ipv4		u_da;	/* IPv4 address */
125 	nd_uint32_t	u_ds;	/* sequence number */
126 };
127 struct rerr_unreach6 {
128 	nd_ipv6		u_da;	/* IPv6 address */
129 	nd_uint32_t	u_ds;	/* sequence number */
130 };
131 struct rerr_unreach6_draft_01 {
132 	nd_ipv6		u_da;	/* IPv6 address */
133 	nd_uint32_t	u_ds;	/* sequence number */
134 };
135 
136 struct aodv_rerr {
137 	nd_uint8_t	rerr_type;	/* AODV message type (3 or 18) */
138 	nd_uint8_t	rerr_flags;	/* various flags */
139 	nd_uint8_t	rerr_zero0;	/* reserved, set to zero */
140 	nd_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 	nd_uint8_t	ra_type;
148 	nd_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 	nd_uint8_t	type;		/* extension type */
163 	nd_uint8_t	length;		/* extension length */
164 };
165 
166 struct aodv_hello {
167 	struct	aodv_ext	eh;		/* extension header */
168 	nd_uint32_t		interval;	/* 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 	ND_TCHECK_SIZE(ep);
182 	switch (GET_U_1(ep->type)) {
183 	case AODV_EXT_HELLO:
184 		ah = (const struct aodv_hello *)(const void *)ep;
185 		ND_TCHECK_SIZE(ah);
186 		if (length < sizeof(struct aodv_hello))
187 			goto trunc;
188 		if (GET_U_1(ep->length) < 4) {
189 			ND_PRINT("\n\text HELLO - bad length %u",
190 				 GET_U_1(ep->length));
191 			break;
192 		}
193 		ND_PRINT("\n\text HELLO %u ms",
194 		    GET_BE_U_4(ah->interval));
195 		break;
196 
197 	default:
198 		ND_PRINT("\n\text %u %u", GET_U_1(ep->type),
199 			 GET_U_1(ep->length));
200 		break;
201 	}
202 	return;
203 
204 trunc:
205 	nd_print_trunc(ndo);
206 }
207 
208 static void
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_SIZE(ap);
215 	if (length < sizeof(*ap))
216 		goto trunc;
217 	ND_PRINT(" rreq %u %s%s%s%s%shops %u id 0x%08x\n"
218 	    "\tdst %s seq %u src %s seq %u", length,
219 	    GET_U_1(ap->rreq_type) & RREQ_JOIN ? "[J]" : "",
220 	    GET_U_1(ap->rreq_type) & RREQ_REPAIR ? "[R]" : "",
221 	    GET_U_1(ap->rreq_type) & RREQ_GRAT ? "[G]" : "",
222 	    GET_U_1(ap->rreq_type) & RREQ_DEST ? "[D]" : "",
223 	    GET_U_1(ap->rreq_type) & RREQ_UNKNOWN ? "[U] " : " ",
224 	    GET_U_1(ap->rreq_hops),
225 	    GET_BE_U_4(ap->rreq_id),
226 	    GET_IPADDR_STRING(ap->rreq_da),
227 	    GET_BE_U_4(ap->rreq_ds),
228 	    GET_IPADDR_STRING(ap->rreq_oa),
229 	    GET_BE_U_4(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_trunc(ndo);
237 }
238 
239 static void
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_SIZE(ap);
246 	if (length < sizeof(*ap))
247 		goto trunc;
248 	ND_PRINT(" rrep %u %s%sprefix %u hops %u\n"
249 	    "\tdst %s dseq %u src %s %u ms", length,
250 	    GET_U_1(ap->rrep_type) & RREP_REPAIR ? "[R]" : "",
251 	    GET_U_1(ap->rrep_type) & RREP_ACK ? "[A] " : " ",
252 	    GET_U_1(ap->rrep_ps) & RREP_PREFIX_MASK,
253 	    GET_U_1(ap->rrep_hops),
254 	    GET_IPADDR_STRING(ap->rrep_da),
255 	    GET_BE_U_4(ap->rrep_ds),
256 	    GET_IPADDR_STRING(ap->rrep_oa),
257 	    GET_BE_U_4(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_trunc(ndo);
265 }
266 
267 static void
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_SIZE(ap);
275 	if (length < sizeof(*ap))
276 		goto trunc;
277 	ND_PRINT(" rerr %s [items %u] [%u]:",
278 	    GET_U_1(ap->rerr_flags) & RERR_NODELETE ? "[D]" : "",
279 	    GET_U_1(ap->rerr_dc), length);
280 	dp = (const struct rerr_unreach *)(dat + sizeof(*ap));
281 	i = length - sizeof(*ap);
282 	for (dc = GET_U_1(ap->rerr_dc); dc != 0; dc--) {
283 		ND_TCHECK_SIZE(dp);
284 		if (i < sizeof(*dp))
285 			goto trunc;
286 		ND_PRINT(" {%s}(%u)", GET_IPADDR_STRING(dp->u_da),
287 		    GET_BE_U_4(dp->u_ds));
288 		dp++;
289 		i -= sizeof(*dp);
290 	}
291 	return;
292 
293 trunc:
294 	nd_print_trunc(ndo);
295 }
296 
297 static void
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_SIZE(ap);
304 	if (length < sizeof(*ap))
305 		goto trunc;
306 	ND_PRINT(" v6 rreq %u %s%s%s%s%shops %u id 0x%08x\n"
307 	    "\tdst %s seq %u src %s seq %u", length,
308 	    GET_U_1(ap->rreq_type) & RREQ_JOIN ? "[J]" : "",
309 	    GET_U_1(ap->rreq_type) & RREQ_REPAIR ? "[R]" : "",
310 	    GET_U_1(ap->rreq_type) & RREQ_GRAT ? "[G]" : "",
311 	    GET_U_1(ap->rreq_type) & RREQ_DEST ? "[D]" : "",
312 	    GET_U_1(ap->rreq_type) & RREQ_UNKNOWN ? "[U] " : " ",
313 	    GET_U_1(ap->rreq_hops),
314 	    GET_BE_U_4(ap->rreq_id),
315 	    GET_IP6ADDR_STRING(ap->rreq_da),
316 	    GET_BE_U_4(ap->rreq_ds),
317 	    GET_IP6ADDR_STRING(ap->rreq_oa),
318 	    GET_BE_U_4(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_trunc(ndo);
326 }
327 
328 static void
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_SIZE(ap);
335 	if (length < sizeof(*ap))
336 		goto trunc;
337 	ND_PRINT(" rrep %u %s%sprefix %u hops %u\n"
338 	   "\tdst %s dseq %u src %s %u ms", length,
339 	    GET_U_1(ap->rrep_type) & RREP_REPAIR ? "[R]" : "",
340 	    GET_U_1(ap->rrep_type) & RREP_ACK ? "[A] " : " ",
341 	    GET_U_1(ap->rrep_ps) & RREP_PREFIX_MASK,
342 	    GET_U_1(ap->rrep_hops),
343 	    GET_IP6ADDR_STRING(ap->rrep_da),
344 	    GET_BE_U_4(ap->rrep_ds),
345 	    GET_IP6ADDR_STRING(ap->rrep_oa),
346 	    GET_BE_U_4(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_trunc(ndo);
354 }
355 
356 static void
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_SIZE(ap);
364 	if (length < sizeof(*ap))
365 		goto trunc;
366 	ND_PRINT(" rerr %s [items %u] [%u]:",
367 	    GET_U_1(ap->rerr_flags) & RERR_NODELETE ? "[D]" : "",
368 	    GET_U_1(ap->rerr_dc), length);
369 	dp6 = (const struct rerr_unreach6 *)(const void *)(ap + 1);
370 	i = length - sizeof(*ap);
371 	for (dc = GET_U_1(ap->rerr_dc); dc != 0; dc--) {
372 		ND_TCHECK_SIZE(dp6);
373 		if (i < sizeof(*dp6))
374 			goto trunc;
375 		ND_PRINT(" {%s}(%u)", GET_IP6ADDR_STRING(dp6->u_da),
376 			 GET_BE_U_4(dp6->u_ds));
377 		dp6++;
378 		i -= sizeof(*dp6);
379 	}
380 	return;
381 
382 trunc:
383 	nd_print_trunc(ndo);
384 }
385 
386 static void
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_SIZE(ap);
393 	if (length < sizeof(*ap))
394 		goto trunc;
395 	ND_PRINT(" rreq %u %s%s%s%s%shops %u id 0x%08x\n"
396 	    "\tdst %s seq %u src %s seq %u", length,
397 	    GET_U_1(ap->rreq_type) & RREQ_JOIN ? "[J]" : "",
398 	    GET_U_1(ap->rreq_type) & RREQ_REPAIR ? "[R]" : "",
399 	    GET_U_1(ap->rreq_type) & RREQ_GRAT ? "[G]" : "",
400 	    GET_U_1(ap->rreq_type) & RREQ_DEST ? "[D]" : "",
401 	    GET_U_1(ap->rreq_type) & RREQ_UNKNOWN ? "[U] " : " ",
402 	    GET_U_1(ap->rreq_hops),
403 	    GET_BE_U_4(ap->rreq_id),
404 	    GET_IP6ADDR_STRING(ap->rreq_da),
405 	    GET_BE_U_4(ap->rreq_ds),
406 	    GET_IP6ADDR_STRING(ap->rreq_oa),
407 	    GET_BE_U_4(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_trunc(ndo);
415 }
416 
417 static void
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_SIZE(ap);
424 	if (length < sizeof(*ap))
425 		goto trunc;
426 	ND_PRINT(" rrep %u %s%sprefix %u hops %u\n"
427 	   "\tdst %s dseq %u src %s %u ms", length,
428 	    GET_U_1(ap->rrep_type) & RREP_REPAIR ? "[R]" : "",
429 	    GET_U_1(ap->rrep_type) & RREP_ACK ? "[A] " : " ",
430 	    GET_U_1(ap->rrep_ps) & RREP_PREFIX_MASK,
431 	    GET_U_1(ap->rrep_hops),
432 	    GET_IP6ADDR_STRING(ap->rrep_da),
433 	    GET_BE_U_4(ap->rrep_ds),
434 	    GET_IP6ADDR_STRING(ap->rrep_oa),
435 	    GET_BE_U_4(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_trunc(ndo);
443 }
444 
445 static void
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_SIZE(ap);
453 	if (length < sizeof(*ap))
454 		goto trunc;
455 	ND_PRINT(" rerr %s [items %u] [%u]:",
456 	    GET_U_1(ap->rerr_flags) & RERR_NODELETE ? "[D]" : "",
457 	    GET_U_1(ap->rerr_dc), length);
458 	dp6 = (const struct rerr_unreach6_draft_01 *)(const void *)(ap + 1);
459 	i = length - sizeof(*ap);
460 	for (dc = GET_U_1(ap->rerr_dc); dc != 0; dc--) {
461 		ND_TCHECK_SIZE(dp6);
462 		if (i < sizeof(*dp6))
463 			goto trunc;
464 		ND_PRINT(" {%s}(%u)", GET_IP6ADDR_STRING(dp6->u_da),
465 			 GET_BE_U_4(dp6->u_ds));
466 		dp6++;
467 		i -= sizeof(*dp6);
468 	}
469 	return;
470 
471 trunc:
472 	nd_print_trunc(ndo);
473 }
474 
475 void
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 	ndo->ndo_protocol = "aodv";
482 	/*
483 	 * The message type is the first byte; make sure we have it
484 	 * and then fetch it.
485 	 */
486 	msg_type = GET_U_1(dat);
487 	ND_PRINT(" 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(" 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(" rrep-ack %u", length);
530 		break;
531 
532 	default:
533 		ND_PRINT(" type %u %u", msg_type, length);
534 	}
535 }
536