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
34static 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
55static void
56aodv_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
84static void
85aodv_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
116static void
117aodv_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
145static void
146aodv_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
177static void
178#ifdef INET6
179aodv_v6_rreq(const union aodv *ap, const u_char *dat, u_int length)
180#else
181aodv_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
217static void
218#ifdef INET6
219aodv_v6_rrep(const union aodv *ap, const u_char *dat, u_int length)
220#else
221aodv_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
254static void
255#ifdef INET6
256aodv_v6_rerr(const union aodv *ap, u_int length)
257#else
258aodv_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
284static void
285#ifdef INET6
286aodv_v6_draft_01_rreq(const union aodv *ap, const u_char *dat, u_int length)
287#else
288aodv_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
325static void
326#ifdef INET6
327aodv_v6_draft_01_rrep(const union aodv *ap, const u_char *dat, u_int length)
328#else
329aodv_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
363static void
364#ifdef INET6
365aodv_v6_draft_01_rerr(const union aodv *ap, u_int length)
366#else
367aodv_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
393void
394aodv_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