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