xref: /freebsd/contrib/tcpdump/print-aodv.c (revision 0bff6a5af8cb6d8e5123f8b667df78cac885dbb7)
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
365b0fe478SBruce M Simpson #include "config.h"
375b0fe478SBruce M Simpson #endif
385b0fe478SBruce M Simpson 
393340d773SGleb Smirnoff #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 
45*0bff6a5aSEd Maste /*
46*0bff6a5aSEd Maste  * RFC 3561
47*0bff6a5aSEd Maste  */
483c602fabSXin LI struct aodv_rreq {
493c602fabSXin LI 	uint8_t		rreq_type;	/* AODV message type (1) */
503c602fabSXin LI 	uint8_t		rreq_flags;	/* various flags */
513c602fabSXin LI 	uint8_t		rreq_zero0;	/* reserved, set to zero */
523c602fabSXin LI 	uint8_t		rreq_hops;	/* number of hops from originator */
533c602fabSXin LI 	uint32_t	rreq_id;	/* request ID */
543c602fabSXin LI 	uint32_t	rreq_da;	/* destination IPv4 address */
553c602fabSXin LI 	uint32_t	rreq_ds;	/* destination sequence number */
563c602fabSXin LI 	uint32_t	rreq_oa;	/* originator IPv4 address */
573c602fabSXin LI 	uint32_t	rreq_os;	/* originator sequence number */
583c602fabSXin LI };
593c602fabSXin LI struct aodv_rreq6 {
603c602fabSXin LI 	uint8_t		rreq_type;	/* AODV message type (1) */
613c602fabSXin LI 	uint8_t		rreq_flags;	/* various flags */
623c602fabSXin LI 	uint8_t		rreq_zero0;	/* reserved, set to zero */
633c602fabSXin LI 	uint8_t		rreq_hops;	/* number of hops from originator */
643c602fabSXin LI 	uint32_t	rreq_id;	/* request ID */
653c602fabSXin LI 	struct in6_addr	rreq_da;	/* destination IPv6 address */
663c602fabSXin LI 	uint32_t	rreq_ds;	/* destination sequence number */
673c602fabSXin LI 	struct in6_addr	rreq_oa;	/* originator IPv6 address */
683c602fabSXin LI 	uint32_t	rreq_os;	/* originator sequence number */
693c602fabSXin LI };
703c602fabSXin LI struct aodv_rreq6_draft_01 {
713c602fabSXin LI 	uint8_t		rreq_type;	/* AODV message type (16) */
723c602fabSXin LI 	uint8_t		rreq_flags;	/* various flags */
733c602fabSXin LI 	uint8_t		rreq_zero0;	/* reserved, set to zero */
743c602fabSXin LI 	uint8_t		rreq_hops;	/* number of hops from originator */
753c602fabSXin LI 	uint32_t	rreq_id;	/* request ID */
763c602fabSXin LI 	uint32_t	rreq_ds;	/* destination sequence number */
773c602fabSXin LI 	uint32_t	rreq_os;	/* originator sequence number */
783c602fabSXin LI 	struct in6_addr	rreq_da;	/* destination IPv6 address */
793c602fabSXin LI 	struct in6_addr	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 {
903c602fabSXin LI 	uint8_t		rrep_type;	/* AODV message type (2) */
913c602fabSXin LI 	uint8_t		rrep_flags;	/* various flags */
923c602fabSXin LI 	uint8_t		rrep_ps;	/* prefix size */
933c602fabSXin LI 	uint8_t		rrep_hops;	/* number of hops from o to d */
943c602fabSXin LI 	uint32_t	rrep_da;	/* destination IPv4 address */
953c602fabSXin LI 	uint32_t	rrep_ds;	/* destination sequence number */
963c602fabSXin LI 	uint32_t	rrep_oa;	/* originator IPv4 address */
973c602fabSXin LI 	uint32_t	rrep_life;	/* lifetime of this route */
983c602fabSXin LI };
993c602fabSXin LI struct aodv_rrep6 {
1003c602fabSXin LI 	uint8_t		rrep_type;	/* AODV message type (2) */
1013c602fabSXin LI 	uint8_t		rrep_flags;	/* various flags */
1023c602fabSXin LI 	uint8_t		rrep_ps;	/* prefix size */
1033c602fabSXin LI 	uint8_t		rrep_hops;	/* number of hops from o to d */
1043c602fabSXin LI 	struct in6_addr	rrep_da;	/* destination IPv6 address */
1053c602fabSXin LI 	uint32_t	rrep_ds;	/* destination sequence number */
1063c602fabSXin LI 	struct in6_addr	rrep_oa;	/* originator IPv6 address */
1073c602fabSXin LI 	uint32_t	rrep_life;	/* lifetime of this route */
1083c602fabSXin LI };
1093c602fabSXin LI struct aodv_rrep6_draft_01 {
1103c602fabSXin LI 	uint8_t		rrep_type;	/* AODV message type (17) */
1113c602fabSXin LI 	uint8_t		rrep_flags;	/* various flags */
1123c602fabSXin LI 	uint8_t		rrep_ps;	/* prefix size */
1133c602fabSXin LI 	uint8_t		rrep_hops;	/* number of hops from o to d */
1143c602fabSXin LI 	uint32_t	rrep_ds;	/* destination sequence number */
1153c602fabSXin LI 	struct in6_addr	rrep_da;	/* destination IPv6 address */
1163c602fabSXin LI 	struct in6_addr	rrep_oa;	/* originator IPv6 address */
1173c602fabSXin LI 	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 {
1263c602fabSXin LI 	uint32_t	u_da;	/* IPv4 address */
1273c602fabSXin LI 	uint32_t	u_ds;	/* sequence number */
1283c602fabSXin LI };
1293c602fabSXin LI struct rerr_unreach6 {
1303c602fabSXin LI 	struct in6_addr	u_da;	/* IPv6 address */
1313c602fabSXin LI 	uint32_t	u_ds;	/* sequence number */
1323c602fabSXin LI };
1333c602fabSXin LI struct rerr_unreach6_draft_01 {
1343c602fabSXin LI 	struct in6_addr	u_da;	/* IPv6 address */
1353c602fabSXin LI 	uint32_t	u_ds;	/* sequence number */
1363c602fabSXin LI };
1373c602fabSXin LI 
1383c602fabSXin LI struct aodv_rerr {
1393c602fabSXin LI 	uint8_t		rerr_type;	/* AODV message type (3 or 18) */
1403c602fabSXin LI 	uint8_t		rerr_flags;	/* various flags */
1413c602fabSXin LI 	uint8_t		rerr_zero0;	/* reserved, set to zero */
1423c602fabSXin LI 	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 {
1493c602fabSXin LI 	uint8_t		ra_type;
1503c602fabSXin LI 	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 {
1643c602fabSXin LI 	uint8_t		type;		/* extension type */
1653c602fabSXin LI 	uint8_t		length;		/* extension length */
1663c602fabSXin LI };
1673c602fabSXin LI 
1683c602fabSXin LI struct aodv_hello {
1693c602fabSXin LI 	struct	aodv_ext	eh;		/* extension header */
1703c602fabSXin LI 	uint8_t			interval[4];	/* 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*0bff6a5aSEd Maste 	ND_TCHECK(*ep);
1845b0fe478SBruce M Simpson 	switch (ep->type) {
1855b0fe478SBruce M Simpson 	case AODV_EXT_HELLO:
1868bdc5a62SPatrick Kelsey 		ah = (const struct aodv_hello *)(const void *)ep;
1878bdc5a62SPatrick Kelsey 		ND_TCHECK(*ah);
1888bdc5a62SPatrick Kelsey 		if (length < sizeof(struct aodv_hello))
1898bdc5a62SPatrick Kelsey 			goto trunc;
190*0bff6a5aSEd Maste 		if (ep->length < 4) {
191*0bff6a5aSEd Maste 			ND_PRINT((ndo, "\n\text HELLO - bad length %u", ep->length));
192*0bff6a5aSEd Maste 			break;
193*0bff6a5aSEd Maste 		}
1943c602fabSXin LI 		ND_PRINT((ndo, "\n\text HELLO %ld ms",
1953c602fabSXin LI 		    (unsigned long)EXTRACT_32BITS(&ah->interval)));
1965b0fe478SBruce M Simpson 		break;
1975b0fe478SBruce M Simpson 
1985b0fe478SBruce M Simpson 	default:
1993c602fabSXin LI 		ND_PRINT((ndo, "\n\text %u %u", ep->type, ep->length));
2005b0fe478SBruce M Simpson 		break;
2015b0fe478SBruce M Simpson 	}
2028bdc5a62SPatrick Kelsey 	return;
2038bdc5a62SPatrick Kelsey 
2048bdc5a62SPatrick Kelsey trunc:
2058bdc5a62SPatrick Kelsey 	ND_PRINT((ndo, " [|hello]"));
2065b0fe478SBruce M Simpson }
2075b0fe478SBruce M Simpson 
2085b0fe478SBruce M Simpson static void
2098bdc5a62SPatrick Kelsey aodv_rreq(netdissect_options *ndo, const u_char *dat, u_int length)
2105b0fe478SBruce M Simpson {
2115b0fe478SBruce M Simpson 	u_int i;
2128bdc5a62SPatrick Kelsey 	const struct aodv_rreq *ap = (const struct aodv_rreq *)dat;
2135b0fe478SBruce M Simpson 
2148bdc5a62SPatrick Kelsey 	ND_TCHECK(*ap);
2158bdc5a62SPatrick Kelsey 	if (length < sizeof(*ap))
2168bdc5a62SPatrick Kelsey 		goto trunc;
2173c602fabSXin LI 	ND_PRINT((ndo, " rreq %u %s%s%s%s%shops %u id 0x%08lx\n"
2185b0fe478SBruce M Simpson 	    "\tdst %s seq %lu src %s seq %lu", length,
2198bdc5a62SPatrick Kelsey 	    ap->rreq_type & RREQ_JOIN ? "[J]" : "",
2208bdc5a62SPatrick Kelsey 	    ap->rreq_type & RREQ_REPAIR ? "[R]" : "",
2218bdc5a62SPatrick Kelsey 	    ap->rreq_type & RREQ_GRAT ? "[G]" : "",
2228bdc5a62SPatrick Kelsey 	    ap->rreq_type & RREQ_DEST ? "[D]" : "",
2238bdc5a62SPatrick Kelsey 	    ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
2248bdc5a62SPatrick Kelsey 	    ap->rreq_hops,
2258bdc5a62SPatrick Kelsey 	    (unsigned long)EXTRACT_32BITS(&ap->rreq_id),
2268bdc5a62SPatrick Kelsey 	    ipaddr_string(ndo, &ap->rreq_da),
2278bdc5a62SPatrick Kelsey 	    (unsigned long)EXTRACT_32BITS(&ap->rreq_ds),
2288bdc5a62SPatrick Kelsey 	    ipaddr_string(ndo, &ap->rreq_oa),
2298bdc5a62SPatrick Kelsey 	    (unsigned long)EXTRACT_32BITS(&ap->rreq_os)));
2308bdc5a62SPatrick Kelsey 	i = length - sizeof(*ap);
2315b0fe478SBruce M Simpson 	if (i >= sizeof(struct aodv_ext))
2328bdc5a62SPatrick Kelsey 		aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
2338bdc5a62SPatrick Kelsey 	return;
2348bdc5a62SPatrick Kelsey 
2358bdc5a62SPatrick Kelsey trunc:
2368bdc5a62SPatrick Kelsey 	ND_PRINT((ndo, " [|rreq"));
2375b0fe478SBruce M Simpson }
2385b0fe478SBruce M Simpson 
2395b0fe478SBruce M Simpson static void
2408bdc5a62SPatrick Kelsey aodv_rrep(netdissect_options *ndo, const u_char *dat, u_int length)
2415b0fe478SBruce M Simpson {
2425b0fe478SBruce M Simpson 	u_int i;
2438bdc5a62SPatrick Kelsey 	const struct aodv_rrep *ap = (const struct aodv_rrep *)dat;
2445b0fe478SBruce M Simpson 
2458bdc5a62SPatrick Kelsey 	ND_TCHECK(*ap);
2468bdc5a62SPatrick Kelsey 	if (length < sizeof(*ap))
2478bdc5a62SPatrick Kelsey 		goto trunc;
2483c602fabSXin LI 	ND_PRINT((ndo, " rrep %u %s%sprefix %u hops %u\n"
2495b0fe478SBruce M Simpson 	    "\tdst %s dseq %lu src %s %lu ms", length,
2508bdc5a62SPatrick Kelsey 	    ap->rrep_type & RREP_REPAIR ? "[R]" : "",
2518bdc5a62SPatrick Kelsey 	    ap->rrep_type & RREP_ACK ? "[A] " : " ",
2528bdc5a62SPatrick Kelsey 	    ap->rrep_ps & RREP_PREFIX_MASK,
2538bdc5a62SPatrick Kelsey 	    ap->rrep_hops,
2548bdc5a62SPatrick Kelsey 	    ipaddr_string(ndo, &ap->rrep_da),
2558bdc5a62SPatrick Kelsey 	    (unsigned long)EXTRACT_32BITS(&ap->rrep_ds),
2568bdc5a62SPatrick Kelsey 	    ipaddr_string(ndo, &ap->rrep_oa),
2578bdc5a62SPatrick Kelsey 	    (unsigned long)EXTRACT_32BITS(&ap->rrep_life)));
2588bdc5a62SPatrick Kelsey 	i = length - sizeof(*ap);
2595b0fe478SBruce M Simpson 	if (i >= sizeof(struct aodv_ext))
2608bdc5a62SPatrick Kelsey 		aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
2618bdc5a62SPatrick Kelsey 	return;
2628bdc5a62SPatrick Kelsey 
2638bdc5a62SPatrick Kelsey trunc:
2648bdc5a62SPatrick Kelsey 	ND_PRINT((ndo, " [|rreq"));
2655b0fe478SBruce M Simpson }
2665b0fe478SBruce M Simpson 
2675b0fe478SBruce M Simpson static void
2688bdc5a62SPatrick Kelsey aodv_rerr(netdissect_options *ndo, const u_char *dat, u_int length)
2695b0fe478SBruce M Simpson {
2708bdc5a62SPatrick Kelsey 	u_int i, dc;
2718bdc5a62SPatrick Kelsey 	const struct aodv_rerr *ap = (const struct aodv_rerr *)dat;
2728bdc5a62SPatrick Kelsey 	const struct rerr_unreach *dp;
2735b0fe478SBruce M Simpson 
2748bdc5a62SPatrick Kelsey 	ND_TCHECK(*ap);
2758bdc5a62SPatrick Kelsey 	if (length < sizeof(*ap))
2768bdc5a62SPatrick Kelsey 		goto trunc;
2773c602fabSXin LI 	ND_PRINT((ndo, " rerr %s [items %u] [%u]:",
2788bdc5a62SPatrick Kelsey 	    ap->rerr_flags & RERR_NODELETE ? "[D]" : "",
2798bdc5a62SPatrick Kelsey 	    ap->rerr_dc, length));
2803340d773SGleb Smirnoff 	dp = (const struct rerr_unreach *)(dat + sizeof(*ap));
2818bdc5a62SPatrick Kelsey 	i = length - sizeof(*ap);
2828bdc5a62SPatrick Kelsey 	for (dc = ap->rerr_dc; dc != 0; dc--) {
2838bdc5a62SPatrick Kelsey 		ND_TCHECK(*dp);
2848bdc5a62SPatrick Kelsey 		if (i < sizeof(*dp))
2858bdc5a62SPatrick Kelsey 			goto trunc;
2863c602fabSXin LI 		ND_PRINT((ndo, " {%s}(%ld)", ipaddr_string(ndo, &dp->u_da),
2873c602fabSXin LI 		    (unsigned long)EXTRACT_32BITS(&dp->u_ds)));
2888bdc5a62SPatrick Kelsey 		dp++;
2898bdc5a62SPatrick Kelsey 		i -= sizeof(*dp);
2905b0fe478SBruce M Simpson 	}
2918bdc5a62SPatrick Kelsey 	return;
2928bdc5a62SPatrick Kelsey 
2938bdc5a62SPatrick Kelsey trunc:
2943c602fabSXin LI 	ND_PRINT((ndo, "[|rerr]"));
2955b0fe478SBruce M Simpson }
2965b0fe478SBruce M Simpson 
2975b0fe478SBruce M Simpson static void
2988bdc5a62SPatrick Kelsey aodv_v6_rreq(netdissect_options *ndo, const u_char *dat, u_int length)
2995b0fe478SBruce M Simpson {
3005b0fe478SBruce M Simpson 	u_int i;
3018bdc5a62SPatrick Kelsey 	const struct aodv_rreq6 *ap = (const struct aodv_rreq6 *)dat;
3025b0fe478SBruce M Simpson 
3038bdc5a62SPatrick Kelsey 	ND_TCHECK(*ap);
3048bdc5a62SPatrick Kelsey 	if (length < sizeof(*ap))
3058bdc5a62SPatrick Kelsey 		goto trunc;
3063c602fabSXin LI 	ND_PRINT((ndo, " v6 rreq %u %s%s%s%s%shops %u id 0x%08lx\n"
3075b0fe478SBruce M Simpson 	    "\tdst %s seq %lu src %s seq %lu", length,
3088bdc5a62SPatrick Kelsey 	    ap->rreq_type & RREQ_JOIN ? "[J]" : "",
3098bdc5a62SPatrick Kelsey 	    ap->rreq_type & RREQ_REPAIR ? "[R]" : "",
3108bdc5a62SPatrick Kelsey 	    ap->rreq_type & RREQ_GRAT ? "[G]" : "",
3118bdc5a62SPatrick Kelsey 	    ap->rreq_type & RREQ_DEST ? "[D]" : "",
3128bdc5a62SPatrick Kelsey 	    ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
3138bdc5a62SPatrick Kelsey 	    ap->rreq_hops,
3148bdc5a62SPatrick Kelsey 	    (unsigned long)EXTRACT_32BITS(&ap->rreq_id),
3158bdc5a62SPatrick Kelsey 	    ip6addr_string(ndo, &ap->rreq_da),
3168bdc5a62SPatrick Kelsey 	    (unsigned long)EXTRACT_32BITS(&ap->rreq_ds),
3178bdc5a62SPatrick Kelsey 	    ip6addr_string(ndo, &ap->rreq_oa),
3188bdc5a62SPatrick Kelsey 	    (unsigned long)EXTRACT_32BITS(&ap->rreq_os)));
3198bdc5a62SPatrick Kelsey 	i = length - sizeof(*ap);
3205b0fe478SBruce M Simpson 	if (i >= sizeof(struct aodv_ext))
3218bdc5a62SPatrick Kelsey 		aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
3228bdc5a62SPatrick Kelsey 	return;
3238bdc5a62SPatrick Kelsey 
3248bdc5a62SPatrick Kelsey trunc:
3258bdc5a62SPatrick Kelsey 	ND_PRINT((ndo, " [|rreq"));
3265b0fe478SBruce M Simpson }
3275b0fe478SBruce M Simpson 
3285b0fe478SBruce M Simpson static void
3298bdc5a62SPatrick Kelsey aodv_v6_rrep(netdissect_options *ndo, const u_char *dat, u_int length)
3305b0fe478SBruce M Simpson {
3315b0fe478SBruce M Simpson 	u_int i;
3328bdc5a62SPatrick Kelsey 	const struct aodv_rrep6 *ap = (const struct aodv_rrep6 *)dat;
3335b0fe478SBruce M Simpson 
3348bdc5a62SPatrick Kelsey 	ND_TCHECK(*ap);
3358bdc5a62SPatrick Kelsey 	if (length < sizeof(*ap))
3368bdc5a62SPatrick Kelsey 		goto trunc;
3373c602fabSXin LI 	ND_PRINT((ndo, " rrep %u %s%sprefix %u hops %u\n"
3385b0fe478SBruce M Simpson 	   "\tdst %s dseq %lu src %s %lu ms", length,
3398bdc5a62SPatrick Kelsey 	    ap->rrep_type & RREP_REPAIR ? "[R]" : "",
3408bdc5a62SPatrick Kelsey 	    ap->rrep_type & RREP_ACK ? "[A] " : " ",
3418bdc5a62SPatrick Kelsey 	    ap->rrep_ps & RREP_PREFIX_MASK,
3428bdc5a62SPatrick Kelsey 	    ap->rrep_hops,
3438bdc5a62SPatrick Kelsey 	    ip6addr_string(ndo, &ap->rrep_da),
3448bdc5a62SPatrick Kelsey 	    (unsigned long)EXTRACT_32BITS(&ap->rrep_ds),
3458bdc5a62SPatrick Kelsey 	    ip6addr_string(ndo, &ap->rrep_oa),
3468bdc5a62SPatrick Kelsey 	    (unsigned long)EXTRACT_32BITS(&ap->rrep_life)));
3478bdc5a62SPatrick Kelsey 	i = length - sizeof(*ap);
3485b0fe478SBruce M Simpson 	if (i >= sizeof(struct aodv_ext))
3498bdc5a62SPatrick Kelsey 		aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
3508bdc5a62SPatrick Kelsey 	return;
3518bdc5a62SPatrick Kelsey 
3528bdc5a62SPatrick Kelsey trunc:
3538bdc5a62SPatrick Kelsey 	ND_PRINT((ndo, " [|rreq"));
3545b0fe478SBruce M Simpson }
3555b0fe478SBruce M Simpson 
3565b0fe478SBruce M Simpson static void
3578bdc5a62SPatrick Kelsey aodv_v6_rerr(netdissect_options *ndo, const u_char *dat, u_int length)
3585b0fe478SBruce M Simpson {
3598bdc5a62SPatrick Kelsey 	u_int i, dc;
3608bdc5a62SPatrick Kelsey 	const struct aodv_rerr *ap = (const struct aodv_rerr *)dat;
3618bdc5a62SPatrick Kelsey 	const struct rerr_unreach6 *dp6;
3625b0fe478SBruce M Simpson 
3638bdc5a62SPatrick Kelsey 	ND_TCHECK(*ap);
3648bdc5a62SPatrick Kelsey 	if (length < sizeof(*ap))
3658bdc5a62SPatrick Kelsey 		goto trunc;
3663c602fabSXin LI 	ND_PRINT((ndo, " rerr %s [items %u] [%u]:",
3678bdc5a62SPatrick Kelsey 	    ap->rerr_flags & RERR_NODELETE ? "[D]" : "",
3688bdc5a62SPatrick Kelsey 	    ap->rerr_dc, length));
3693340d773SGleb Smirnoff 	dp6 = (const struct rerr_unreach6 *)(const void *)(ap + 1);
3708bdc5a62SPatrick Kelsey 	i = length - sizeof(*ap);
3718bdc5a62SPatrick Kelsey 	for (dc = ap->rerr_dc; dc != 0; dc--) {
3728bdc5a62SPatrick Kelsey 		ND_TCHECK(*dp6);
3738bdc5a62SPatrick Kelsey 		if (i < sizeof(*dp6))
3748bdc5a62SPatrick Kelsey 			goto trunc;
3753c602fabSXin LI 		ND_PRINT((ndo, " {%s}(%ld)", ip6addr_string(ndo, &dp6->u_da),
3763c602fabSXin LI 		    (unsigned long)EXTRACT_32BITS(&dp6->u_ds)));
3778bdc5a62SPatrick Kelsey 		dp6++;
3788bdc5a62SPatrick Kelsey 		i -= sizeof(*dp6);
3795b0fe478SBruce M Simpson 	}
3808bdc5a62SPatrick Kelsey 	return;
3818bdc5a62SPatrick Kelsey 
3828bdc5a62SPatrick Kelsey trunc:
3833c602fabSXin LI 	ND_PRINT((ndo, "[|rerr]"));
3845b0fe478SBruce M Simpson }
3855b0fe478SBruce M Simpson 
3865b0fe478SBruce M Simpson static void
3878bdc5a62SPatrick Kelsey aodv_v6_draft_01_rreq(netdissect_options *ndo, const u_char *dat, u_int length)
3885b0fe478SBruce M Simpson {
3895b0fe478SBruce M Simpson 	u_int i;
3908bdc5a62SPatrick Kelsey 	const struct aodv_rreq6_draft_01 *ap = (const struct aodv_rreq6_draft_01 *)dat;
3915b0fe478SBruce M Simpson 
3928bdc5a62SPatrick Kelsey 	ND_TCHECK(*ap);
3938bdc5a62SPatrick Kelsey 	if (length < sizeof(*ap))
3948bdc5a62SPatrick Kelsey 		goto trunc;
3953c602fabSXin LI 	ND_PRINT((ndo, " rreq %u %s%s%s%s%shops %u id 0x%08lx\n"
3965b0fe478SBruce M Simpson 	    "\tdst %s seq %lu src %s seq %lu", length,
3978bdc5a62SPatrick Kelsey 	    ap->rreq_type & RREQ_JOIN ? "[J]" : "",
3988bdc5a62SPatrick Kelsey 	    ap->rreq_type & RREQ_REPAIR ? "[R]" : "",
3998bdc5a62SPatrick Kelsey 	    ap->rreq_type & RREQ_GRAT ? "[G]" : "",
4008bdc5a62SPatrick Kelsey 	    ap->rreq_type & RREQ_DEST ? "[D]" : "",
4018bdc5a62SPatrick Kelsey 	    ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
4028bdc5a62SPatrick Kelsey 	    ap->rreq_hops,
4038bdc5a62SPatrick Kelsey 	    (unsigned long)EXTRACT_32BITS(&ap->rreq_id),
4048bdc5a62SPatrick Kelsey 	    ip6addr_string(ndo, &ap->rreq_da),
4058bdc5a62SPatrick Kelsey 	    (unsigned long)EXTRACT_32BITS(&ap->rreq_ds),
4068bdc5a62SPatrick Kelsey 	    ip6addr_string(ndo, &ap->rreq_oa),
4078bdc5a62SPatrick Kelsey 	    (unsigned long)EXTRACT_32BITS(&ap->rreq_os)));
4088bdc5a62SPatrick Kelsey 	i = length - sizeof(*ap);
4095b0fe478SBruce M Simpson 	if (i >= sizeof(struct aodv_ext))
4108bdc5a62SPatrick Kelsey 		aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
4118bdc5a62SPatrick Kelsey 	return;
4128bdc5a62SPatrick Kelsey 
4138bdc5a62SPatrick Kelsey trunc:
4148bdc5a62SPatrick Kelsey 	ND_PRINT((ndo, " [|rreq"));
4155b0fe478SBruce M Simpson }
4165b0fe478SBruce M Simpson 
4175b0fe478SBruce M Simpson static void
4188bdc5a62SPatrick Kelsey aodv_v6_draft_01_rrep(netdissect_options *ndo, const u_char *dat, u_int length)
4195b0fe478SBruce M Simpson {
4205b0fe478SBruce M Simpson 	u_int i;
4218bdc5a62SPatrick Kelsey 	const struct aodv_rrep6_draft_01 *ap = (const struct aodv_rrep6_draft_01 *)dat;
4225b0fe478SBruce M Simpson 
4238bdc5a62SPatrick Kelsey 	ND_TCHECK(*ap);
4248bdc5a62SPatrick Kelsey 	if (length < sizeof(*ap))
4258bdc5a62SPatrick Kelsey 		goto trunc;
4263c602fabSXin LI 	ND_PRINT((ndo, " rrep %u %s%sprefix %u hops %u\n"
4275b0fe478SBruce M Simpson 	   "\tdst %s dseq %lu src %s %lu ms", length,
4288bdc5a62SPatrick Kelsey 	    ap->rrep_type & RREP_REPAIR ? "[R]" : "",
4298bdc5a62SPatrick Kelsey 	    ap->rrep_type & RREP_ACK ? "[A] " : " ",
4308bdc5a62SPatrick Kelsey 	    ap->rrep_ps & RREP_PREFIX_MASK,
4318bdc5a62SPatrick Kelsey 	    ap->rrep_hops,
4328bdc5a62SPatrick Kelsey 	    ip6addr_string(ndo, &ap->rrep_da),
4338bdc5a62SPatrick Kelsey 	    (unsigned long)EXTRACT_32BITS(&ap->rrep_ds),
4348bdc5a62SPatrick Kelsey 	    ip6addr_string(ndo, &ap->rrep_oa),
4358bdc5a62SPatrick Kelsey 	    (unsigned long)EXTRACT_32BITS(&ap->rrep_life)));
4368bdc5a62SPatrick Kelsey 	i = length - sizeof(*ap);
4375b0fe478SBruce M Simpson 	if (i >= sizeof(struct aodv_ext))
4388bdc5a62SPatrick Kelsey 		aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
4398bdc5a62SPatrick Kelsey 	return;
4408bdc5a62SPatrick Kelsey 
4418bdc5a62SPatrick Kelsey trunc:
4428bdc5a62SPatrick Kelsey 	ND_PRINT((ndo, " [|rreq"));
4435b0fe478SBruce M Simpson }
4445b0fe478SBruce M Simpson 
4455b0fe478SBruce M Simpson static void
4468bdc5a62SPatrick Kelsey aodv_v6_draft_01_rerr(netdissect_options *ndo, const u_char *dat, u_int length)
4475b0fe478SBruce M Simpson {
4488bdc5a62SPatrick Kelsey 	u_int i, dc;
4498bdc5a62SPatrick Kelsey 	const struct aodv_rerr *ap = (const struct aodv_rerr *)dat;
4508bdc5a62SPatrick Kelsey 	const struct rerr_unreach6_draft_01 *dp6;
4515b0fe478SBruce M Simpson 
4528bdc5a62SPatrick Kelsey 	ND_TCHECK(*ap);
4538bdc5a62SPatrick Kelsey 	if (length < sizeof(*ap))
4548bdc5a62SPatrick Kelsey 		goto trunc;
4553c602fabSXin LI 	ND_PRINT((ndo, " rerr %s [items %u] [%u]:",
4568bdc5a62SPatrick Kelsey 	    ap->rerr_flags & RERR_NODELETE ? "[D]" : "",
4578bdc5a62SPatrick Kelsey 	    ap->rerr_dc, length));
4583340d773SGleb Smirnoff 	dp6 = (const struct rerr_unreach6_draft_01 *)(const void *)(ap + 1);
4598bdc5a62SPatrick Kelsey 	i = length - sizeof(*ap);
4608bdc5a62SPatrick Kelsey 	for (dc = ap->rerr_dc; dc != 0; dc--) {
4618bdc5a62SPatrick Kelsey 		ND_TCHECK(*dp6);
4628bdc5a62SPatrick Kelsey 		if (i < sizeof(*dp6))
4638bdc5a62SPatrick Kelsey 			goto trunc;
4643c602fabSXin LI 		ND_PRINT((ndo, " {%s}(%ld)", ip6addr_string(ndo, &dp6->u_da),
4653c602fabSXin LI 		    (unsigned long)EXTRACT_32BITS(&dp6->u_ds)));
4668bdc5a62SPatrick Kelsey 		dp6++;
4678bdc5a62SPatrick Kelsey 		i -= sizeof(*dp6);
4685b0fe478SBruce M Simpson 	}
4698bdc5a62SPatrick Kelsey 	return;
4708bdc5a62SPatrick Kelsey 
4718bdc5a62SPatrick Kelsey trunc:
4723c602fabSXin LI 	ND_PRINT((ndo, "[|rerr]"));
4735b0fe478SBruce M Simpson }
4745b0fe478SBruce M Simpson 
4755b0fe478SBruce M Simpson void
4763c602fabSXin LI aodv_print(netdissect_options *ndo,
4773c602fabSXin LI            const u_char *dat, u_int length, int is_ip6)
4785b0fe478SBruce M Simpson {
4798bdc5a62SPatrick Kelsey 	uint8_t msg_type;
4805b0fe478SBruce M Simpson 
4818bdc5a62SPatrick Kelsey 	/*
4828bdc5a62SPatrick Kelsey 	 * The message type is the first byte; make sure we have it
4838bdc5a62SPatrick Kelsey 	 * and then fetch it.
4848bdc5a62SPatrick Kelsey 	 */
4858bdc5a62SPatrick Kelsey 	ND_TCHECK(*dat);
4868bdc5a62SPatrick Kelsey 	msg_type = *dat;
4873c602fabSXin LI 	ND_PRINT((ndo, " aodv"));
4885b0fe478SBruce M Simpson 
4898bdc5a62SPatrick Kelsey 	switch (msg_type) {
4905b0fe478SBruce M Simpson 
4915b0fe478SBruce M Simpson 	case AODV_RREQ:
4925b0fe478SBruce M Simpson 		if (is_ip6)
4938bdc5a62SPatrick Kelsey 			aodv_v6_rreq(ndo, dat, length);
4945b0fe478SBruce M Simpson 		else
4958bdc5a62SPatrick Kelsey 			aodv_rreq(ndo, dat, length);
4965b0fe478SBruce M Simpson 		break;
4975b0fe478SBruce M Simpson 
4985b0fe478SBruce M Simpson 	case AODV_RREP:
4995b0fe478SBruce M Simpson 		if (is_ip6)
5008bdc5a62SPatrick Kelsey 			aodv_v6_rrep(ndo, dat, length);
5015b0fe478SBruce M Simpson 		else
5028bdc5a62SPatrick Kelsey 			aodv_rrep(ndo, dat, length);
5035b0fe478SBruce M Simpson 		break;
5045b0fe478SBruce M Simpson 
5055b0fe478SBruce M Simpson 	case AODV_RERR:
5065b0fe478SBruce M Simpson 		if (is_ip6)
5078bdc5a62SPatrick Kelsey 			aodv_v6_rerr(ndo, dat, length);
5085b0fe478SBruce M Simpson 		else
5098bdc5a62SPatrick Kelsey 			aodv_rerr(ndo, dat, length);
5105b0fe478SBruce M Simpson 		break;
5115b0fe478SBruce M Simpson 
5125b0fe478SBruce M Simpson 	case AODV_RREP_ACK:
5133c602fabSXin LI 		ND_PRINT((ndo, " rrep-ack %u", length));
5145b0fe478SBruce M Simpson 		break;
5155b0fe478SBruce M Simpson 
5165b0fe478SBruce M Simpson 	case AODV_V6_DRAFT_01_RREQ:
5178bdc5a62SPatrick Kelsey 		aodv_v6_draft_01_rreq(ndo, dat, length);
5185b0fe478SBruce M Simpson 		break;
5195b0fe478SBruce M Simpson 
5205b0fe478SBruce M Simpson 	case AODV_V6_DRAFT_01_RREP:
5218bdc5a62SPatrick Kelsey 		aodv_v6_draft_01_rrep(ndo, dat, length);
5225b0fe478SBruce M Simpson 		break;
5235b0fe478SBruce M Simpson 
5245b0fe478SBruce M Simpson 	case AODV_V6_DRAFT_01_RERR:
5258bdc5a62SPatrick Kelsey 		aodv_v6_draft_01_rerr(ndo, dat, length);
5265b0fe478SBruce M Simpson 		break;
5275b0fe478SBruce M Simpson 
5285b0fe478SBruce M Simpson 	case AODV_V6_DRAFT_01_RREP_ACK:
5293c602fabSXin LI 		ND_PRINT((ndo, " rrep-ack %u", length));
5305b0fe478SBruce M Simpson 		break;
5315b0fe478SBruce M Simpson 
5325b0fe478SBruce M Simpson 	default:
5338bdc5a62SPatrick Kelsey 		ND_PRINT((ndo, " type %u %u", msg_type, length));
5345b0fe478SBruce M Simpson 	}
5358bdc5a62SPatrick Kelsey 	return;
5368bdc5a62SPatrick Kelsey 
5378bdc5a62SPatrick Kelsey trunc:
5388bdc5a62SPatrick Kelsey 	ND_PRINT((ndo, " [|aodv]"));
5395b0fe478SBruce M Simpson }
540