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