xref: /freebsd/contrib/tcpdump/print-aodv.c (revision ee67461e56828dd1f8de165947ba83f6d9148a87)
15b0fe478SBruce M Simpson /*
25b0fe478SBruce M Simpson  * Copyright (c) 2003 Bruce M. Simpson <bms@spc.org>
35b0fe478SBruce M Simpson  * All rights reserved.
45b0fe478SBruce M Simpson  *
55b0fe478SBruce M Simpson  * Redistribution and use in source and binary forms, with or without
65b0fe478SBruce M Simpson  * modification, are permitted provided that the following conditions
75b0fe478SBruce M Simpson  * are met:
85b0fe478SBruce M Simpson  * 1. Redistributions of source code must retain the above copyright
95b0fe478SBruce M Simpson  *    notice, this list of conditions and the following disclaimer.
105b0fe478SBruce M Simpson  * 2. Redistributions in binary form must reproduce the above copyright
115b0fe478SBruce M Simpson  *    notice, this list of conditions and the following disclaimer in the
125b0fe478SBruce M Simpson  *    documentation and/or other materials provided with the distribution.
135b0fe478SBruce M Simpson  * 3. All advertising materials mentioning features or use of this software
145b0fe478SBruce M Simpson  *    must display the following acknowledgement:
155b0fe478SBruce M Simpson  *        This product includes software developed by Bruce M. Simpson.
165b0fe478SBruce M Simpson  * 4. Neither the name of Bruce M. Simpson nor the names of co-
175b0fe478SBruce M Simpson  *    contributors may be used to endorse or promote products derived
185b0fe478SBruce M Simpson  *    from this software without specific prior written permission.
195b0fe478SBruce M Simpson  *
205b0fe478SBruce M Simpson  * THIS SOFTWARE IS PROVIDED BY Bruce M. Simpson AND CONTRIBUTORS
215b0fe478SBruce M Simpson  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
225b0fe478SBruce M Simpson  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
235b0fe478SBruce M Simpson  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL Bruce M. Simpson OR CONTRIBUTORS
245b0fe478SBruce M Simpson  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
255b0fe478SBruce M Simpson  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
265b0fe478SBruce M Simpson  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
275b0fe478SBruce M Simpson  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
285b0fe478SBruce M Simpson  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
295b0fe478SBruce M Simpson  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
305b0fe478SBruce M Simpson  * POSSIBILITY OF SUCH DAMAGE.
315b0fe478SBruce M Simpson  */
325b0fe478SBruce M Simpson 
333340d773SGleb Smirnoff /* \summary: Ad hoc On-Demand Distance Vector (AODV) Routing printer */
343340d773SGleb Smirnoff 
355b0fe478SBruce M Simpson #ifdef HAVE_CONFIG_H
36*ee67461eSJoseph Mingrone #include <config.h>
375b0fe478SBruce M Simpson #endif
385b0fe478SBruce M Simpson 
39*ee67461eSJoseph Mingrone #include "netdissect-stdinc.h"
405b0fe478SBruce M Simpson 
413340d773SGleb Smirnoff #include "netdissect.h"
425b0fe478SBruce M Simpson #include "addrtoname.h"
433340d773SGleb Smirnoff #include "extract.h"
445b0fe478SBruce M Simpson 
450bff6a5aSEd Maste /*
460bff6a5aSEd Maste  * RFC 3561
470bff6a5aSEd Maste  */
483c602fabSXin LI struct aodv_rreq {
49*ee67461eSJoseph Mingrone 	nd_uint8_t	rreq_type;	/* AODV message type (1) */
50*ee67461eSJoseph Mingrone 	nd_uint8_t	rreq_flags;	/* various flags */
51*ee67461eSJoseph Mingrone 	nd_uint8_t	rreq_zero0;	/* reserved, set to zero */
52*ee67461eSJoseph Mingrone 	nd_uint8_t	rreq_hops;	/* number of hops from originator */
53*ee67461eSJoseph Mingrone 	nd_uint32_t	rreq_id;	/* request ID */
54*ee67461eSJoseph Mingrone 	nd_ipv4		rreq_da;	/* destination IPv4 address */
55*ee67461eSJoseph Mingrone 	nd_uint32_t	rreq_ds;	/* destination sequence number */
56*ee67461eSJoseph Mingrone 	nd_ipv4		rreq_oa;	/* originator IPv4 address */
57*ee67461eSJoseph Mingrone 	nd_uint32_t	rreq_os;	/* originator sequence number */
583c602fabSXin LI };
593c602fabSXin LI struct aodv_rreq6 {
60*ee67461eSJoseph Mingrone 	nd_uint8_t	rreq_type;	/* AODV message type (1) */
61*ee67461eSJoseph Mingrone 	nd_uint8_t	rreq_flags;	/* various flags */
62*ee67461eSJoseph Mingrone 	nd_uint8_t	rreq_zero0;	/* reserved, set to zero */
63*ee67461eSJoseph Mingrone 	nd_uint8_t	rreq_hops;	/* number of hops from originator */
64*ee67461eSJoseph Mingrone 	nd_uint32_t	rreq_id;	/* request ID */
65*ee67461eSJoseph Mingrone 	nd_ipv6		rreq_da;	/* destination IPv6 address */
66*ee67461eSJoseph Mingrone 	nd_uint32_t	rreq_ds;	/* destination sequence number */
67*ee67461eSJoseph Mingrone 	nd_ipv6		rreq_oa;	/* originator IPv6 address */
68*ee67461eSJoseph Mingrone 	nd_uint32_t	rreq_os;	/* originator sequence number */
693c602fabSXin LI };
703c602fabSXin LI struct aodv_rreq6_draft_01 {
71*ee67461eSJoseph Mingrone 	nd_uint8_t	rreq_type;	/* AODV message type (16) */
72*ee67461eSJoseph Mingrone 	nd_uint8_t	rreq_flags;	/* various flags */
73*ee67461eSJoseph Mingrone 	nd_uint8_t	rreq_zero0;	/* reserved, set to zero */
74*ee67461eSJoseph Mingrone 	nd_uint8_t	rreq_hops;	/* number of hops from originator */
75*ee67461eSJoseph Mingrone 	nd_uint32_t	rreq_id;	/* request ID */
76*ee67461eSJoseph Mingrone 	nd_uint32_t	rreq_ds;	/* destination sequence number */
77*ee67461eSJoseph Mingrone 	nd_uint32_t	rreq_os;	/* originator sequence number */
78*ee67461eSJoseph Mingrone 	nd_ipv6		rreq_da;	/* destination IPv6 address */
79*ee67461eSJoseph Mingrone 	nd_ipv6		rreq_oa;	/* originator IPv6 address */
803c602fabSXin LI };
813c602fabSXin LI 
823c602fabSXin LI #define	RREQ_JOIN	0x80		/* join (reserved for multicast */
833c602fabSXin LI #define	RREQ_REPAIR	0x40		/* repair (reserved for multicast */
843c602fabSXin LI #define	RREQ_GRAT	0x20		/* gratuitous RREP */
853c602fabSXin LI #define	RREQ_DEST	0x10		/* destination only */
863c602fabSXin LI #define	RREQ_UNKNOWN	0x08		/* unknown destination sequence num */
873c602fabSXin LI #define	RREQ_FLAGS_MASK	0xF8		/* mask for rreq_flags */
883c602fabSXin LI 
893c602fabSXin LI struct aodv_rrep {
90*ee67461eSJoseph Mingrone 	nd_uint8_t	rrep_type;	/* AODV message type (2) */
91*ee67461eSJoseph Mingrone 	nd_uint8_t	rrep_flags;	/* various flags */
92*ee67461eSJoseph Mingrone 	nd_uint8_t	rrep_ps;	/* prefix size */
93*ee67461eSJoseph Mingrone 	nd_uint8_t	rrep_hops;	/* number of hops from o to d */
94*ee67461eSJoseph Mingrone 	nd_ipv4		rrep_da;	/* destination IPv4 address */
95*ee67461eSJoseph Mingrone 	nd_uint32_t	rrep_ds;	/* destination sequence number */
96*ee67461eSJoseph Mingrone 	nd_ipv4		rrep_oa;	/* originator IPv4 address */
97*ee67461eSJoseph Mingrone 	nd_uint32_t	rrep_life;	/* lifetime of this route */
983c602fabSXin LI };
993c602fabSXin LI struct aodv_rrep6 {
100*ee67461eSJoseph Mingrone 	nd_uint8_t	rrep_type;	/* AODV message type (2) */
101*ee67461eSJoseph Mingrone 	nd_uint8_t	rrep_flags;	/* various flags */
102*ee67461eSJoseph Mingrone 	nd_uint8_t	rrep_ps;	/* prefix size */
103*ee67461eSJoseph Mingrone 	nd_uint8_t	rrep_hops;	/* number of hops from o to d */
104*ee67461eSJoseph Mingrone 	nd_ipv6		rrep_da;	/* destination IPv6 address */
105*ee67461eSJoseph Mingrone 	nd_uint32_t	rrep_ds;	/* destination sequence number */
106*ee67461eSJoseph Mingrone 	nd_ipv6		rrep_oa;	/* originator IPv6 address */
107*ee67461eSJoseph Mingrone 	nd_uint32_t	rrep_life;	/* lifetime of this route */
1083c602fabSXin LI };
1093c602fabSXin LI struct aodv_rrep6_draft_01 {
110*ee67461eSJoseph Mingrone 	nd_uint8_t	rrep_type;	/* AODV message type (17) */
111*ee67461eSJoseph Mingrone 	nd_uint8_t	rrep_flags;	/* various flags */
112*ee67461eSJoseph Mingrone 	nd_uint8_t	rrep_ps;	/* prefix size */
113*ee67461eSJoseph Mingrone 	nd_uint8_t	rrep_hops;	/* number of hops from o to d */
114*ee67461eSJoseph Mingrone 	nd_uint32_t	rrep_ds;	/* destination sequence number */
115*ee67461eSJoseph Mingrone 	nd_ipv6		rrep_da;	/* destination IPv6 address */
116*ee67461eSJoseph Mingrone 	nd_ipv6		rrep_oa;	/* originator IPv6 address */
117*ee67461eSJoseph Mingrone 	nd_uint32_t	rrep_life;	/* lifetime of this route */
1183c602fabSXin LI };
1193c602fabSXin LI 
1203c602fabSXin LI #define	RREP_REPAIR		0x80	/* repair (reserved for multicast */
1213c602fabSXin LI #define	RREP_ACK		0x40	/* acknowledgement required */
1223c602fabSXin LI #define	RREP_FLAGS_MASK		0xC0	/* mask for rrep_flags */
1233c602fabSXin LI #define	RREP_PREFIX_MASK	0x1F	/* mask for prefix size */
1243c602fabSXin LI 
1253c602fabSXin LI struct rerr_unreach {
126*ee67461eSJoseph Mingrone 	nd_ipv4		u_da;	/* IPv4 address */
127*ee67461eSJoseph Mingrone 	nd_uint32_t	u_ds;	/* sequence number */
1283c602fabSXin LI };
1293c602fabSXin LI struct rerr_unreach6 {
130*ee67461eSJoseph Mingrone 	nd_ipv6		u_da;	/* IPv6 address */
131*ee67461eSJoseph Mingrone 	nd_uint32_t	u_ds;	/* sequence number */
1323c602fabSXin LI };
1333c602fabSXin LI struct rerr_unreach6_draft_01 {
134*ee67461eSJoseph Mingrone 	nd_ipv6		u_da;	/* IPv6 address */
135*ee67461eSJoseph Mingrone 	nd_uint32_t	u_ds;	/* sequence number */
1363c602fabSXin LI };
1373c602fabSXin LI 
1383c602fabSXin LI struct aodv_rerr {
139*ee67461eSJoseph Mingrone 	nd_uint8_t	rerr_type;	/* AODV message type (3 or 18) */
140*ee67461eSJoseph Mingrone 	nd_uint8_t	rerr_flags;	/* various flags */
141*ee67461eSJoseph Mingrone 	nd_uint8_t	rerr_zero0;	/* reserved, set to zero */
142*ee67461eSJoseph Mingrone 	nd_uint8_t	rerr_dc;	/* destination count */
1433c602fabSXin LI };
1443c602fabSXin LI 
1453c602fabSXin LI #define RERR_NODELETE		0x80	/* don't delete the link */
1463c602fabSXin LI #define RERR_FLAGS_MASK		0x80	/* mask for rerr_flags */
1473c602fabSXin LI 
1483c602fabSXin LI struct aodv_rrep_ack {
149*ee67461eSJoseph Mingrone 	nd_uint8_t	ra_type;
150*ee67461eSJoseph Mingrone 	nd_uint8_t	ra_zero0;
1513c602fabSXin LI };
1523c602fabSXin LI 
1533c602fabSXin LI #define	AODV_RREQ		1	/* route request */
1543c602fabSXin LI #define	AODV_RREP		2	/* route response */
1553c602fabSXin LI #define	AODV_RERR		3	/* error report */
1563c602fabSXin LI #define	AODV_RREP_ACK		4	/* route response acknowledgement */
1573c602fabSXin LI 
1583c602fabSXin LI #define AODV_V6_DRAFT_01_RREQ		16	/* IPv6 route request */
1593c602fabSXin LI #define AODV_V6_DRAFT_01_RREP		17	/* IPv6 route response */
1603c602fabSXin LI #define AODV_V6_DRAFT_01_RERR		18	/* IPv6 error report */
1613c602fabSXin LI #define AODV_V6_DRAFT_01_RREP_ACK	19	/* IPV6 route response acknowledgment */
1623c602fabSXin LI 
1633c602fabSXin LI struct aodv_ext {
164*ee67461eSJoseph Mingrone 	nd_uint8_t	type;		/* extension type */
165*ee67461eSJoseph Mingrone 	nd_uint8_t	length;		/* extension length */
1663c602fabSXin LI };
1673c602fabSXin LI 
1683c602fabSXin LI struct aodv_hello {
1693c602fabSXin LI 	struct	aodv_ext	eh;		/* extension header */
170*ee67461eSJoseph Mingrone 	nd_uint32_t		interval;	/* expect my next hello in
1713c602fabSXin LI 						 * (n) ms
1723c602fabSXin LI 						 * NOTE: this is not aligned */
1733c602fabSXin LI };
1743c602fabSXin LI 
1753c602fabSXin LI #define	AODV_EXT_HELLO	1
1765b0fe478SBruce M Simpson 
1775b0fe478SBruce M Simpson static void
1783c602fabSXin LI aodv_extension(netdissect_options *ndo,
1793c602fabSXin LI                const struct aodv_ext *ep, u_int length)
1805b0fe478SBruce M Simpson {
1815b0fe478SBruce M Simpson 	const struct aodv_hello *ah;
1825b0fe478SBruce M Simpson 
183*ee67461eSJoseph Mingrone 	ND_TCHECK_SIZE(ep);
184*ee67461eSJoseph Mingrone 	switch (GET_U_1(ep->type)) {
1855b0fe478SBruce M Simpson 	case AODV_EXT_HELLO:
1868bdc5a62SPatrick Kelsey 		ah = (const struct aodv_hello *)(const void *)ep;
187*ee67461eSJoseph Mingrone 		ND_TCHECK_SIZE(ah);
1888bdc5a62SPatrick Kelsey 		if (length < sizeof(struct aodv_hello))
1898bdc5a62SPatrick Kelsey 			goto trunc;
190*ee67461eSJoseph Mingrone 		if (GET_U_1(ep->length) < 4) {
191*ee67461eSJoseph Mingrone 			ND_PRINT("\n\text HELLO - bad length %u",
192*ee67461eSJoseph Mingrone 				 GET_U_1(ep->length));
1930bff6a5aSEd Maste 			break;
1940bff6a5aSEd Maste 		}
195*ee67461eSJoseph Mingrone 		ND_PRINT("\n\text HELLO %u ms",
196*ee67461eSJoseph Mingrone 		    GET_BE_U_4(ah->interval));
1975b0fe478SBruce M Simpson 		break;
1985b0fe478SBruce M Simpson 
1995b0fe478SBruce M Simpson 	default:
200*ee67461eSJoseph Mingrone 		ND_PRINT("\n\text %u %u", GET_U_1(ep->type),
201*ee67461eSJoseph Mingrone 			 GET_U_1(ep->length));
2025b0fe478SBruce M Simpson 		break;
2035b0fe478SBruce M Simpson 	}
2048bdc5a62SPatrick Kelsey 	return;
2058bdc5a62SPatrick Kelsey 
2068bdc5a62SPatrick Kelsey trunc:
207*ee67461eSJoseph Mingrone 	nd_print_trunc(ndo);
2085b0fe478SBruce M Simpson }
2095b0fe478SBruce M Simpson 
2105b0fe478SBruce M Simpson static void
2118bdc5a62SPatrick Kelsey aodv_rreq(netdissect_options *ndo, const u_char *dat, u_int length)
2125b0fe478SBruce M Simpson {
2135b0fe478SBruce M Simpson 	u_int i;
2148bdc5a62SPatrick Kelsey 	const struct aodv_rreq *ap = (const struct aodv_rreq *)dat;
2155b0fe478SBruce M Simpson 
216*ee67461eSJoseph Mingrone 	ND_TCHECK_SIZE(ap);
2178bdc5a62SPatrick Kelsey 	if (length < sizeof(*ap))
2188bdc5a62SPatrick Kelsey 		goto trunc;
219*ee67461eSJoseph Mingrone 	ND_PRINT(" rreq %u %s%s%s%s%shops %u id 0x%08x\n"
220*ee67461eSJoseph Mingrone 	    "\tdst %s seq %u src %s seq %u", length,
221*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rreq_type) & RREQ_JOIN ? "[J]" : "",
222*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rreq_type) & RREQ_REPAIR ? "[R]" : "",
223*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rreq_type) & RREQ_GRAT ? "[G]" : "",
224*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rreq_type) & RREQ_DEST ? "[D]" : "",
225*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rreq_type) & RREQ_UNKNOWN ? "[U] " : " ",
226*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rreq_hops),
227*ee67461eSJoseph Mingrone 	    GET_BE_U_4(ap->rreq_id),
228*ee67461eSJoseph Mingrone 	    GET_IPADDR_STRING(ap->rreq_da),
229*ee67461eSJoseph Mingrone 	    GET_BE_U_4(ap->rreq_ds),
230*ee67461eSJoseph Mingrone 	    GET_IPADDR_STRING(ap->rreq_oa),
231*ee67461eSJoseph Mingrone 	    GET_BE_U_4(ap->rreq_os));
2328bdc5a62SPatrick Kelsey 	i = length - sizeof(*ap);
2335b0fe478SBruce M Simpson 	if (i >= sizeof(struct aodv_ext))
2348bdc5a62SPatrick Kelsey 		aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
2358bdc5a62SPatrick Kelsey 	return;
2368bdc5a62SPatrick Kelsey 
2378bdc5a62SPatrick Kelsey trunc:
238*ee67461eSJoseph Mingrone 	nd_print_trunc(ndo);
2395b0fe478SBruce M Simpson }
2405b0fe478SBruce M Simpson 
2415b0fe478SBruce M Simpson static void
2428bdc5a62SPatrick Kelsey aodv_rrep(netdissect_options *ndo, const u_char *dat, u_int length)
2435b0fe478SBruce M Simpson {
2445b0fe478SBruce M Simpson 	u_int i;
2458bdc5a62SPatrick Kelsey 	const struct aodv_rrep *ap = (const struct aodv_rrep *)dat;
2465b0fe478SBruce M Simpson 
247*ee67461eSJoseph Mingrone 	ND_TCHECK_SIZE(ap);
2488bdc5a62SPatrick Kelsey 	if (length < sizeof(*ap))
2498bdc5a62SPatrick Kelsey 		goto trunc;
250*ee67461eSJoseph Mingrone 	ND_PRINT(" rrep %u %s%sprefix %u hops %u\n"
251*ee67461eSJoseph Mingrone 	    "\tdst %s dseq %u src %s %u ms", length,
252*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rrep_type) & RREP_REPAIR ? "[R]" : "",
253*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rrep_type) & RREP_ACK ? "[A] " : " ",
254*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rrep_ps) & RREP_PREFIX_MASK,
255*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rrep_hops),
256*ee67461eSJoseph Mingrone 	    GET_IPADDR_STRING(ap->rrep_da),
257*ee67461eSJoseph Mingrone 	    GET_BE_U_4(ap->rrep_ds),
258*ee67461eSJoseph Mingrone 	    GET_IPADDR_STRING(ap->rrep_oa),
259*ee67461eSJoseph Mingrone 	    GET_BE_U_4(ap->rrep_life));
2608bdc5a62SPatrick Kelsey 	i = length - sizeof(*ap);
2615b0fe478SBruce M Simpson 	if (i >= sizeof(struct aodv_ext))
2628bdc5a62SPatrick Kelsey 		aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
2638bdc5a62SPatrick Kelsey 	return;
2648bdc5a62SPatrick Kelsey 
2658bdc5a62SPatrick Kelsey trunc:
266*ee67461eSJoseph Mingrone 	nd_print_trunc(ndo);
2675b0fe478SBruce M Simpson }
2685b0fe478SBruce M Simpson 
2695b0fe478SBruce M Simpson static void
2708bdc5a62SPatrick Kelsey aodv_rerr(netdissect_options *ndo, const u_char *dat, u_int length)
2715b0fe478SBruce M Simpson {
2728bdc5a62SPatrick Kelsey 	u_int i, dc;
2738bdc5a62SPatrick Kelsey 	const struct aodv_rerr *ap = (const struct aodv_rerr *)dat;
2748bdc5a62SPatrick Kelsey 	const struct rerr_unreach *dp;
2755b0fe478SBruce M Simpson 
276*ee67461eSJoseph Mingrone 	ND_TCHECK_SIZE(ap);
2778bdc5a62SPatrick Kelsey 	if (length < sizeof(*ap))
2788bdc5a62SPatrick Kelsey 		goto trunc;
279*ee67461eSJoseph Mingrone 	ND_PRINT(" rerr %s [items %u] [%u]:",
280*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rerr_flags) & RERR_NODELETE ? "[D]" : "",
281*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rerr_dc), length);
2823340d773SGleb Smirnoff 	dp = (const struct rerr_unreach *)(dat + sizeof(*ap));
2838bdc5a62SPatrick Kelsey 	i = length - sizeof(*ap);
284*ee67461eSJoseph Mingrone 	for (dc = GET_U_1(ap->rerr_dc); dc != 0; dc--) {
285*ee67461eSJoseph Mingrone 		ND_TCHECK_SIZE(dp);
2868bdc5a62SPatrick Kelsey 		if (i < sizeof(*dp))
2878bdc5a62SPatrick Kelsey 			goto trunc;
288*ee67461eSJoseph Mingrone 		ND_PRINT(" {%s}(%u)", GET_IPADDR_STRING(dp->u_da),
289*ee67461eSJoseph Mingrone 		    GET_BE_U_4(dp->u_ds));
2908bdc5a62SPatrick Kelsey 		dp++;
2918bdc5a62SPatrick Kelsey 		i -= sizeof(*dp);
2925b0fe478SBruce M Simpson 	}
2938bdc5a62SPatrick Kelsey 	return;
2948bdc5a62SPatrick Kelsey 
2958bdc5a62SPatrick Kelsey trunc:
296*ee67461eSJoseph Mingrone 	nd_print_trunc(ndo);
2975b0fe478SBruce M Simpson }
2985b0fe478SBruce M Simpson 
2995b0fe478SBruce M Simpson static void
3008bdc5a62SPatrick Kelsey aodv_v6_rreq(netdissect_options *ndo, const u_char *dat, u_int length)
3015b0fe478SBruce M Simpson {
3025b0fe478SBruce M Simpson 	u_int i;
3038bdc5a62SPatrick Kelsey 	const struct aodv_rreq6 *ap = (const struct aodv_rreq6 *)dat;
3045b0fe478SBruce M Simpson 
305*ee67461eSJoseph Mingrone 	ND_TCHECK_SIZE(ap);
3068bdc5a62SPatrick Kelsey 	if (length < sizeof(*ap))
3078bdc5a62SPatrick Kelsey 		goto trunc;
308*ee67461eSJoseph Mingrone 	ND_PRINT(" v6 rreq %u %s%s%s%s%shops %u id 0x%08x\n"
309*ee67461eSJoseph Mingrone 	    "\tdst %s seq %u src %s seq %u", length,
310*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rreq_type) & RREQ_JOIN ? "[J]" : "",
311*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rreq_type) & RREQ_REPAIR ? "[R]" : "",
312*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rreq_type) & RREQ_GRAT ? "[G]" : "",
313*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rreq_type) & RREQ_DEST ? "[D]" : "",
314*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rreq_type) & RREQ_UNKNOWN ? "[U] " : " ",
315*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rreq_hops),
316*ee67461eSJoseph Mingrone 	    GET_BE_U_4(ap->rreq_id),
317*ee67461eSJoseph Mingrone 	    GET_IP6ADDR_STRING(ap->rreq_da),
318*ee67461eSJoseph Mingrone 	    GET_BE_U_4(ap->rreq_ds),
319*ee67461eSJoseph Mingrone 	    GET_IP6ADDR_STRING(ap->rreq_oa),
320*ee67461eSJoseph Mingrone 	    GET_BE_U_4(ap->rreq_os));
3218bdc5a62SPatrick Kelsey 	i = length - sizeof(*ap);
3225b0fe478SBruce M Simpson 	if (i >= sizeof(struct aodv_ext))
3238bdc5a62SPatrick Kelsey 		aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
3248bdc5a62SPatrick Kelsey 	return;
3258bdc5a62SPatrick Kelsey 
3268bdc5a62SPatrick Kelsey trunc:
327*ee67461eSJoseph Mingrone 	nd_print_trunc(ndo);
3285b0fe478SBruce M Simpson }
3295b0fe478SBruce M Simpson 
3305b0fe478SBruce M Simpson static void
3318bdc5a62SPatrick Kelsey aodv_v6_rrep(netdissect_options *ndo, const u_char *dat, u_int length)
3325b0fe478SBruce M Simpson {
3335b0fe478SBruce M Simpson 	u_int i;
3348bdc5a62SPatrick Kelsey 	const struct aodv_rrep6 *ap = (const struct aodv_rrep6 *)dat;
3355b0fe478SBruce M Simpson 
336*ee67461eSJoseph Mingrone 	ND_TCHECK_SIZE(ap);
3378bdc5a62SPatrick Kelsey 	if (length < sizeof(*ap))
3388bdc5a62SPatrick Kelsey 		goto trunc;
339*ee67461eSJoseph Mingrone 	ND_PRINT(" rrep %u %s%sprefix %u hops %u\n"
340*ee67461eSJoseph Mingrone 	   "\tdst %s dseq %u src %s %u ms", length,
341*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rrep_type) & RREP_REPAIR ? "[R]" : "",
342*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rrep_type) & RREP_ACK ? "[A] " : " ",
343*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rrep_ps) & RREP_PREFIX_MASK,
344*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rrep_hops),
345*ee67461eSJoseph Mingrone 	    GET_IP6ADDR_STRING(ap->rrep_da),
346*ee67461eSJoseph Mingrone 	    GET_BE_U_4(ap->rrep_ds),
347*ee67461eSJoseph Mingrone 	    GET_IP6ADDR_STRING(ap->rrep_oa),
348*ee67461eSJoseph Mingrone 	    GET_BE_U_4(ap->rrep_life));
3498bdc5a62SPatrick Kelsey 	i = length - sizeof(*ap);
3505b0fe478SBruce M Simpson 	if (i >= sizeof(struct aodv_ext))
3518bdc5a62SPatrick Kelsey 		aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
3528bdc5a62SPatrick Kelsey 	return;
3538bdc5a62SPatrick Kelsey 
3548bdc5a62SPatrick Kelsey trunc:
355*ee67461eSJoseph Mingrone 	nd_print_trunc(ndo);
3565b0fe478SBruce M Simpson }
3575b0fe478SBruce M Simpson 
3585b0fe478SBruce M Simpson static void
3598bdc5a62SPatrick Kelsey aodv_v6_rerr(netdissect_options *ndo, const u_char *dat, u_int length)
3605b0fe478SBruce M Simpson {
3618bdc5a62SPatrick Kelsey 	u_int i, dc;
3628bdc5a62SPatrick Kelsey 	const struct aodv_rerr *ap = (const struct aodv_rerr *)dat;
3638bdc5a62SPatrick Kelsey 	const struct rerr_unreach6 *dp6;
3645b0fe478SBruce M Simpson 
365*ee67461eSJoseph Mingrone 	ND_TCHECK_SIZE(ap);
3668bdc5a62SPatrick Kelsey 	if (length < sizeof(*ap))
3678bdc5a62SPatrick Kelsey 		goto trunc;
368*ee67461eSJoseph Mingrone 	ND_PRINT(" rerr %s [items %u] [%u]:",
369*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rerr_flags) & RERR_NODELETE ? "[D]" : "",
370*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rerr_dc), length);
3713340d773SGleb Smirnoff 	dp6 = (const struct rerr_unreach6 *)(const void *)(ap + 1);
3728bdc5a62SPatrick Kelsey 	i = length - sizeof(*ap);
373*ee67461eSJoseph Mingrone 	for (dc = GET_U_1(ap->rerr_dc); dc != 0; dc--) {
374*ee67461eSJoseph Mingrone 		ND_TCHECK_SIZE(dp6);
3758bdc5a62SPatrick Kelsey 		if (i < sizeof(*dp6))
3768bdc5a62SPatrick Kelsey 			goto trunc;
377*ee67461eSJoseph Mingrone 		ND_PRINT(" {%s}(%u)", GET_IP6ADDR_STRING(dp6->u_da),
378*ee67461eSJoseph Mingrone 			 GET_BE_U_4(dp6->u_ds));
3798bdc5a62SPatrick Kelsey 		dp6++;
3808bdc5a62SPatrick Kelsey 		i -= sizeof(*dp6);
3815b0fe478SBruce M Simpson 	}
3828bdc5a62SPatrick Kelsey 	return;
3838bdc5a62SPatrick Kelsey 
3848bdc5a62SPatrick Kelsey trunc:
385*ee67461eSJoseph Mingrone 	nd_print_trunc(ndo);
3865b0fe478SBruce M Simpson }
3875b0fe478SBruce M Simpson 
3885b0fe478SBruce M Simpson static void
3898bdc5a62SPatrick Kelsey aodv_v6_draft_01_rreq(netdissect_options *ndo, const u_char *dat, u_int length)
3905b0fe478SBruce M Simpson {
3915b0fe478SBruce M Simpson 	u_int i;
3928bdc5a62SPatrick Kelsey 	const struct aodv_rreq6_draft_01 *ap = (const struct aodv_rreq6_draft_01 *)dat;
3935b0fe478SBruce M Simpson 
394*ee67461eSJoseph Mingrone 	ND_TCHECK_SIZE(ap);
3958bdc5a62SPatrick Kelsey 	if (length < sizeof(*ap))
3968bdc5a62SPatrick Kelsey 		goto trunc;
397*ee67461eSJoseph Mingrone 	ND_PRINT(" rreq %u %s%s%s%s%shops %u id 0x%08x\n"
398*ee67461eSJoseph Mingrone 	    "\tdst %s seq %u src %s seq %u", length,
399*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rreq_type) & RREQ_JOIN ? "[J]" : "",
400*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rreq_type) & RREQ_REPAIR ? "[R]" : "",
401*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rreq_type) & RREQ_GRAT ? "[G]" : "",
402*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rreq_type) & RREQ_DEST ? "[D]" : "",
403*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rreq_type) & RREQ_UNKNOWN ? "[U] " : " ",
404*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rreq_hops),
405*ee67461eSJoseph Mingrone 	    GET_BE_U_4(ap->rreq_id),
406*ee67461eSJoseph Mingrone 	    GET_IP6ADDR_STRING(ap->rreq_da),
407*ee67461eSJoseph Mingrone 	    GET_BE_U_4(ap->rreq_ds),
408*ee67461eSJoseph Mingrone 	    GET_IP6ADDR_STRING(ap->rreq_oa),
409*ee67461eSJoseph Mingrone 	    GET_BE_U_4(ap->rreq_os));
4108bdc5a62SPatrick Kelsey 	i = length - sizeof(*ap);
4115b0fe478SBruce M Simpson 	if (i >= sizeof(struct aodv_ext))
4128bdc5a62SPatrick Kelsey 		aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
4138bdc5a62SPatrick Kelsey 	return;
4148bdc5a62SPatrick Kelsey 
4158bdc5a62SPatrick Kelsey trunc:
416*ee67461eSJoseph Mingrone 	nd_print_trunc(ndo);
4175b0fe478SBruce M Simpson }
4185b0fe478SBruce M Simpson 
4195b0fe478SBruce M Simpson static void
4208bdc5a62SPatrick Kelsey aodv_v6_draft_01_rrep(netdissect_options *ndo, const u_char *dat, u_int length)
4215b0fe478SBruce M Simpson {
4225b0fe478SBruce M Simpson 	u_int i;
4238bdc5a62SPatrick Kelsey 	const struct aodv_rrep6_draft_01 *ap = (const struct aodv_rrep6_draft_01 *)dat;
4245b0fe478SBruce M Simpson 
425*ee67461eSJoseph Mingrone 	ND_TCHECK_SIZE(ap);
4268bdc5a62SPatrick Kelsey 	if (length < sizeof(*ap))
4278bdc5a62SPatrick Kelsey 		goto trunc;
428*ee67461eSJoseph Mingrone 	ND_PRINT(" rrep %u %s%sprefix %u hops %u\n"
429*ee67461eSJoseph Mingrone 	   "\tdst %s dseq %u src %s %u ms", length,
430*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rrep_type) & RREP_REPAIR ? "[R]" : "",
431*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rrep_type) & RREP_ACK ? "[A] " : " ",
432*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rrep_ps) & RREP_PREFIX_MASK,
433*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rrep_hops),
434*ee67461eSJoseph Mingrone 	    GET_IP6ADDR_STRING(ap->rrep_da),
435*ee67461eSJoseph Mingrone 	    GET_BE_U_4(ap->rrep_ds),
436*ee67461eSJoseph Mingrone 	    GET_IP6ADDR_STRING(ap->rrep_oa),
437*ee67461eSJoseph Mingrone 	    GET_BE_U_4(ap->rrep_life));
4388bdc5a62SPatrick Kelsey 	i = length - sizeof(*ap);
4395b0fe478SBruce M Simpson 	if (i >= sizeof(struct aodv_ext))
4408bdc5a62SPatrick Kelsey 		aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
4418bdc5a62SPatrick Kelsey 	return;
4428bdc5a62SPatrick Kelsey 
4438bdc5a62SPatrick Kelsey trunc:
444*ee67461eSJoseph Mingrone 	nd_print_trunc(ndo);
4455b0fe478SBruce M Simpson }
4465b0fe478SBruce M Simpson 
4475b0fe478SBruce M Simpson static void
4488bdc5a62SPatrick Kelsey aodv_v6_draft_01_rerr(netdissect_options *ndo, const u_char *dat, u_int length)
4495b0fe478SBruce M Simpson {
4508bdc5a62SPatrick Kelsey 	u_int i, dc;
4518bdc5a62SPatrick Kelsey 	const struct aodv_rerr *ap = (const struct aodv_rerr *)dat;
4528bdc5a62SPatrick Kelsey 	const struct rerr_unreach6_draft_01 *dp6;
4535b0fe478SBruce M Simpson 
454*ee67461eSJoseph Mingrone 	ND_TCHECK_SIZE(ap);
4558bdc5a62SPatrick Kelsey 	if (length < sizeof(*ap))
4568bdc5a62SPatrick Kelsey 		goto trunc;
457*ee67461eSJoseph Mingrone 	ND_PRINT(" rerr %s [items %u] [%u]:",
458*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rerr_flags) & RERR_NODELETE ? "[D]" : "",
459*ee67461eSJoseph Mingrone 	    GET_U_1(ap->rerr_dc), length);
4603340d773SGleb Smirnoff 	dp6 = (const struct rerr_unreach6_draft_01 *)(const void *)(ap + 1);
4618bdc5a62SPatrick Kelsey 	i = length - sizeof(*ap);
462*ee67461eSJoseph Mingrone 	for (dc = GET_U_1(ap->rerr_dc); dc != 0; dc--) {
463*ee67461eSJoseph Mingrone 		ND_TCHECK_SIZE(dp6);
4648bdc5a62SPatrick Kelsey 		if (i < sizeof(*dp6))
4658bdc5a62SPatrick Kelsey 			goto trunc;
466*ee67461eSJoseph Mingrone 		ND_PRINT(" {%s}(%u)", GET_IP6ADDR_STRING(dp6->u_da),
467*ee67461eSJoseph Mingrone 			 GET_BE_U_4(dp6->u_ds));
4688bdc5a62SPatrick Kelsey 		dp6++;
4698bdc5a62SPatrick Kelsey 		i -= sizeof(*dp6);
4705b0fe478SBruce M Simpson 	}
4718bdc5a62SPatrick Kelsey 	return;
4728bdc5a62SPatrick Kelsey 
4738bdc5a62SPatrick Kelsey trunc:
474*ee67461eSJoseph Mingrone 	nd_print_trunc(ndo);
4755b0fe478SBruce M Simpson }
4765b0fe478SBruce M Simpson 
4775b0fe478SBruce M Simpson void
4783c602fabSXin LI aodv_print(netdissect_options *ndo,
4793c602fabSXin LI            const u_char *dat, u_int length, int is_ip6)
4805b0fe478SBruce M Simpson {
4818bdc5a62SPatrick Kelsey 	uint8_t msg_type;
4825b0fe478SBruce M Simpson 
483*ee67461eSJoseph Mingrone 	ndo->ndo_protocol = "aodv";
4848bdc5a62SPatrick Kelsey 	/*
4858bdc5a62SPatrick Kelsey 	 * The message type is the first byte; make sure we have it
4868bdc5a62SPatrick Kelsey 	 * and then fetch it.
4878bdc5a62SPatrick Kelsey 	 */
488*ee67461eSJoseph Mingrone 	msg_type = GET_U_1(dat);
489*ee67461eSJoseph Mingrone 	ND_PRINT(" aodv");
4905b0fe478SBruce M Simpson 
4918bdc5a62SPatrick Kelsey 	switch (msg_type) {
4925b0fe478SBruce M Simpson 
4935b0fe478SBruce M Simpson 	case AODV_RREQ:
4945b0fe478SBruce M Simpson 		if (is_ip6)
4958bdc5a62SPatrick Kelsey 			aodv_v6_rreq(ndo, dat, length);
4965b0fe478SBruce M Simpson 		else
4978bdc5a62SPatrick Kelsey 			aodv_rreq(ndo, dat, length);
4985b0fe478SBruce M Simpson 		break;
4995b0fe478SBruce M Simpson 
5005b0fe478SBruce M Simpson 	case AODV_RREP:
5015b0fe478SBruce M Simpson 		if (is_ip6)
5028bdc5a62SPatrick Kelsey 			aodv_v6_rrep(ndo, dat, length);
5035b0fe478SBruce M Simpson 		else
5048bdc5a62SPatrick Kelsey 			aodv_rrep(ndo, dat, length);
5055b0fe478SBruce M Simpson 		break;
5065b0fe478SBruce M Simpson 
5075b0fe478SBruce M Simpson 	case AODV_RERR:
5085b0fe478SBruce M Simpson 		if (is_ip6)
5098bdc5a62SPatrick Kelsey 			aodv_v6_rerr(ndo, dat, length);
5105b0fe478SBruce M Simpson 		else
5118bdc5a62SPatrick Kelsey 			aodv_rerr(ndo, dat, length);
5125b0fe478SBruce M Simpson 		break;
5135b0fe478SBruce M Simpson 
5145b0fe478SBruce M Simpson 	case AODV_RREP_ACK:
515*ee67461eSJoseph Mingrone 		ND_PRINT(" rrep-ack %u", length);
5165b0fe478SBruce M Simpson 		break;
5175b0fe478SBruce M Simpson 
5185b0fe478SBruce M Simpson 	case AODV_V6_DRAFT_01_RREQ:
5198bdc5a62SPatrick Kelsey 		aodv_v6_draft_01_rreq(ndo, dat, length);
5205b0fe478SBruce M Simpson 		break;
5215b0fe478SBruce M Simpson 
5225b0fe478SBruce M Simpson 	case AODV_V6_DRAFT_01_RREP:
5238bdc5a62SPatrick Kelsey 		aodv_v6_draft_01_rrep(ndo, dat, length);
5245b0fe478SBruce M Simpson 		break;
5255b0fe478SBruce M Simpson 
5265b0fe478SBruce M Simpson 	case AODV_V6_DRAFT_01_RERR:
5278bdc5a62SPatrick Kelsey 		aodv_v6_draft_01_rerr(ndo, dat, length);
5285b0fe478SBruce M Simpson 		break;
5295b0fe478SBruce M Simpson 
5305b0fe478SBruce M Simpson 	case AODV_V6_DRAFT_01_RREP_ACK:
531*ee67461eSJoseph Mingrone 		ND_PRINT(" rrep-ack %u", length);
5325b0fe478SBruce M Simpson 		break;
5335b0fe478SBruce M Simpson 
5345b0fe478SBruce M Simpson 	default:
535*ee67461eSJoseph Mingrone 		ND_PRINT(" type %u %u", msg_type, length);
5365b0fe478SBruce M Simpson 	}
5375b0fe478SBruce M Simpson }
538