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