]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/tcpdump/print-aodv.c
ident(1): Normalizing date format
[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 /* \summary: Ad hoc On-Demand Distance Vector (AODV) Routing printer */
34
35 #ifdef HAVE_CONFIG_H
36 #include "config.h"
37 #endif
38
39 #include <netdissect-stdinc.h>
40
41 #include "netdissect.h"
42 #include "addrtoname.h"
43 #include "extract.h"
44
45 /*
46  * RFC 3561
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 struct aodv_rreq6 {
60         uint8_t         rreq_type;      /* AODV message type (1) */
61         uint8_t         rreq_flags;     /* various flags */
62         uint8_t         rreq_zero0;     /* reserved, set to zero */
63         uint8_t         rreq_hops;      /* number of hops from originator */
64         uint32_t        rreq_id;        /* request ID */
65         struct in6_addr rreq_da;        /* destination IPv6 address */
66         uint32_t        rreq_ds;        /* destination sequence number */
67         struct in6_addr rreq_oa;        /* originator IPv6 address */
68         uint32_t        rreq_os;        /* originator sequence number */
69 };
70 struct aodv_rreq6_draft_01 {
71         uint8_t         rreq_type;      /* AODV message type (16) */
72         uint8_t         rreq_flags;     /* various flags */
73         uint8_t         rreq_zero0;     /* reserved, set to zero */
74         uint8_t         rreq_hops;      /* number of hops from originator */
75         uint32_t        rreq_id;        /* request ID */
76         uint32_t        rreq_ds;        /* destination sequence number */
77         uint32_t        rreq_os;        /* originator sequence number */
78         struct in6_addr rreq_da;        /* destination IPv6 address */
79         struct in6_addr rreq_oa;        /* originator IPv6 address */
80 };
81
82 #define RREQ_JOIN       0x80            /* join (reserved for multicast */
83 #define RREQ_REPAIR     0x40            /* repair (reserved for multicast */
84 #define RREQ_GRAT       0x20            /* gratuitous RREP */
85 #define RREQ_DEST       0x10            /* destination only */
86 #define RREQ_UNKNOWN    0x08            /* unknown destination sequence num */
87 #define RREQ_FLAGS_MASK 0xF8            /* mask for rreq_flags */
88
89 struct aodv_rrep {
90         uint8_t         rrep_type;      /* AODV message type (2) */
91         uint8_t         rrep_flags;     /* various flags */
92         uint8_t         rrep_ps;        /* prefix size */
93         uint8_t         rrep_hops;      /* number of hops from o to d */
94         uint32_t        rrep_da;        /* destination IPv4 address */
95         uint32_t        rrep_ds;        /* destination sequence number */
96         uint32_t        rrep_oa;        /* originator IPv4 address */
97         uint32_t        rrep_life;      /* lifetime of this route */
98 };
99 struct 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 };
109 struct 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
120 #define RREP_REPAIR             0x80    /* repair (reserved for multicast */
121 #define RREP_ACK                0x40    /* acknowledgement required */
122 #define RREP_FLAGS_MASK         0xC0    /* mask for rrep_flags */
123 #define RREP_PREFIX_MASK        0x1F    /* mask for prefix size */
124
125 struct rerr_unreach {
126         uint32_t        u_da;   /* IPv4 address */
127         uint32_t        u_ds;   /* sequence number */
128 };
129 struct rerr_unreach6 {
130         struct in6_addr u_da;   /* IPv6 address */
131         uint32_t        u_ds;   /* sequence number */
132 };
133 struct rerr_unreach6_draft_01 {
134         struct in6_addr u_da;   /* IPv6 address */
135         uint32_t        u_ds;   /* sequence number */
136 };
137
138 struct aodv_rerr {
139         uint8_t         rerr_type;      /* AODV message type (3 or 18) */
140         uint8_t         rerr_flags;     /* various flags */
141         uint8_t         rerr_zero0;     /* reserved, set to zero */
142         uint8_t         rerr_dc;        /* destination count */
143 };
144
145 #define RERR_NODELETE           0x80    /* don't delete the link */
146 #define RERR_FLAGS_MASK         0x80    /* mask for rerr_flags */
147
148 struct aodv_rrep_ack {
149         uint8_t         ra_type;
150         uint8_t         ra_zero0;
151 };
152
153 #define AODV_RREQ               1       /* route request */
154 #define AODV_RREP               2       /* route response */
155 #define AODV_RERR               3       /* error report */
156 #define AODV_RREP_ACK           4       /* route response acknowledgement */
157
158 #define AODV_V6_DRAFT_01_RREQ           16      /* IPv6 route request */
159 #define AODV_V6_DRAFT_01_RREP           17      /* IPv6 route response */
160 #define AODV_V6_DRAFT_01_RERR           18      /* IPv6 error report */
161 #define AODV_V6_DRAFT_01_RREP_ACK       19      /* IPV6 route response acknowledgment */
162
163 struct aodv_ext {
164         uint8_t         type;           /* extension type */
165         uint8_t         length;         /* extension length */
166 };
167
168 struct aodv_hello {
169         struct  aodv_ext        eh;             /* extension header */
170         uint8_t                 interval[4];    /* expect my next hello in
171                                                  * (n) ms
172                                                  * NOTE: this is not aligned */
173 };
174
175 #define AODV_EXT_HELLO  1
176
177 static void
178 aodv_extension(netdissect_options *ndo,
179                const struct aodv_ext *ep, u_int length)
180 {
181         const struct aodv_hello *ah;
182
183         ND_TCHECK(*ep);
184         switch (ep->type) {
185         case AODV_EXT_HELLO:
186                 ah = (const struct aodv_hello *)(const void *)ep;
187                 ND_TCHECK(*ah);
188                 if (length < sizeof(struct aodv_hello))
189                         goto trunc;
190                 if (ep->length < 4) {
191                         ND_PRINT((ndo, "\n\text HELLO - bad length %u", ep->length));
192                         break;
193                 }
194                 ND_PRINT((ndo, "\n\text HELLO %ld ms",
195                     (unsigned long)EXTRACT_32BITS(&ah->interval)));
196                 break;
197
198         default:
199                 ND_PRINT((ndo, "\n\text %u %u", ep->type, ep->length));
200                 break;
201         }
202         return;
203
204 trunc:
205         ND_PRINT((ndo, " [|hello]"));
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(*ap);
215         if (length < sizeof(*ap))
216                 goto trunc;
217         ND_PRINT((ndo, " rreq %u %s%s%s%s%shops %u id 0x%08lx\n"
218             "\tdst %s seq %lu src %s seq %lu", length,
219             ap->rreq_type & RREQ_JOIN ? "[J]" : "",
220             ap->rreq_type & RREQ_REPAIR ? "[R]" : "",
221             ap->rreq_type & RREQ_GRAT ? "[G]" : "",
222             ap->rreq_type & RREQ_DEST ? "[D]" : "",
223             ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
224             ap->rreq_hops,
225             (unsigned long)EXTRACT_32BITS(&ap->rreq_id),
226             ipaddr_string(ndo, &ap->rreq_da),
227             (unsigned long)EXTRACT_32BITS(&ap->rreq_ds),
228             ipaddr_string(ndo, &ap->rreq_oa),
229             (unsigned long)EXTRACT_32BITS(&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((ndo, " [|rreq"));
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(*ap);
246         if (length < sizeof(*ap))
247                 goto trunc;
248         ND_PRINT((ndo, " rrep %u %s%sprefix %u hops %u\n"
249             "\tdst %s dseq %lu src %s %lu ms", length,
250             ap->rrep_type & RREP_REPAIR ? "[R]" : "",
251             ap->rrep_type & RREP_ACK ? "[A] " : " ",
252             ap->rrep_ps & RREP_PREFIX_MASK,
253             ap->rrep_hops,
254             ipaddr_string(ndo, &ap->rrep_da),
255             (unsigned long)EXTRACT_32BITS(&ap->rrep_ds),
256             ipaddr_string(ndo, &ap->rrep_oa),
257             (unsigned long)EXTRACT_32BITS(&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((ndo, " [|rreq"));
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(*ap);
275         if (length < sizeof(*ap))
276                 goto trunc;
277         ND_PRINT((ndo, " rerr %s [items %u] [%u]:",
278             ap->rerr_flags & RERR_NODELETE ? "[D]" : "",
279             ap->rerr_dc, length));
280         dp = (const struct rerr_unreach *)(dat + sizeof(*ap));
281         i = length - sizeof(*ap);
282         for (dc = ap->rerr_dc; dc != 0; dc--) {
283                 ND_TCHECK(*dp);
284                 if (i < sizeof(*dp))
285                         goto trunc;
286                 ND_PRINT((ndo, " {%s}(%ld)", ipaddr_string(ndo, &dp->u_da),
287                     (unsigned long)EXTRACT_32BITS(&dp->u_ds)));
288                 dp++;
289                 i -= sizeof(*dp);
290         }
291         return;
292
293 trunc:
294         ND_PRINT((ndo, "[|rerr]"));
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(*ap);
304         if (length < sizeof(*ap))
305                 goto trunc;
306         ND_PRINT((ndo, " v6 rreq %u %s%s%s%s%shops %u id 0x%08lx\n"
307             "\tdst %s seq %lu src %s seq %lu", length,
308             ap->rreq_type & RREQ_JOIN ? "[J]" : "",
309             ap->rreq_type & RREQ_REPAIR ? "[R]" : "",
310             ap->rreq_type & RREQ_GRAT ? "[G]" : "",
311             ap->rreq_type & RREQ_DEST ? "[D]" : "",
312             ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
313             ap->rreq_hops,
314             (unsigned long)EXTRACT_32BITS(&ap->rreq_id),
315             ip6addr_string(ndo, &ap->rreq_da),
316             (unsigned long)EXTRACT_32BITS(&ap->rreq_ds),
317             ip6addr_string(ndo, &ap->rreq_oa),
318             (unsigned long)EXTRACT_32BITS(&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((ndo, " [|rreq"));
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(*ap);
335         if (length < sizeof(*ap))
336                 goto trunc;
337         ND_PRINT((ndo, " rrep %u %s%sprefix %u hops %u\n"
338            "\tdst %s dseq %lu src %s %lu ms", length,
339             ap->rrep_type & RREP_REPAIR ? "[R]" : "",
340             ap->rrep_type & RREP_ACK ? "[A] " : " ",
341             ap->rrep_ps & RREP_PREFIX_MASK,
342             ap->rrep_hops,
343             ip6addr_string(ndo, &ap->rrep_da),
344             (unsigned long)EXTRACT_32BITS(&ap->rrep_ds),
345             ip6addr_string(ndo, &ap->rrep_oa),
346             (unsigned long)EXTRACT_32BITS(&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((ndo, " [|rreq"));
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(*ap);
364         if (length < sizeof(*ap))
365                 goto trunc;
366         ND_PRINT((ndo, " rerr %s [items %u] [%u]:",
367             ap->rerr_flags & RERR_NODELETE ? "[D]" : "",
368             ap->rerr_dc, length));
369         dp6 = (const struct rerr_unreach6 *)(const void *)(ap + 1);
370         i = length - sizeof(*ap);
371         for (dc = ap->rerr_dc; dc != 0; dc--) {
372                 ND_TCHECK(*dp6);
373                 if (i < sizeof(*dp6))
374                         goto trunc;
375                 ND_PRINT((ndo, " {%s}(%ld)", ip6addr_string(ndo, &dp6->u_da),
376                     (unsigned long)EXTRACT_32BITS(&dp6->u_ds)));
377                 dp6++;
378                 i -= sizeof(*dp6);
379         }
380         return;
381
382 trunc:
383         ND_PRINT((ndo, "[|rerr]"));
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(*ap);
393         if (length < sizeof(*ap))
394                 goto trunc;
395         ND_PRINT((ndo, " rreq %u %s%s%s%s%shops %u id 0x%08lx\n"
396             "\tdst %s seq %lu src %s seq %lu", length,
397             ap->rreq_type & RREQ_JOIN ? "[J]" : "",
398             ap->rreq_type & RREQ_REPAIR ? "[R]" : "",
399             ap->rreq_type & RREQ_GRAT ? "[G]" : "",
400             ap->rreq_type & RREQ_DEST ? "[D]" : "",
401             ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
402             ap->rreq_hops,
403             (unsigned long)EXTRACT_32BITS(&ap->rreq_id),
404             ip6addr_string(ndo, &ap->rreq_da),
405             (unsigned long)EXTRACT_32BITS(&ap->rreq_ds),
406             ip6addr_string(ndo, &ap->rreq_oa),
407             (unsigned long)EXTRACT_32BITS(&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((ndo, " [|rreq"));
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(*ap);
424         if (length < sizeof(*ap))
425                 goto trunc;
426         ND_PRINT((ndo, " rrep %u %s%sprefix %u hops %u\n"
427            "\tdst %s dseq %lu src %s %lu ms", length,
428             ap->rrep_type & RREP_REPAIR ? "[R]" : "",
429             ap->rrep_type & RREP_ACK ? "[A] " : " ",
430             ap->rrep_ps & RREP_PREFIX_MASK,
431             ap->rrep_hops,
432             ip6addr_string(ndo, &ap->rrep_da),
433             (unsigned long)EXTRACT_32BITS(&ap->rrep_ds),
434             ip6addr_string(ndo, &ap->rrep_oa),
435             (unsigned long)EXTRACT_32BITS(&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((ndo, " [|rreq"));
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(*ap);
453         if (length < sizeof(*ap))
454                 goto trunc;
455         ND_PRINT((ndo, " rerr %s [items %u] [%u]:",
456             ap->rerr_flags & RERR_NODELETE ? "[D]" : "",
457             ap->rerr_dc, length));
458         dp6 = (const struct rerr_unreach6_draft_01 *)(const void *)(ap + 1);
459         i = length - sizeof(*ap);
460         for (dc = ap->rerr_dc; dc != 0; dc--) {
461                 ND_TCHECK(*dp6);
462                 if (i < sizeof(*dp6))
463                         goto trunc;
464                 ND_PRINT((ndo, " {%s}(%ld)", ip6addr_string(ndo, &dp6->u_da),
465                     (unsigned long)EXTRACT_32BITS(&dp6->u_ds)));
466                 dp6++;
467                 i -= sizeof(*dp6);
468         }
469         return;
470
471 trunc:
472         ND_PRINT((ndo, "[|rerr]"));
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         /*
482          * The message type is the first byte; make sure we have it
483          * and then fetch it.
484          */
485         ND_TCHECK(*dat);
486         msg_type = *dat;
487         ND_PRINT((ndo, " 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((ndo, " 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((ndo, " rrep-ack %u", length));
530                 break;
531
532         default:
533                 ND_PRINT((ndo, " type %u %u", msg_type, length));
534         }
535         return;
536
537 trunc:
538         ND_PRINT((ndo, " [|aodv]"));
539 }