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 #ifndef lint
34 static const char rcsid[] _U_ =
35 "@(#) $Header: /tcpdump/master/tcpdump/print-aodv.c,v 1.11 2004/03/24 00:30:19 guy Exp $ (LBL)";
36 #endif
37
38 #ifdef HAVE_CONFIG_H
39 #include "config.h"
40 #endif
41
42 #include <tcpdump-stdinc.h>
43
44 #include <stddef.h>
45 #include <stdio.h>
46 #include <ctype.h>
47 #include <string.h>
48
49 #include "interface.h"
50 #include "addrtoname.h"
51 #include "extract.h" /* must come after interface.h */
52
53 #include "aodv.h"
54
55 static void
aodv_extension(const struct aodv_ext * ep,u_int length)56 aodv_extension(const struct aodv_ext *ep, u_int length)
57 {
58 u_int i;
59 const struct aodv_hello *ah;
60
61 switch (ep->type) {
62 case AODV_EXT_HELLO:
63 if (snapend < (u_char *) ep) {
64 printf(" [|hello]");
65 return;
66 }
67 i = min(length, (u_int)(snapend - (u_char *)ep));
68 if (i < sizeof(struct aodv_hello)) {
69 printf(" [|hello]");
70 return;
71 }
72 i -= sizeof(struct aodv_hello);
73 ah = (void *)ep;
74 printf("\n\text HELLO %ld ms",
75 (unsigned long)EXTRACT_32BITS(&ah->interval));
76 break;
77
78 default:
79 printf("\n\text %u %u", ep->type, ep->length);
80 break;
81 }
82 }
83
84 static void
aodv_rreq(const union aodv * ap,const u_char * dat,u_int length)85 aodv_rreq(const union aodv *ap, const u_char *dat, u_int length)
86 {
87 u_int i;
88
89 if (snapend < dat) {
90 printf(" [|aodv]");
91 return;
92 }
93 i = min(length, (u_int)(snapend - dat));
94 if (i < sizeof(ap->rreq)) {
95 printf(" [|rreq]");
96 return;
97 }
98 i -= sizeof(ap->rreq);
99 printf(" rreq %u %s%s%s%s%shops %u id 0x%08lx\n"
100 "\tdst %s seq %lu src %s seq %lu", length,
101 ap->rreq.rreq_type & RREQ_JOIN ? "[J]" : "",
102 ap->rreq.rreq_type & RREQ_REPAIR ? "[R]" : "",
103 ap->rreq.rreq_type & RREQ_GRAT ? "[G]" : "",
104 ap->rreq.rreq_type & RREQ_DEST ? "[D]" : "",
105 ap->rreq.rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
106 ap->rreq.rreq_hops,
107 (unsigned long)EXTRACT_32BITS(&ap->rreq.rreq_id),
108 ipaddr_string(&ap->rreq.rreq_da),
109 (unsigned long)EXTRACT_32BITS(&ap->rreq.rreq_ds),
110 ipaddr_string(&ap->rreq.rreq_oa),
111 (unsigned long)EXTRACT_32BITS(&ap->rreq.rreq_os));
112 if (i >= sizeof(struct aodv_ext))
113 aodv_extension((void *)(&ap->rreq + 1), i);
114 }
115
116 static void
aodv_rrep(const union aodv * ap,const u_char * dat,u_int length)117 aodv_rrep(const union aodv *ap, const u_char *dat, u_int length)
118 {
119 u_int i;
120
121 if (snapend < dat) {
122 printf(" [|aodv]");
123 return;
124 }
125 i = min(length, (u_int)(snapend - dat));
126 if (i < sizeof(ap->rrep)) {
127 printf(" [|rrep]");
128 return;
129 }
130 i -= sizeof(ap->rrep);
131 printf(" rrep %u %s%sprefix %u hops %u\n"
132 "\tdst %s dseq %lu src %s %lu ms", length,
133 ap->rrep.rrep_type & RREP_REPAIR ? "[R]" : "",
134 ap->rrep.rrep_type & RREP_ACK ? "[A] " : " ",
135 ap->rrep.rrep_ps & RREP_PREFIX_MASK,
136 ap->rrep.rrep_hops,
137 ipaddr_string(&ap->rrep.rrep_da),
138 (unsigned long)EXTRACT_32BITS(&ap->rrep.rrep_ds),
139 ipaddr_string(&ap->rrep.rrep_oa),
140 (unsigned long)EXTRACT_32BITS(&ap->rrep.rrep_life));
141 if (i >= sizeof(struct aodv_ext))
142 aodv_extension((void *)(&ap->rrep + 1), i);
143 }
144
145 static void
aodv_rerr(const union aodv * ap,const u_char * dat,u_int length)146 aodv_rerr(const union aodv *ap, const u_char *dat, u_int length)
147 {
148 u_int i;
149 const struct rerr_unreach *dp = NULL;
150 int n, trunc;
151
152 if (snapend < dat) {
153 printf(" [|aodv]");
154 return;
155 }
156 i = min(length, (u_int)(snapend - dat));
157 if (i < offsetof(struct aodv_rerr, r)) {
158 printf(" [|rerr]");
159 return;
160 }
161 i -= offsetof(struct aodv_rerr, r);
162 dp = &ap->rerr.r.dest[0];
163 n = ap->rerr.rerr_dc * sizeof(ap->rerr.r.dest[0]);
164 printf(" rerr %s [items %u] [%u]:",
165 ap->rerr.rerr_flags & RERR_NODELETE ? "[D]" : "",
166 ap->rerr.rerr_dc, length);
167 trunc = n - (i/sizeof(ap->rerr.r.dest[0]));
168 for (; i >= sizeof(ap->rerr.r.dest[0]);
169 ++dp, i -= sizeof(ap->rerr.r.dest[0])) {
170 printf(" {%s}(%ld)", ipaddr_string(&dp->u_da),
171 (unsigned long)EXTRACT_32BITS(&dp->u_ds));
172 }
173 if (trunc)
174 printf("[|rerr]");
175 }
176
177 static void
178 #ifdef INET6
aodv_v6_rreq(const union aodv * ap,const u_char * dat,u_int length)179 aodv_v6_rreq(const union aodv *ap, const u_char *dat, u_int length)
180 #else
181 aodv_v6_rreq(const union aodv *ap _U_, const u_char *dat _U_, u_int length)
182 #endif
183 {
184 #ifdef INET6
185 u_int i;
186
187 if (snapend < dat) {
188 printf(" [|aodv]");
189 return;
190 }
191 i = min(length, (u_int)(snapend - dat));
192 if (i < sizeof(ap->rreq6)) {
193 printf(" [|rreq6]");
194 return;
195 }
196 i -= sizeof(ap->rreq6);
197 printf(" v6 rreq %u %s%s%s%s%shops %u id 0x%08lx\n"
198 "\tdst %s seq %lu src %s seq %lu", length,
199 ap->rreq6.rreq_type & RREQ_JOIN ? "[J]" : "",
200 ap->rreq6.rreq_type & RREQ_REPAIR ? "[R]" : "",
201 ap->rreq6.rreq_type & RREQ_GRAT ? "[G]" : "",
202 ap->rreq6.rreq_type & RREQ_DEST ? "[D]" : "",
203 ap->rreq6.rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
204 ap->rreq6.rreq_hops,
205 (unsigned long)EXTRACT_32BITS(&ap->rreq6.rreq_id),
206 ip6addr_string(&ap->rreq6.rreq_da),
207 (unsigned long)EXTRACT_32BITS(&ap->rreq6.rreq_ds),
208 ip6addr_string(&ap->rreq6.rreq_oa),
209 (unsigned long)EXTRACT_32BITS(&ap->rreq6.rreq_os));
210 if (i >= sizeof(struct aodv_ext))
211 aodv_extension((void *)(&ap->rreq6 + 1), i);
212 #else
213 printf(" v6 rreq %u", length);
214 #endif
215 }
216
217 static void
218 #ifdef INET6
aodv_v6_rrep(const union aodv * ap,const u_char * dat,u_int length)219 aodv_v6_rrep(const union aodv *ap, const u_char *dat, u_int length)
220 #else
221 aodv_v6_rrep(const union aodv *ap _U_, const u_char *dat _U_, u_int length)
222 #endif
223 {
224 #ifdef INET6
225 u_int i;
226
227 if (snapend < dat) {
228 printf(" [|aodv]");
229 return;
230 }
231 i = min(length, (u_int)(snapend - dat));
232 if (i < sizeof(ap->rrep6)) {
233 printf(" [|rrep6]");
234 return;
235 }
236 i -= sizeof(ap->rrep6);
237 printf(" rrep %u %s%sprefix %u hops %u\n"
238 "\tdst %s dseq %lu src %s %lu ms", length,
239 ap->rrep6.rrep_type & RREP_REPAIR ? "[R]" : "",
240 ap->rrep6.rrep_type & RREP_ACK ? "[A] " : " ",
241 ap->rrep6.rrep_ps & RREP_PREFIX_MASK,
242 ap->rrep6.rrep_hops,
243 ip6addr_string(&ap->rrep6.rrep_da),
244 (unsigned long)EXTRACT_32BITS(&ap->rrep6.rrep_ds),
245 ip6addr_string(&ap->rrep6.rrep_oa),
246 (unsigned long)EXTRACT_32BITS(&ap->rrep6.rrep_life));
247 if (i >= sizeof(struct aodv_ext))
248 aodv_extension((void *)(&ap->rrep6 + 1), i);
249 #else
250 printf(" rrep %u", length);
251 #endif
252 }
253
254 static void
255 #ifdef INET6
aodv_v6_rerr(const union aodv * ap,u_int length)256 aodv_v6_rerr(const union aodv *ap, u_int length)
257 #else
258 aodv_v6_rerr(const union aodv *ap _U_, u_int length)
259 #endif
260 {
261 #ifdef INET6
262 const struct rerr_unreach6 *dp6 = NULL;
263 int i, j, n, trunc;
264
265 i = length - offsetof(struct aodv_rerr, r);
266 j = sizeof(ap->rerr.r.dest6[0]);
267 dp6 = &ap->rerr.r.dest6[0];
268 n = ap->rerr.rerr_dc * j;
269 printf(" rerr %s [items %u] [%u]:",
270 ap->rerr.rerr_flags & RERR_NODELETE ? "[D]" : "",
271 ap->rerr.rerr_dc, length);
272 trunc = n - (i/j);
273 for (; i -= j >= 0; ++dp6) {
274 printf(" {%s}(%ld)", ip6addr_string(&dp6->u_da),
275 (unsigned long)EXTRACT_32BITS(&dp6->u_ds));
276 }
277 if (trunc)
278 printf("[|rerr]");
279 #else
280 printf(" rerr %u", length);
281 #endif
282 }
283
284 static void
285 #ifdef INET6
aodv_v6_draft_01_rreq(const union aodv * ap,const u_char * dat,u_int length)286 aodv_v6_draft_01_rreq(const union aodv *ap, const u_char *dat, u_int length)
287 #else
288 aodv_v6_draft_01_rreq(const union aodv *ap _U_, const u_char *dat _U_,
289 u_int length)
290 #endif
291 {
292 #ifdef INET6
293 u_int i;
294
295 if (snapend < dat) {
296 printf(" [|aodv]");
297 return;
298 }
299 i = min(length, (u_int)(snapend - dat));
300 if (i < sizeof(ap->rreq6_draft_01)) {
301 printf(" [|rreq6]");
302 return;
303 }
304 i -= sizeof(ap->rreq6_draft_01);
305 printf(" rreq %u %s%s%s%s%shops %u id 0x%08lx\n"
306 "\tdst %s seq %lu src %s seq %lu", length,
307 ap->rreq6_draft_01.rreq_type & RREQ_JOIN ? "[J]" : "",
308 ap->rreq6_draft_01.rreq_type & RREQ_REPAIR ? "[R]" : "",
309 ap->rreq6_draft_01.rreq_type & RREQ_GRAT ? "[G]" : "",
310 ap->rreq6_draft_01.rreq_type & RREQ_DEST ? "[D]" : "",
311 ap->rreq6_draft_01.rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
312 ap->rreq6_draft_01.rreq_hops,
313 (unsigned long)EXTRACT_32BITS(&ap->rreq6_draft_01.rreq_id),
314 ip6addr_string(&ap->rreq6_draft_01.rreq_da),
315 (unsigned long)EXTRACT_32BITS(&ap->rreq6_draft_01.rreq_ds),
316 ip6addr_string(&ap->rreq6_draft_01.rreq_oa),
317 (unsigned long)EXTRACT_32BITS(&ap->rreq6_draft_01.rreq_os));
318 if (i >= sizeof(struct aodv_ext))
319 aodv_extension((void *)(&ap->rreq6_draft_01 + 1), i);
320 #else
321 printf(" rreq %u", length);
322 #endif
323 }
324
325 static void
326 #ifdef INET6
aodv_v6_draft_01_rrep(const union aodv * ap,const u_char * dat,u_int length)327 aodv_v6_draft_01_rrep(const union aodv *ap, const u_char *dat, u_int length)
328 #else
329 aodv_v6_draft_01_rrep(const union aodv *ap _U_, const u_char *dat _U_,
330 u_int length)
331 #endif
332 {
333 #ifdef INET6
334 u_int i;
335
336 if (snapend < dat) {
337 printf(" [|aodv]");
338 return;
339 }
340 i = min(length, (u_int)(snapend - dat));
341 if (i < sizeof(ap->rrep6_draft_01)) {
342 printf(" [|rrep6]");
343 return;
344 }
345 i -= sizeof(ap->rrep6_draft_01);
346 printf(" rrep %u %s%sprefix %u hops %u\n"
347 "\tdst %s dseq %lu src %s %lu ms", length,
348 ap->rrep6_draft_01.rrep_type & RREP_REPAIR ? "[R]" : "",
349 ap->rrep6_draft_01.rrep_type & RREP_ACK ? "[A] " : " ",
350 ap->rrep6_draft_01.rrep_ps & RREP_PREFIX_MASK,
351 ap->rrep6_draft_01.rrep_hops,
352 ip6addr_string(&ap->rrep6_draft_01.rrep_da),
353 (unsigned long)EXTRACT_32BITS(&ap->rrep6_draft_01.rrep_ds),
354 ip6addr_string(&ap->rrep6_draft_01.rrep_oa),
355 (unsigned long)EXTRACT_32BITS(&ap->rrep6_draft_01.rrep_life));
356 if (i >= sizeof(struct aodv_ext))
357 aodv_extension((void *)(&ap->rrep6_draft_01 + 1), i);
358 #else
359 printf(" rrep %u", length);
360 #endif
361 }
362
363 static void
364 #ifdef INET6
aodv_v6_draft_01_rerr(const union aodv * ap,u_int length)365 aodv_v6_draft_01_rerr(const union aodv *ap, u_int length)
366 #else
367 aodv_v6_draft_01_rerr(const union aodv *ap _U_, u_int length)
368 #endif
369 {
370 #ifdef INET6
371 const struct rerr_unreach6_draft_01 *dp6 = NULL;
372 int i, j, n, trunc;
373
374 i = length - offsetof(struct aodv_rerr, r);
375 j = sizeof(ap->rerr.r.dest6_draft_01[0]);
376 dp6 = &ap->rerr.r.dest6_draft_01[0];
377 n = ap->rerr.rerr_dc * j;
378 printf(" rerr %s [items %u] [%u]:",
379 ap->rerr.rerr_flags & RERR_NODELETE ? "[D]" : "",
380 ap->rerr.rerr_dc, length);
381 trunc = n - (i/j);
382 for (; i -= j >= 0; ++dp6) {
383 printf(" {%s}(%ld)", ip6addr_string(&dp6->u_da),
384 (unsigned long)EXTRACT_32BITS(&dp6->u_ds));
385 }
386 if (trunc)
387 printf("[|rerr]");
388 #else
389 printf(" rerr %u", length);
390 #endif
391 }
392
393 void
aodv_print(const u_char * dat,u_int length,int is_ip6)394 aodv_print(const u_char *dat, u_int length, int is_ip6)
395 {
396 const union aodv *ap;
397
398 ap = (union aodv *)dat;
399 if (snapend < dat) {
400 printf(" [|aodv]");
401 return;
402 }
403 if (min(length, (u_int)(snapend - dat)) < sizeof(ap->rrep_ack)) {
404 printf(" [|aodv]");
405 return;
406 }
407 printf(" aodv");
408
409 switch (ap->rerr.rerr_type) {
410
411 case AODV_RREQ:
412 if (is_ip6)
413 aodv_v6_rreq(ap, dat, length);
414 else
415 aodv_rreq(ap, dat, length);
416 break;
417
418 case AODV_RREP:
419 if (is_ip6)
420 aodv_v6_rrep(ap, dat, length);
421 else
422 aodv_rrep(ap, dat, length);
423 break;
424
425 case AODV_RERR:
426 if (is_ip6)
427 aodv_v6_rerr(ap, length);
428 else
429 aodv_rerr(ap, dat, length);
430 break;
431
432 case AODV_RREP_ACK:
433 printf(" rrep-ack %u", length);
434 break;
435
436 case AODV_V6_DRAFT_01_RREQ:
437 aodv_v6_draft_01_rreq(ap, dat, length);
438 break;
439
440 case AODV_V6_DRAFT_01_RREP:
441 aodv_v6_draft_01_rrep(ap, dat, length);
442 break;
443
444 case AODV_V6_DRAFT_01_RERR:
445 aodv_v6_draft_01_rerr(ap, length);
446 break;
447
448 case AODV_V6_DRAFT_01_RREP_ACK:
449 printf(" rrep-ack %u", length);
450 break;
451
452 default:
453 printf(" %u %u", ap->rreq.rreq_type, length);
454 }
455 }
456