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