]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/tcpdump/print-aodv.c
Update to zstd 1.3.2
[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 struct aodv_rreq {
47         uint8_t         rreq_type;      /* AODV message type (1) */
48         uint8_t         rreq_flags;     /* various flags */
49         uint8_t         rreq_zero0;     /* reserved, set to zero */
50         uint8_t         rreq_hops;      /* number of hops from originator */
51         uint32_t        rreq_id;        /* request ID */
52         uint32_t        rreq_da;        /* destination IPv4 address */
53         uint32_t        rreq_ds;        /* destination sequence number */
54         uint32_t        rreq_oa;        /* originator IPv4 address */
55         uint32_t        rreq_os;        /* originator sequence number */
56 };
57 struct 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 };
68 struct 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
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         uint8_t         rrep_type;      /* AODV message type (2) */
89         uint8_t         rrep_flags;     /* various flags */
90         uint8_t         rrep_ps;        /* prefix size */
91         uint8_t         rrep_hops;      /* number of hops from o to d */
92         uint32_t        rrep_da;        /* destination IPv4 address */
93         uint32_t        rrep_ds;        /* destination sequence number */
94         uint32_t        rrep_oa;        /* originator IPv4 address */
95         uint32_t        rrep_life;      /* lifetime of this route */
96 };
97 struct aodv_rrep6 {
98         uint8_t         rrep_type;      /* AODV message type (2) */
99         uint8_t         rrep_flags;     /* various flags */
100         uint8_t         rrep_ps;        /* prefix size */
101         uint8_t         rrep_hops;      /* number of hops from o to d */
102         struct in6_addr rrep_da;        /* destination IPv6 address */
103         uint32_t        rrep_ds;        /* destination sequence number */
104         struct in6_addr rrep_oa;        /* originator IPv6 address */
105         uint32_t        rrep_life;      /* lifetime of this route */
106 };
107 struct aodv_rrep6_draft_01 {
108         uint8_t         rrep_type;      /* AODV message type (17) */
109         uint8_t         rrep_flags;     /* various flags */
110         uint8_t         rrep_ps;        /* prefix size */
111         uint8_t         rrep_hops;      /* number of hops from o to d */
112         uint32_t        rrep_ds;        /* destination sequence number */
113         struct in6_addr rrep_da;        /* destination IPv6 address */
114         struct in6_addr rrep_oa;        /* originator IPv6 address */
115         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         uint32_t        u_da;   /* IPv4 address */
125         uint32_t        u_ds;   /* sequence number */
126 };
127 struct rerr_unreach6 {
128         struct in6_addr u_da;   /* IPv6 address */
129         uint32_t        u_ds;   /* sequence number */
130 };
131 struct rerr_unreach6_draft_01 {
132         struct in6_addr u_da;   /* IPv6 address */
133         uint32_t        u_ds;   /* sequence number */
134 };
135
136 struct aodv_rerr {
137         uint8_t         rerr_type;      /* AODV message type (3 or 18) */
138         uint8_t         rerr_flags;     /* various flags */
139         uint8_t         rerr_zero0;     /* reserved, set to zero */
140         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         uint8_t         ra_type;
148         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         uint8_t         type;           /* extension type */
163         uint8_t         length;         /* extension length */
164 };
165
166 struct aodv_hello {
167         struct  aodv_ext        eh;             /* extension header */
168         uint8_t                 interval[4];    /* 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         switch (ep->type) {
182         case AODV_EXT_HELLO:
183                 ah = (const struct aodv_hello *)(const void *)ep;
184                 ND_TCHECK(*ah);
185                 if (length < sizeof(struct aodv_hello))
186                         goto trunc;
187                 ND_PRINT((ndo, "\n\text HELLO %ld ms",
188                     (unsigned long)EXTRACT_32BITS(&ah->interval)));
189                 break;
190
191         default:
192                 ND_PRINT((ndo, "\n\text %u %u", ep->type, ep->length));
193                 break;
194         }
195         return;
196
197 trunc:
198         ND_PRINT((ndo, " [|hello]"));
199 }
200
201 static void
202 aodv_rreq(netdissect_options *ndo, const u_char *dat, u_int length)
203 {
204         u_int i;
205         const struct aodv_rreq *ap = (const struct aodv_rreq *)dat;
206
207         ND_TCHECK(*ap);
208         if (length < sizeof(*ap))
209                 goto trunc;
210         ND_PRINT((ndo, " rreq %u %s%s%s%s%shops %u id 0x%08lx\n"
211             "\tdst %s seq %lu src %s seq %lu", length,
212             ap->rreq_type & RREQ_JOIN ? "[J]" : "",
213             ap->rreq_type & RREQ_REPAIR ? "[R]" : "",
214             ap->rreq_type & RREQ_GRAT ? "[G]" : "",
215             ap->rreq_type & RREQ_DEST ? "[D]" : "",
216             ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
217             ap->rreq_hops,
218             (unsigned long)EXTRACT_32BITS(&ap->rreq_id),
219             ipaddr_string(ndo, &ap->rreq_da),
220             (unsigned long)EXTRACT_32BITS(&ap->rreq_ds),
221             ipaddr_string(ndo, &ap->rreq_oa),
222             (unsigned long)EXTRACT_32BITS(&ap->rreq_os)));
223         i = length - sizeof(*ap);
224         if (i >= sizeof(struct aodv_ext))
225                 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
226         return;
227
228 trunc:
229         ND_PRINT((ndo, " [|rreq"));
230 }
231
232 static void
233 aodv_rrep(netdissect_options *ndo, const u_char *dat, u_int length)
234 {
235         u_int i;
236         const struct aodv_rrep *ap = (const struct aodv_rrep *)dat;
237
238         ND_TCHECK(*ap);
239         if (length < sizeof(*ap))
240                 goto trunc;
241         ND_PRINT((ndo, " rrep %u %s%sprefix %u hops %u\n"
242             "\tdst %s dseq %lu src %s %lu ms", length,
243             ap->rrep_type & RREP_REPAIR ? "[R]" : "",
244             ap->rrep_type & RREP_ACK ? "[A] " : " ",
245             ap->rrep_ps & RREP_PREFIX_MASK,
246             ap->rrep_hops,
247             ipaddr_string(ndo, &ap->rrep_da),
248             (unsigned long)EXTRACT_32BITS(&ap->rrep_ds),
249             ipaddr_string(ndo, &ap->rrep_oa),
250             (unsigned long)EXTRACT_32BITS(&ap->rrep_life)));
251         i = length - sizeof(*ap);
252         if (i >= sizeof(struct aodv_ext))
253                 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
254         return;
255
256 trunc:
257         ND_PRINT((ndo, " [|rreq"));
258 }
259
260 static void
261 aodv_rerr(netdissect_options *ndo, const u_char *dat, u_int length)
262 {
263         u_int i, dc;
264         const struct aodv_rerr *ap = (const struct aodv_rerr *)dat;
265         const struct rerr_unreach *dp;
266
267         ND_TCHECK(*ap);
268         if (length < sizeof(*ap))
269                 goto trunc;
270         ND_PRINT((ndo, " rerr %s [items %u] [%u]:",
271             ap->rerr_flags & RERR_NODELETE ? "[D]" : "",
272             ap->rerr_dc, length));
273         dp = (const struct rerr_unreach *)(dat + sizeof(*ap));
274         i = length - sizeof(*ap);
275         for (dc = ap->rerr_dc; dc != 0; dc--) {
276                 ND_TCHECK(*dp);
277                 if (i < sizeof(*dp))
278                         goto trunc;
279                 ND_PRINT((ndo, " {%s}(%ld)", ipaddr_string(ndo, &dp->u_da),
280                     (unsigned long)EXTRACT_32BITS(&dp->u_ds)));
281                 dp++;
282                 i -= sizeof(*dp);
283         }
284         return;
285
286 trunc:
287         ND_PRINT((ndo, "[|rerr]"));
288 }
289
290 static void
291 aodv_v6_rreq(netdissect_options *ndo, const u_char *dat, u_int length)
292 {
293         u_int i;
294         const struct aodv_rreq6 *ap = (const struct aodv_rreq6 *)dat;
295
296         ND_TCHECK(*ap);
297         if (length < sizeof(*ap))
298                 goto trunc;
299         ND_PRINT((ndo, " v6 rreq %u %s%s%s%s%shops %u id 0x%08lx\n"
300             "\tdst %s seq %lu src %s seq %lu", length,
301             ap->rreq_type & RREQ_JOIN ? "[J]" : "",
302             ap->rreq_type & RREQ_REPAIR ? "[R]" : "",
303             ap->rreq_type & RREQ_GRAT ? "[G]" : "",
304             ap->rreq_type & RREQ_DEST ? "[D]" : "",
305             ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
306             ap->rreq_hops,
307             (unsigned long)EXTRACT_32BITS(&ap->rreq_id),
308             ip6addr_string(ndo, &ap->rreq_da),
309             (unsigned long)EXTRACT_32BITS(&ap->rreq_ds),
310             ip6addr_string(ndo, &ap->rreq_oa),
311             (unsigned long)EXTRACT_32BITS(&ap->rreq_os)));
312         i = length - sizeof(*ap);
313         if (i >= sizeof(struct aodv_ext))
314                 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
315         return;
316
317 trunc:
318         ND_PRINT((ndo, " [|rreq"));
319 }
320
321 static void
322 aodv_v6_rrep(netdissect_options *ndo, const u_char *dat, u_int length)
323 {
324         u_int i;
325         const struct aodv_rrep6 *ap = (const struct aodv_rrep6 *)dat;
326
327         ND_TCHECK(*ap);
328         if (length < sizeof(*ap))
329                 goto trunc;
330         ND_PRINT((ndo, " rrep %u %s%sprefix %u hops %u\n"
331            "\tdst %s dseq %lu src %s %lu ms", length,
332             ap->rrep_type & RREP_REPAIR ? "[R]" : "",
333             ap->rrep_type & RREP_ACK ? "[A] " : " ",
334             ap->rrep_ps & RREP_PREFIX_MASK,
335             ap->rrep_hops,
336             ip6addr_string(ndo, &ap->rrep_da),
337             (unsigned long)EXTRACT_32BITS(&ap->rrep_ds),
338             ip6addr_string(ndo, &ap->rrep_oa),
339             (unsigned long)EXTRACT_32BITS(&ap->rrep_life)));
340         i = length - sizeof(*ap);
341         if (i >= sizeof(struct aodv_ext))
342                 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
343         return;
344
345 trunc:
346         ND_PRINT((ndo, " [|rreq"));
347 }
348
349 static void
350 aodv_v6_rerr(netdissect_options *ndo, const u_char *dat, u_int length)
351 {
352         u_int i, dc;
353         const struct aodv_rerr *ap = (const struct aodv_rerr *)dat;
354         const struct rerr_unreach6 *dp6;
355
356         ND_TCHECK(*ap);
357         if (length < sizeof(*ap))
358                 goto trunc;
359         ND_PRINT((ndo, " rerr %s [items %u] [%u]:",
360             ap->rerr_flags & RERR_NODELETE ? "[D]" : "",
361             ap->rerr_dc, length));
362         dp6 = (const struct rerr_unreach6 *)(const void *)(ap + 1);
363         i = length - sizeof(*ap);
364         for (dc = ap->rerr_dc; dc != 0; dc--) {
365                 ND_TCHECK(*dp6);
366                 if (i < sizeof(*dp6))
367                         goto trunc;
368                 ND_PRINT((ndo, " {%s}(%ld)", ip6addr_string(ndo, &dp6->u_da),
369                     (unsigned long)EXTRACT_32BITS(&dp6->u_ds)));
370                 dp6++;
371                 i -= sizeof(*dp6);
372         }
373         return;
374
375 trunc:
376         ND_PRINT((ndo, "[|rerr]"));
377 }
378
379 static void
380 aodv_v6_draft_01_rreq(netdissect_options *ndo, const u_char *dat, u_int length)
381 {
382         u_int i;
383         const struct aodv_rreq6_draft_01 *ap = (const struct aodv_rreq6_draft_01 *)dat;
384
385         ND_TCHECK(*ap);
386         if (length < sizeof(*ap))
387                 goto trunc;
388         ND_PRINT((ndo, " rreq %u %s%s%s%s%shops %u id 0x%08lx\n"
389             "\tdst %s seq %lu src %s seq %lu", length,
390             ap->rreq_type & RREQ_JOIN ? "[J]" : "",
391             ap->rreq_type & RREQ_REPAIR ? "[R]" : "",
392             ap->rreq_type & RREQ_GRAT ? "[G]" : "",
393             ap->rreq_type & RREQ_DEST ? "[D]" : "",
394             ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
395             ap->rreq_hops,
396             (unsigned long)EXTRACT_32BITS(&ap->rreq_id),
397             ip6addr_string(ndo, &ap->rreq_da),
398             (unsigned long)EXTRACT_32BITS(&ap->rreq_ds),
399             ip6addr_string(ndo, &ap->rreq_oa),
400             (unsigned long)EXTRACT_32BITS(&ap->rreq_os)));
401         i = length - sizeof(*ap);
402         if (i >= sizeof(struct aodv_ext))
403                 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
404         return;
405
406 trunc:
407         ND_PRINT((ndo, " [|rreq"));
408 }
409
410 static void
411 aodv_v6_draft_01_rrep(netdissect_options *ndo, const u_char *dat, u_int length)
412 {
413         u_int i;
414         const struct aodv_rrep6_draft_01 *ap = (const struct aodv_rrep6_draft_01 *)dat;
415
416         ND_TCHECK(*ap);
417         if (length < sizeof(*ap))
418                 goto trunc;
419         ND_PRINT((ndo, " rrep %u %s%sprefix %u hops %u\n"
420            "\tdst %s dseq %lu src %s %lu ms", length,
421             ap->rrep_type & RREP_REPAIR ? "[R]" : "",
422             ap->rrep_type & RREP_ACK ? "[A] " : " ",
423             ap->rrep_ps & RREP_PREFIX_MASK,
424             ap->rrep_hops,
425             ip6addr_string(ndo, &ap->rrep_da),
426             (unsigned long)EXTRACT_32BITS(&ap->rrep_ds),
427             ip6addr_string(ndo, &ap->rrep_oa),
428             (unsigned long)EXTRACT_32BITS(&ap->rrep_life)));
429         i = length - sizeof(*ap);
430         if (i >= sizeof(struct aodv_ext))
431                 aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
432         return;
433
434 trunc:
435         ND_PRINT((ndo, " [|rreq"));
436 }
437
438 static void
439 aodv_v6_draft_01_rerr(netdissect_options *ndo, const u_char *dat, u_int length)
440 {
441         u_int i, dc;
442         const struct aodv_rerr *ap = (const struct aodv_rerr *)dat;
443         const struct rerr_unreach6_draft_01 *dp6;
444
445         ND_TCHECK(*ap);
446         if (length < sizeof(*ap))
447                 goto trunc;
448         ND_PRINT((ndo, " rerr %s [items %u] [%u]:",
449             ap->rerr_flags & RERR_NODELETE ? "[D]" : "",
450             ap->rerr_dc, length));
451         dp6 = (const struct rerr_unreach6_draft_01 *)(const void *)(ap + 1);
452         i = length - sizeof(*ap);
453         for (dc = ap->rerr_dc; dc != 0; dc--) {
454                 ND_TCHECK(*dp6);
455                 if (i < sizeof(*dp6))
456                         goto trunc;
457                 ND_PRINT((ndo, " {%s}(%ld)", ip6addr_string(ndo, &dp6->u_da),
458                     (unsigned long)EXTRACT_32BITS(&dp6->u_ds)));
459                 dp6++;
460                 i -= sizeof(*dp6);
461         }
462         return;
463
464 trunc:
465         ND_PRINT((ndo, "[|rerr]"));
466 }
467
468 void
469 aodv_print(netdissect_options *ndo,
470            const u_char *dat, u_int length, int is_ip6)
471 {
472         uint8_t msg_type;
473
474         /*
475          * The message type is the first byte; make sure we have it
476          * and then fetch it.
477          */
478         ND_TCHECK(*dat);
479         msg_type = *dat;
480         ND_PRINT((ndo, " aodv"));
481
482         switch (msg_type) {
483
484         case AODV_RREQ:
485                 if (is_ip6)
486                         aodv_v6_rreq(ndo, dat, length);
487                 else
488                         aodv_rreq(ndo, dat, length);
489                 break;
490
491         case AODV_RREP:
492                 if (is_ip6)
493                         aodv_v6_rrep(ndo, dat, length);
494                 else
495                         aodv_rrep(ndo, dat, length);
496                 break;
497
498         case AODV_RERR:
499                 if (is_ip6)
500                         aodv_v6_rerr(ndo, dat, length);
501                 else
502                         aodv_rerr(ndo, dat, length);
503                 break;
504
505         case AODV_RREP_ACK:
506                 ND_PRINT((ndo, " rrep-ack %u", length));
507                 break;
508
509         case AODV_V6_DRAFT_01_RREQ:
510                 aodv_v6_draft_01_rreq(ndo, dat, length);
511                 break;
512
513         case AODV_V6_DRAFT_01_RREP:
514                 aodv_v6_draft_01_rrep(ndo, dat, length);
515                 break;
516
517         case AODV_V6_DRAFT_01_RERR:
518                 aodv_v6_draft_01_rerr(ndo, dat, length);
519                 break;
520
521         case AODV_V6_DRAFT_01_RREP_ACK:
522                 ND_PRINT((ndo, " rrep-ack %u", length));
523                 break;
524
525         default:
526                 ND_PRINT((ndo, " type %u %u", msg_type, length));
527         }
528         return;
529
530 trunc:
531         ND_PRINT((ndo, " [|aodv]"));
532 }