1 /*
2  * Copyright (c) 2003 Bruce M. Simpson <bms@spc.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *        This product includes software developed by Bruce M. Simpson.
16  * 4. Neither the name of Bruce M. Simpson nor the names of co-
17  *    contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY Bruce M. Simpson AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL Bruce M. Simpson OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #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
aodv_extension(netdissect_options * ndo,const struct aodv_ext * ep,u_int length)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
aodv_rreq(netdissect_options * ndo,const u_char * dat,u_int length)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
aodv_rrep(netdissect_options * ndo,const u_char * dat,u_int length)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
aodv_rerr(netdissect_options * ndo,const u_char * dat,u_int length)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
aodv_v6_rreq(netdissect_options * ndo,const u_char * dat,u_int length)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
aodv_v6_rrep(netdissect_options * ndo,const u_char * dat,u_int length)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
aodv_v6_rerr(netdissect_options * ndo,const u_char * dat,u_int length)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
aodv_v6_draft_01_rreq(netdissect_options * ndo,const u_char * dat,u_int length)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
aodv_v6_draft_01_rrep(netdissect_options * ndo,const u_char * dat,u_int length)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
aodv_v6_draft_01_rerr(netdissect_options * ndo,const u_char * dat,u_int length)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
aodv_print(netdissect_options * ndo,const u_char * dat,u_int length,int is_ip6)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