Home | History | Annotate | Download | only in tcpdump
      1 /*
      2  * Copyright (c) 2003 Bruce M. Simpson <bms (at) 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 #define NETDISSECT_REWORKED
     34 #ifdef HAVE_CONFIG_H
     35 #include "config.h"
     36 #endif
     37 
     38 #include <tcpdump-stdinc.h>
     39 
     40 #include "interface.h"
     41 #include "addrtoname.h"
     42 #include "extract.h"			/* must come after interface.h */
     43 
     44 
     45 struct aodv_rreq {
     46 	uint8_t		rreq_type;	/* AODV message type (1) */
     47 	uint8_t		rreq_flags;	/* various flags */
     48 	uint8_t		rreq_zero0;	/* reserved, set to zero */
     49 	uint8_t		rreq_hops;	/* number of hops from originator */
     50 	uint32_t	rreq_id;	/* request ID */
     51 	uint32_t	rreq_da;	/* destination IPv4 address */
     52 	uint32_t	rreq_ds;	/* destination sequence number */
     53 	uint32_t	rreq_oa;	/* originator IPv4 address */
     54 	uint32_t	rreq_os;	/* originator sequence number */
     55 };
     56 #ifdef INET6
     57 struct aodv_rreq6 {
     58 	uint8_t		rreq_type;	/* AODV message type (1) */
     59 	uint8_t		rreq_flags;	/* various flags */
     60 	uint8_t		rreq_zero0;	/* reserved, set to zero */
     61 	uint8_t		rreq_hops;	/* number of hops from originator */
     62 	uint32_t	rreq_id;	/* request ID */
     63 	struct in6_addr	rreq_da;	/* destination IPv6 address */
     64 	uint32_t	rreq_ds;	/* destination sequence number */
     65 	struct in6_addr	rreq_oa;	/* originator IPv6 address */
     66 	uint32_t	rreq_os;	/* originator sequence number */
     67 };
     68 struct aodv_rreq6_draft_01 {
     69 	uint8_t		rreq_type;	/* AODV message type (16) */
     70 	uint8_t		rreq_flags;	/* various flags */
     71 	uint8_t		rreq_zero0;	/* reserved, set to zero */
     72 	uint8_t		rreq_hops;	/* number of hops from originator */
     73 	uint32_t	rreq_id;	/* request ID */
     74 	uint32_t	rreq_ds;	/* destination sequence number */
     75 	uint32_t	rreq_os;	/* originator sequence number */
     76 	struct in6_addr	rreq_da;	/* destination IPv6 address */
     77 	struct in6_addr	rreq_oa;	/* originator IPv6 address */
     78 };
     79 #endif
     80 
     81 #define	RREQ_JOIN	0x80		/* join (reserved for multicast */
     82 #define	RREQ_REPAIR	0x40		/* repair (reserved for multicast */
     83 #define	RREQ_GRAT	0x20		/* gratuitous RREP */
     84 #define	RREQ_DEST	0x10		/* destination only */
     85 #define	RREQ_UNKNOWN	0x08		/* unknown destination sequence num */
     86 #define	RREQ_FLAGS_MASK	0xF8		/* mask for rreq_flags */
     87 
     88 struct aodv_rrep {
     89 	uint8_t		rrep_type;	/* AODV message type (2) */
     90 	uint8_t		rrep_flags;	/* various flags */
     91 	uint8_t		rrep_ps;	/* prefix size */
     92 	uint8_t		rrep_hops;	/* number of hops from o to d */
     93 	uint32_t	rrep_da;	/* destination IPv4 address */
     94 	uint32_t	rrep_ds;	/* destination sequence number */
     95 	uint32_t	rrep_oa;	/* originator IPv4 address */
     96 	uint32_t	rrep_life;	/* lifetime of this route */
     97 };
     98 #ifdef INET6
     99 struct aodv_rrep6 {
    100 	uint8_t		rrep_type;	/* AODV message type (2) */
    101 	uint8_t		rrep_flags;	/* various flags */
    102 	uint8_t		rrep_ps;	/* prefix size */
    103 	uint8_t		rrep_hops;	/* number of hops from o to d */
    104 	struct in6_addr	rrep_da;	/* destination IPv6 address */
    105 	uint32_t	rrep_ds;	/* destination sequence number */
    106 	struct in6_addr	rrep_oa;	/* originator IPv6 address */
    107 	uint32_t	rrep_life;	/* lifetime of this route */
    108 };
    109 struct aodv_rrep6_draft_01 {
    110 	uint8_t		rrep_type;	/* AODV message type (17) */
    111 	uint8_t		rrep_flags;	/* various flags */
    112 	uint8_t		rrep_ps;	/* prefix size */
    113 	uint8_t		rrep_hops;	/* number of hops from o to d */
    114 	uint32_t	rrep_ds;	/* destination sequence number */
    115 	struct in6_addr	rrep_da;	/* destination IPv6 address */
    116 	struct in6_addr	rrep_oa;	/* originator IPv6 address */
    117 	uint32_t	rrep_life;	/* lifetime of this route */
    118 };
    119 #endif
    120 
    121 #define	RREP_REPAIR		0x80	/* repair (reserved for multicast */
    122 #define	RREP_ACK		0x40	/* acknowledgement required */
    123 #define	RREP_FLAGS_MASK		0xC0	/* mask for rrep_flags */
    124 #define	RREP_PREFIX_MASK	0x1F	/* mask for prefix size */
    125 
    126 struct rerr_unreach {
    127 	uint32_t	u_da;	/* IPv4 address */
    128 	uint32_t	u_ds;	/* sequence number */
    129 };
    130 #ifdef INET6
    131 struct rerr_unreach6 {
    132 	struct in6_addr	u_da;	/* IPv6 address */
    133 	uint32_t	u_ds;	/* sequence number */
    134 };
    135 struct rerr_unreach6_draft_01 {
    136 	struct in6_addr	u_da;	/* IPv6 address */
    137 	uint32_t	u_ds;	/* sequence number */
    138 };
    139 #endif
    140 
    141 struct aodv_rerr {
    142 	uint8_t		rerr_type;	/* AODV message type (3 or 18) */
    143 	uint8_t		rerr_flags;	/* various flags */
    144 	uint8_t		rerr_zero0;	/* reserved, set to zero */
    145 	uint8_t		rerr_dc;	/* destination count */
    146 };
    147 
    148 #define RERR_NODELETE		0x80	/* don't delete the link */
    149 #define RERR_FLAGS_MASK		0x80	/* mask for rerr_flags */
    150 
    151 struct aodv_rrep_ack {
    152 	uint8_t		ra_type;
    153 	uint8_t		ra_zero0;
    154 };
    155 
    156 #define	AODV_RREQ		1	/* route request */
    157 #define	AODV_RREP		2	/* route response */
    158 #define	AODV_RERR		3	/* error report */
    159 #define	AODV_RREP_ACK		4	/* route response acknowledgement */
    160 
    161 #define AODV_V6_DRAFT_01_RREQ		16	/* IPv6 route request */
    162 #define AODV_V6_DRAFT_01_RREP		17	/* IPv6 route response */
    163 #define AODV_V6_DRAFT_01_RERR		18	/* IPv6 error report */
    164 #define AODV_V6_DRAFT_01_RREP_ACK	19	/* IPV6 route response acknowledgment */
    165 
    166 struct aodv_ext {
    167 	uint8_t		type;		/* extension type */
    168 	uint8_t		length;		/* extension length */
    169 };
    170 
    171 struct aodv_hello {
    172 	struct	aodv_ext	eh;		/* extension header */
    173 	uint8_t			interval[4];	/* expect my next hello in
    174 						 * (n) ms
    175 						 * NOTE: this is not aligned */
    176 };
    177 
    178 #define	AODV_EXT_HELLO	1
    179 
    180 static void
    181 aodv_extension(netdissect_options *ndo,
    182                const struct aodv_ext *ep, u_int length)
    183 {
    184 	const struct aodv_hello *ah;
    185 
    186 	switch (ep->type) {
    187 	case AODV_EXT_HELLO:
    188 		ah = (const struct aodv_hello *)(const void *)ep;
    189 		ND_TCHECK(*ah);
    190 		if (length < sizeof(struct aodv_hello))
    191 			goto trunc;
    192 		ND_PRINT((ndo, "\n\text HELLO %ld ms",
    193 		    (unsigned long)EXTRACT_32BITS(&ah->interval)));
    194 		break;
    195 
    196 	default:
    197 		ND_PRINT((ndo, "\n\text %u %u", ep->type, ep->length));
    198 		break;
    199 	}
    200 	return;
    201 
    202 trunc:
    203 	ND_PRINT((ndo, " [|hello]"));
    204 }
    205 
    206 static void
    207 aodv_rreq(netdissect_options *ndo, const u_char *dat, u_int length)
    208 {
    209 	u_int i;
    210 	const struct aodv_rreq *ap = (const struct aodv_rreq *)dat;
    211 
    212 	ND_TCHECK(*ap);
    213 	if (length < sizeof(*ap))
    214 		goto trunc;
    215 	ND_PRINT((ndo, " rreq %u %s%s%s%s%shops %u id 0x%08lx\n"
    216 	    "\tdst %s seq %lu src %s seq %lu", length,
    217 	    ap->rreq_type & RREQ_JOIN ? "[J]" : "",
    218 	    ap->rreq_type & RREQ_REPAIR ? "[R]" : "",
    219 	    ap->rreq_type & RREQ_GRAT ? "[G]" : "",
    220 	    ap->rreq_type & RREQ_DEST ? "[D]" : "",
    221 	    ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
    222 	    ap->rreq_hops,
    223 	    (unsigned long)EXTRACT_32BITS(&ap->rreq_id),
    224 	    ipaddr_string(ndo, &ap->rreq_da),
    225 	    (unsigned long)EXTRACT_32BITS(&ap->rreq_ds),
    226 	    ipaddr_string(ndo, &ap->rreq_oa),
    227 	    (unsigned long)EXTRACT_32BITS(&ap->rreq_os)));
    228 	i = length - sizeof(*ap);
    229 	if (i >= sizeof(struct aodv_ext))
    230 		aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
    231 	return;
    232 
    233 trunc:
    234 	ND_PRINT((ndo, " [|rreq"));
    235 }
    236 
    237 static void
    238 aodv_rrep(netdissect_options *ndo, const u_char *dat, u_int length)
    239 {
    240 	u_int i;
    241 	const struct aodv_rrep *ap = (const struct aodv_rrep *)dat;
    242 
    243 	ND_TCHECK(*ap);
    244 	if (length < sizeof(*ap))
    245 		goto trunc;
    246 	ND_PRINT((ndo, " rrep %u %s%sprefix %u hops %u\n"
    247 	    "\tdst %s dseq %lu src %s %lu ms", length,
    248 	    ap->rrep_type & RREP_REPAIR ? "[R]" : "",
    249 	    ap->rrep_type & RREP_ACK ? "[A] " : " ",
    250 	    ap->rrep_ps & RREP_PREFIX_MASK,
    251 	    ap->rrep_hops,
    252 	    ipaddr_string(ndo, &ap->rrep_da),
    253 	    (unsigned long)EXTRACT_32BITS(&ap->rrep_ds),
    254 	    ipaddr_string(ndo, &ap->rrep_oa),
    255 	    (unsigned long)EXTRACT_32BITS(&ap->rrep_life)));
    256 	i = length - sizeof(*ap);
    257 	if (i >= sizeof(struct aodv_ext))
    258 		aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
    259 	return;
    260 
    261 trunc:
    262 	ND_PRINT((ndo, " [|rreq"));
    263 }
    264 
    265 static void
    266 aodv_rerr(netdissect_options *ndo, const u_char *dat, u_int length)
    267 {
    268 	u_int i, dc;
    269 	const struct aodv_rerr *ap = (const struct aodv_rerr *)dat;
    270 	const struct rerr_unreach *dp;
    271 
    272 	ND_TCHECK(*ap);
    273 	if (length < sizeof(*ap))
    274 		goto trunc;
    275 	ND_PRINT((ndo, " rerr %s [items %u] [%u]:",
    276 	    ap->rerr_flags & RERR_NODELETE ? "[D]" : "",
    277 	    ap->rerr_dc, length));
    278 	dp = (struct rerr_unreach *)(dat + sizeof(*ap));
    279 	i = length - sizeof(*ap);
    280 	for (dc = ap->rerr_dc; dc != 0; dc--) {
    281 		ND_TCHECK(*dp);
    282 		if (i < sizeof(*dp))
    283 			goto trunc;
    284 		ND_PRINT((ndo, " {%s}(%ld)", ipaddr_string(ndo, &dp->u_da),
    285 		    (unsigned long)EXTRACT_32BITS(&dp->u_ds)));
    286 		dp++;
    287 		i -= sizeof(*dp);
    288 	}
    289 	return;
    290 
    291 trunc:
    292 	ND_PRINT((ndo, "[|rerr]"));
    293 }
    294 
    295 static void
    296 #ifdef INET6
    297 aodv_v6_rreq(netdissect_options *ndo, const u_char *dat, u_int length)
    298 #else
    299 aodv_v6_rreq(netdissect_options *ndo, const u_char *dat _U_, u_int length)
    300 #endif
    301 {
    302 #ifdef INET6
    303 	u_int i;
    304 	const struct aodv_rreq6 *ap = (const struct aodv_rreq6 *)dat;
    305 
    306 	ND_TCHECK(*ap);
    307 	if (length < sizeof(*ap))
    308 		goto trunc;
    309 	ND_PRINT((ndo, " v6 rreq %u %s%s%s%s%shops %u id 0x%08lx\n"
    310 	    "\tdst %s seq %lu src %s seq %lu", length,
    311 	    ap->rreq_type & RREQ_JOIN ? "[J]" : "",
    312 	    ap->rreq_type & RREQ_REPAIR ? "[R]" : "",
    313 	    ap->rreq_type & RREQ_GRAT ? "[G]" : "",
    314 	    ap->rreq_type & RREQ_DEST ? "[D]" : "",
    315 	    ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
    316 	    ap->rreq_hops,
    317 	    (unsigned long)EXTRACT_32BITS(&ap->rreq_id),
    318 	    ip6addr_string(ndo, &ap->rreq_da),
    319 	    (unsigned long)EXTRACT_32BITS(&ap->rreq_ds),
    320 	    ip6addr_string(ndo, &ap->rreq_oa),
    321 	    (unsigned long)EXTRACT_32BITS(&ap->rreq_os)));
    322 	i = length - sizeof(*ap);
    323 	if (i >= sizeof(struct aodv_ext))
    324 		aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
    325 	return;
    326 
    327 trunc:
    328 	ND_PRINT((ndo, " [|rreq"));
    329 #else
    330 	ND_PRINT((ndo, " v6 rreq %u", length));
    331 #endif
    332 }
    333 
    334 static void
    335 #ifdef INET6
    336 aodv_v6_rrep(netdissect_options *ndo, const u_char *dat, u_int length)
    337 #else
    338 aodv_v6_rrep(netdissect_options *ndo, const u_char *dat _U_, u_int length)
    339 #endif
    340 {
    341 #ifdef INET6
    342 	u_int i;
    343 	const struct aodv_rrep6 *ap = (const struct aodv_rrep6 *)dat;
    344 
    345 	ND_TCHECK(*ap);
    346 	if (length < sizeof(*ap))
    347 		goto trunc;
    348 	ND_PRINT((ndo, " rrep %u %s%sprefix %u hops %u\n"
    349 	   "\tdst %s dseq %lu src %s %lu ms", length,
    350 	    ap->rrep_type & RREP_REPAIR ? "[R]" : "",
    351 	    ap->rrep_type & RREP_ACK ? "[A] " : " ",
    352 	    ap->rrep_ps & RREP_PREFIX_MASK,
    353 	    ap->rrep_hops,
    354 	    ip6addr_string(ndo, &ap->rrep_da),
    355 	    (unsigned long)EXTRACT_32BITS(&ap->rrep_ds),
    356 	    ip6addr_string(ndo, &ap->rrep_oa),
    357 	    (unsigned long)EXTRACT_32BITS(&ap->rrep_life)));
    358 	i = length - sizeof(*ap);
    359 	if (i >= sizeof(struct aodv_ext))
    360 		aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
    361 	return;
    362 
    363 trunc:
    364 	ND_PRINT((ndo, " [|rreq"));
    365 #else
    366 	ND_PRINT((ndo, " rrep %u", length));
    367 #endif
    368 }
    369 
    370 static void
    371 #ifdef INET6
    372 aodv_v6_rerr(netdissect_options *ndo, const u_char *dat, u_int length)
    373 #else
    374 aodv_v6_rerr(netdissect_options *ndo, const u_char *dat _U_, u_int length)
    375 #endif
    376 {
    377 #ifdef INET6
    378 	u_int i, dc;
    379 	const struct aodv_rerr *ap = (const struct aodv_rerr *)dat;
    380 	const struct rerr_unreach6 *dp6;
    381 
    382 	ND_TCHECK(*ap);
    383 	if (length < sizeof(*ap))
    384 		goto trunc;
    385 	ND_PRINT((ndo, " rerr %s [items %u] [%u]:",
    386 	    ap->rerr_flags & RERR_NODELETE ? "[D]" : "",
    387 	    ap->rerr_dc, length));
    388 	dp6 = (struct rerr_unreach6 *)(void *)(ap + 1);
    389 	i = length - sizeof(*ap);
    390 	for (dc = ap->rerr_dc; dc != 0; dc--) {
    391 		ND_TCHECK(*dp6);
    392 		if (i < sizeof(*dp6))
    393 			goto trunc;
    394 		ND_PRINT((ndo, " {%s}(%ld)", ip6addr_string(ndo, &dp6->u_da),
    395 		    (unsigned long)EXTRACT_32BITS(&dp6->u_ds)));
    396 		dp6++;
    397 		i -= sizeof(*dp6);
    398 	}
    399 	return;
    400 
    401 trunc:
    402 	ND_PRINT((ndo, "[|rerr]"));
    403 #else
    404 	ND_PRINT((ndo, " rerr %u", length));
    405 #endif
    406 }
    407 
    408 static void
    409 #ifdef INET6
    410 aodv_v6_draft_01_rreq(netdissect_options *ndo, const u_char *dat, u_int length)
    411 #else
    412 aodv_v6_draft_01_rreq(netdissect_options *ndo, const u_char *dat _U_, u_int length)
    413 #endif
    414 {
    415 #ifdef INET6
    416 	u_int i;
    417 	const struct aodv_rreq6_draft_01 *ap = (const struct aodv_rreq6_draft_01 *)dat;
    418 
    419 	ND_TCHECK(*ap);
    420 	if (length < sizeof(*ap))
    421 		goto trunc;
    422 	ND_PRINT((ndo, " rreq %u %s%s%s%s%shops %u id 0x%08lx\n"
    423 	    "\tdst %s seq %lu src %s seq %lu", length,
    424 	    ap->rreq_type & RREQ_JOIN ? "[J]" : "",
    425 	    ap->rreq_type & RREQ_REPAIR ? "[R]" : "",
    426 	    ap->rreq_type & RREQ_GRAT ? "[G]" : "",
    427 	    ap->rreq_type & RREQ_DEST ? "[D]" : "",
    428 	    ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
    429 	    ap->rreq_hops,
    430 	    (unsigned long)EXTRACT_32BITS(&ap->rreq_id),
    431 	    ip6addr_string(ndo, &ap->rreq_da),
    432 	    (unsigned long)EXTRACT_32BITS(&ap->rreq_ds),
    433 	    ip6addr_string(ndo, &ap->rreq_oa),
    434 	    (unsigned long)EXTRACT_32BITS(&ap->rreq_os)));
    435 	i = length - sizeof(*ap);
    436 	if (i >= sizeof(struct aodv_ext))
    437 		aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
    438 	return;
    439 
    440 trunc:
    441 	ND_PRINT((ndo, " [|rreq"));
    442 #else
    443 	ND_PRINT((ndo, " rreq %u", length));
    444 #endif
    445 }
    446 
    447 static void
    448 #ifdef INET6
    449 aodv_v6_draft_01_rrep(netdissect_options *ndo, const u_char *dat, u_int length)
    450 #else
    451 aodv_v6_draft_01_rrep(netdissect_options *ndo, const u_char *dat _U_, u_int length)
    452 #endif
    453 {
    454 #ifdef INET6
    455 	u_int i;
    456 	const struct aodv_rrep6_draft_01 *ap = (const struct aodv_rrep6_draft_01 *)dat;
    457 
    458 	ND_TCHECK(*ap);
    459 	if (length < sizeof(*ap))
    460 		goto trunc;
    461 	ND_PRINT((ndo, " rrep %u %s%sprefix %u hops %u\n"
    462 	   "\tdst %s dseq %lu src %s %lu ms", length,
    463 	    ap->rrep_type & RREP_REPAIR ? "[R]" : "",
    464 	    ap->rrep_type & RREP_ACK ? "[A] " : " ",
    465 	    ap->rrep_ps & RREP_PREFIX_MASK,
    466 	    ap->rrep_hops,
    467 	    ip6addr_string(ndo, &ap->rrep_da),
    468 	    (unsigned long)EXTRACT_32BITS(&ap->rrep_ds),
    469 	    ip6addr_string(ndo, &ap->rrep_oa),
    470 	    (unsigned long)EXTRACT_32BITS(&ap->rrep_life)));
    471 	i = length - sizeof(*ap);
    472 	if (i >= sizeof(struct aodv_ext))
    473 		aodv_extension(ndo, (const struct aodv_ext *)(dat + sizeof(*ap)), i);
    474 	return;
    475 
    476 trunc:
    477 	ND_PRINT((ndo, " [|rreq"));
    478 #else
    479 	ND_PRINT((ndo, " rrep %u", length));
    480 #endif
    481 }
    482 
    483 static void
    484 #ifdef INET6
    485 aodv_v6_draft_01_rerr(netdissect_options *ndo, const u_char *dat, u_int length)
    486 #else
    487 aodv_v6_draft_01_rerr(netdissect_options *ndo, const u_char *dat _U_, u_int length)
    488 #endif
    489 {
    490 #ifdef INET6
    491 	u_int i, dc;
    492 	const struct aodv_rerr *ap = (const struct aodv_rerr *)dat;
    493 	const struct rerr_unreach6_draft_01 *dp6;
    494 
    495 	ND_TCHECK(*ap);
    496 	if (length < sizeof(*ap))
    497 		goto trunc;
    498 	ND_PRINT((ndo, " rerr %s [items %u] [%u]:",
    499 	    ap->rerr_flags & RERR_NODELETE ? "[D]" : "",
    500 	    ap->rerr_dc, length));
    501 	dp6 = (struct rerr_unreach6_draft_01 *)(void *)(ap + 1);
    502 	i = length - sizeof(*ap);
    503 	for (dc = ap->rerr_dc; dc != 0; dc--) {
    504 		ND_TCHECK(*dp6);
    505 		if (i < sizeof(*dp6))
    506 			goto trunc;
    507 		ND_PRINT((ndo, " {%s}(%ld)", ip6addr_string(ndo, &dp6->u_da),
    508 		    (unsigned long)EXTRACT_32BITS(&dp6->u_ds)));
    509 		dp6++;
    510 		i -= sizeof(*dp6);
    511 	}
    512 	return;
    513 
    514 trunc:
    515 	ND_PRINT((ndo, "[|rerr]"));
    516 #else
    517 	ND_PRINT((ndo, " rerr %u", length));
    518 #endif
    519 }
    520 
    521 void
    522 aodv_print(netdissect_options *ndo,
    523            const u_char *dat, u_int length, int is_ip6)
    524 {
    525 	uint8_t msg_type;
    526 
    527 	/*
    528 	 * The message type is the first byte; make sure we have it
    529 	 * and then fetch it.
    530 	 */
    531 	ND_TCHECK(*dat);
    532 	msg_type = *dat;
    533 	ND_PRINT((ndo, " aodv"));
    534 
    535 	switch (msg_type) {
    536 
    537 	case AODV_RREQ:
    538 		if (is_ip6)
    539 			aodv_v6_rreq(ndo, dat, length);
    540 		else
    541 			aodv_rreq(ndo, dat, length);
    542 		break;
    543 
    544 	case AODV_RREP:
    545 		if (is_ip6)
    546 			aodv_v6_rrep(ndo, dat, length);
    547 		else
    548 			aodv_rrep(ndo, dat, length);
    549 		break;
    550 
    551 	case AODV_RERR:
    552 		if (is_ip6)
    553 			aodv_v6_rerr(ndo, dat, length);
    554 		else
    555 			aodv_rerr(ndo, dat, length);
    556 		break;
    557 
    558 	case AODV_RREP_ACK:
    559 		ND_PRINT((ndo, " rrep-ack %u", length));
    560 		break;
    561 
    562 	case AODV_V6_DRAFT_01_RREQ:
    563 		aodv_v6_draft_01_rreq(ndo, dat, length);
    564 		break;
    565 
    566 	case AODV_V6_DRAFT_01_RREP:
    567 		aodv_v6_draft_01_rrep(ndo, dat, length);
    568 		break;
    569 
    570 	case AODV_V6_DRAFT_01_RERR:
    571 		aodv_v6_draft_01_rerr(ndo, dat, length);
    572 		break;
    573 
    574 	case AODV_V6_DRAFT_01_RREP_ACK:
    575 		ND_PRINT((ndo, " rrep-ack %u", length));
    576 		break;
    577 
    578 	default:
    579 		ND_PRINT((ndo, " type %u %u", msg_type, length));
    580 	}
    581 	return;
    582 
    583 trunc:
    584 	ND_PRINT((ndo, " [|aodv]"));
    585 }
    586