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