Blob Blame History Raw
From 357525b6942eef3ef9696f1fe92ba7fe2ed68ac2 Mon Sep 17 00:00:00 2001
From: Michal Sekletar <msekleta@redhat.com>
Date: Fri, 21 Nov 2014 12:19:32 +0100
Subject: [PATCH] Fix for CVE-2014-8769

(cherry picked from ab4e52b94aac6cb729a5a695aa612d5ebda2ec3a
                    3e8a443c3671baa37ae7870f08fb9b4bf386fd24)
---
 aodv.h       |  20 ----
 print-aodv.c | 315 +++++++++++++++++++++++++++++++----------------------------
 2 files changed, 168 insertions(+), 167 deletions(-)

diff --git a/aodv.h b/aodv.h
index 456ec8b..18467d5 100644
--- a/aodv.h
+++ b/aodv.h
@@ -134,13 +134,6 @@ struct aodv_rerr {
 	u_int8_t	rerr_flags;	/* various flags */
 	u_int8_t	rerr_zero0;	/* reserved, set to zero */
 	u_int8_t	rerr_dc;	/* destination count */
-	union {
-		struct	rerr_unreach dest[1];
-#ifdef INET6
-		struct	rerr_unreach6 dest6[1];
-		struct	rerr_unreach6_draft_01 dest6_draft_01[1];
-#endif
-	} r;
 };
 
 #define RERR_NODELETE		0x80	/* don't delete the link */
@@ -151,19 +144,6 @@ struct aodv_rrep_ack {
 	u_int8_t	ra_zero0;
 };
 
-union aodv {
-	struct aodv_rreq rreq;
-	struct aodv_rrep rrep;
-	struct aodv_rerr rerr;
-	struct aodv_rrep_ack rrep_ack;
-#ifdef INET6
-	struct aodv_rreq6 rreq6;
-	struct aodv_rreq6_draft_01 rreq6_draft_01;
-	struct aodv_rrep6 rrep6;
-	struct aodv_rrep6_draft_01 rrep6_draft_01;
-#endif
-};
-
 #define	AODV_RREQ		1	/* route request */
 #define	AODV_RREP		2	/* route response */
 #define	AODV_RERR		3	/* error report */
diff --git a/print-aodv.c b/print-aodv.c
index c5f6622..b4f7989 100644
--- a/print-aodv.c
+++ b/print-aodv.c
@@ -82,7 +82,7 @@ aodv_extension(const struct aodv_ext *ep, u_int length)
 }
 
 static void
-aodv_rreq(const union aodv *ap, const u_char *dat, u_int length)
+aodv_rreq(const struct aodv_rreq *ap, const u_char *dat, u_int length)
 {
 	u_int i;
 
@@ -91,30 +91,31 @@ aodv_rreq(const union aodv *ap, const u_char *dat, u_int length)
 		return;
 	}
 	i = min(length, (u_int)(snapend - dat));
-	if (i < sizeof(ap->rreq)) {
+	if (i < sizeof(*ap)) {
 		printf(" [|rreq]");
 		return;
 	}
-	i -= sizeof(ap->rreq);
+	i -= sizeof(*ap);
 	printf(" rreq %u %s%s%s%s%shops %u id 0x%08lx\n"
 	    "\tdst %s seq %lu src %s seq %lu", length,
-	    ap->rreq.rreq_type & RREQ_JOIN ? "[J]" : "",
-	    ap->rreq.rreq_type & RREQ_REPAIR ? "[R]" : "",
-	    ap->rreq.rreq_type & RREQ_GRAT ? "[G]" : "",
-	    ap->rreq.rreq_type & RREQ_DEST ? "[D]" : "",
-	    ap->rreq.rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
-	    ap->rreq.rreq_hops,
-	    (unsigned long)EXTRACT_32BITS(&ap->rreq.rreq_id),
-	    ipaddr_string(&ap->rreq.rreq_da),
-	    (unsigned long)EXTRACT_32BITS(&ap->rreq.rreq_ds),
-	    ipaddr_string(&ap->rreq.rreq_oa),
-	    (unsigned long)EXTRACT_32BITS(&ap->rreq.rreq_os));
+               ap->rreq_type & RREQ_JOIN ? "[J]" : "",
+               ap->rreq_type & RREQ_REPAIR ? "[R]" : "",
+               ap->rreq_type & RREQ_GRAT ? "[G]" : "",
+               ap->rreq_type & RREQ_DEST ? "[D]" : "",
+               ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
+               ap->rreq_hops,
+               (unsigned long)EXTRACT_32BITS(&ap->rreq_id),
+               ipaddr_string(&ap->rreq_da),
+               (unsigned long)EXTRACT_32BITS(&ap->rreq_ds),
+               ipaddr_string(&ap->rreq_oa),
+               (unsigned long)EXTRACT_32BITS(&ap->rreq_os));
+
 	if (i >= sizeof(struct aodv_ext))
-		aodv_extension((void *)(&ap->rreq + 1), i);
+		aodv_extension((void *)(ap + 1), i);
 }
 
 static void
-aodv_rrep(const union aodv *ap, const u_char *dat, u_int length)
+aodv_rrep(const struct aodv_rrep *ap, const u_char *dat, u_int length)
 {
 	u_int i;
 
@@ -123,62 +124,60 @@ aodv_rrep(const union aodv *ap, const u_char *dat, u_int length)
 		return;
 	}
 	i = min(length, (u_int)(snapend - dat));
-	if (i < sizeof(ap->rrep)) {
+	if (i < sizeof(*ap)) {
 		printf(" [|rrep]");
 		return;
 	}
-	i -= sizeof(ap->rrep);
+	i -= sizeof(*ap);
 	printf(" rrep %u %s%sprefix %u hops %u\n"
 	    "\tdst %s dseq %lu src %s %lu ms", length,
-	    ap->rrep.rrep_type & RREP_REPAIR ? "[R]" : "",
-	    ap->rrep.rrep_type & RREP_ACK ? "[A] " : " ",
-	    ap->rrep.rrep_ps & RREP_PREFIX_MASK,
-	    ap->rrep.rrep_hops,
-	    ipaddr_string(&ap->rrep.rrep_da),
-	    (unsigned long)EXTRACT_32BITS(&ap->rrep.rrep_ds),
-	    ipaddr_string(&ap->rrep.rrep_oa),
-	    (unsigned long)EXTRACT_32BITS(&ap->rrep.rrep_life));
-	if (i >= sizeof(struct aodv_ext))
-		aodv_extension((void *)(&ap->rrep + 1), i);
+	    ap->rrep_type & RREP_REPAIR ? "[R]" : "",
+	    ap->rrep_type & RREP_ACK ? "[A] " : " ",
+	    ap->rrep_ps & RREP_PREFIX_MASK,
+	    ap->rrep_hops,
+	    ipaddr_string(&ap->rrep_da),
+	    (unsigned long)EXTRACT_32BITS(&ap->rrep_ds),
+	    ipaddr_string(&ap->rrep_oa),
+               (unsigned long)EXTRACT_32BITS(&ap->rrep_life));
+
+        if (i >= sizeof(struct aodv_ext))
+		aodv_extension((void *)(ap + 1), i);
 }
 
 static void
-aodv_rerr(const union aodv *ap, const u_char *dat, u_int length)
+aodv_rerr(const struct aodv_rerr *ap, const u_char *dat, u_int length)
 {
-	u_int i;
-	const struct rerr_unreach *dp = NULL;
-	int n, trunc;
+	u_int i, dc;
+	const struct rerr_unreach *dp;
 
 	if (snapend < dat) {
 		printf(" [|aodv]");
 		return;
 	}
 	i = min(length, (u_int)(snapend - dat));
-	if (i < offsetof(struct aodv_rerr, r)) {
+	if (i < sizeof(*ap)) {
 		printf(" [|rerr]");
 		return;
 	}
-	i -= offsetof(struct aodv_rerr, r);
-	dp = &ap->rerr.r.dest[0];
-	n = ap->rerr.rerr_dc * sizeof(ap->rerr.r.dest[0]);
+	i -= sizeof(*ap);
 	printf(" rerr %s [items %u] [%u]:",
-	    ap->rerr.rerr_flags & RERR_NODELETE ? "[D]" : "",
-	    ap->rerr.rerr_dc, length);
-	trunc = n - (i/sizeof(ap->rerr.r.dest[0]));
-	for (; i >= sizeof(ap->rerr.r.dest[0]);
-	    ++dp, i -= sizeof(ap->rerr.r.dest[0])) {
+	    ap->rerr_flags & RERR_NODELETE ? "[D]" : "",
+	    ap->rerr_dc, length);
+        dp = (struct rerr_unreach *)(void *)(ap + 1);
+	for (dc = ap->rerr_dc; dc != 0 && i >= sizeof(*dp);
+             ++dp, --dc, i -= sizeof(*dp)) {
 		printf(" {%s}(%ld)", ipaddr_string(&dp->u_da),
 		    (unsigned long)EXTRACT_32BITS(&dp->u_ds));
 	}
-	if (trunc)
+        if ((i % sizeof(*dp)) != 0)
 		printf("[|rerr]");
 }
 
 static void
 #ifdef INET6
-aodv_v6_rreq(const union aodv *ap, const u_char *dat, u_int length)
+aodv_v6_rreq(const struct aodv_rreq6 *ap, const u_char *dat, u_int length)
 #else
-aodv_v6_rreq(const union aodv *ap _U_, const u_char *dat _U_, u_int length)
+aodv_v6_rreq(const struct aodv_rreq6 *ap _U_, const u_char *dat _U_, u_int length)
 #endif
 {
 #ifdef INET6
@@ -189,26 +188,27 @@ aodv_v6_rreq(const union aodv *ap _U_, const u_char *dat _U_, u_int length)
 		return;
 	}
 	i = min(length, (u_int)(snapend - dat));
-	if (i < sizeof(ap->rreq6)) {
+	if (i < sizeof(*ap)) {
 		printf(" [|rreq6]");
 		return;
 	}
-	i -= sizeof(ap->rreq6);
+	i -= sizeof(*ap);
 	printf(" v6 rreq %u %s%s%s%s%shops %u id 0x%08lx\n"
 	    "\tdst %s seq %lu src %s seq %lu", length,
-	    ap->rreq6.rreq_type & RREQ_JOIN ? "[J]" : "",
-	    ap->rreq6.rreq_type & RREQ_REPAIR ? "[R]" : "",
-	    ap->rreq6.rreq_type & RREQ_GRAT ? "[G]" : "",
-	    ap->rreq6.rreq_type & RREQ_DEST ? "[D]" : "",
-	    ap->rreq6.rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
-	    ap->rreq6.rreq_hops,
-	    (unsigned long)EXTRACT_32BITS(&ap->rreq6.rreq_id),
-	    ip6addr_string(&ap->rreq6.rreq_da),
-	    (unsigned long)EXTRACT_32BITS(&ap->rreq6.rreq_ds),
-	    ip6addr_string(&ap->rreq6.rreq_oa),
-	    (unsigned long)EXTRACT_32BITS(&ap->rreq6.rreq_os));
+               ap->rreq_type & RREQ_JOIN ? "[J]" : "",
+               ap->rreq_type & RREQ_REPAIR ? "[R]" : "",
+               ap->rreq_type & RREQ_GRAT ? "[G]" : "",
+               ap->rreq_type & RREQ_DEST ? "[D]" : "",
+               ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
+               ap->rreq_hops,
+               (unsigned long)EXTRACT_32BITS(&ap->rreq_id),
+               ip6addr_string(&ap->rreq_da),
+               (unsigned long)EXTRACT_32BITS(&ap->rreq_ds),
+               ip6addr_string(&ap->rreq_oa),
+               (unsigned long)EXTRACT_32BITS(&ap->rreq_os));
+
 	if (i >= sizeof(struct aodv_ext))
-		aodv_extension((void *)(&ap->rreq6 + 1), i);
+		aodv_extension((void *)(ap + 1), i);
 #else
 	printf(" v6 rreq %u", length);
 #endif
@@ -216,9 +216,9 @@ aodv_v6_rreq(const union aodv *ap _U_, const u_char *dat _U_, u_int length)
 
 static void
 #ifdef INET6
-aodv_v6_rrep(const union aodv *ap, const u_char *dat, u_int length)
+aodv_v6_rrep(const struct aodv_rrep6 *ap, const u_char *dat, u_int length)
 #else
-aodv_v6_rrep(const union aodv *ap _U_, const u_char *dat _U_, u_int length)
+aodv_v6_rrep(const struct aodv_rrep6 *ap _U_, const u_char *dat _U_, u_int length)
 #endif
 {
 #ifdef INET6
@@ -229,23 +229,24 @@ aodv_v6_rrep(const union aodv *ap _U_, const u_char *dat _U_, u_int length)
 		return;
 	}
 	i = min(length, (u_int)(snapend - dat));
-	if (i < sizeof(ap->rrep6)) {
+	if (i < sizeof(*ap)) {
 		printf(" [|rrep6]");
 		return;
 	}
-	i -= sizeof(ap->rrep6);
+	i -= sizeof(*ap);
 	printf(" rrep %u %s%sprefix %u hops %u\n"
 	   "\tdst %s dseq %lu src %s %lu ms", length,
-	    ap->rrep6.rrep_type & RREP_REPAIR ? "[R]" : "",
-	    ap->rrep6.rrep_type & RREP_ACK ? "[A] " : " ",
-	    ap->rrep6.rrep_ps & RREP_PREFIX_MASK,
-	    ap->rrep6.rrep_hops,
-	    ip6addr_string(&ap->rrep6.rrep_da),
-	    (unsigned long)EXTRACT_32BITS(&ap->rrep6.rrep_ds),
-	    ip6addr_string(&ap->rrep6.rrep_oa),
-	    (unsigned long)EXTRACT_32BITS(&ap->rrep6.rrep_life));
+               ap->rrep_type & RREP_REPAIR ? "[R]" : "",
+               ap->rrep_type & RREP_ACK ? "[A] " : " ",
+               ap->rrep_ps & RREP_PREFIX_MASK,
+               ap->rrep_hops,
+               ip6addr_string(&ap->rrep_da),
+               (unsigned long)EXTRACT_32BITS(&ap->rrep_ds),
+               ip6addr_string(&ap->rrep_oa),
+               (unsigned long)EXTRACT_32BITS(&ap->rrep_life));
+
 	if (i >= sizeof(struct aodv_ext))
-		aodv_extension((void *)(&ap->rrep6 + 1), i);
+		aodv_extension((void *)(ap + 1), i);
 #else
 	printf(" rrep %u", length);
 #endif
@@ -253,28 +254,36 @@ aodv_v6_rrep(const union aodv *ap _U_, const u_char *dat _U_, u_int length)
 
 static void
 #ifdef INET6
-aodv_v6_rerr(const union aodv *ap, u_int length)
+aodv_v6_rerr(const struct aodv_rerr *ap, const u_char *dat, u_int length)
 #else
-aodv_v6_rerr(const union aodv *ap _U_, u_int length)
+aodv_v6_rerr(const struct aodv_rerr *ap _U_, const u_char *dat, u_int length)
 #endif
 {
 #ifdef INET6
-	const struct rerr_unreach6 *dp6 = NULL;
-	int i, j, n, trunc;
+	u_int i, dc;
+	const struct rerr_unreach6 *dp6;
+
+	if (snapend < dat) {
+		printf(" [|aodv]");
+		return;
+	}
+	i = min(length, (u_int)(snapend - dat));
+        if (i < sizeof(*ap)) {
+		printf(" [|rerr]");
+		return;
+	}
+	i -= sizeof(*ap);
 
-	i = length - offsetof(struct aodv_rerr, r);
-	j = sizeof(ap->rerr.r.dest6[0]);
-	dp6 = &ap->rerr.r.dest6[0];
-	n = ap->rerr.rerr_dc * j;
 	printf(" rerr %s [items %u] [%u]:",
-	    ap->rerr.rerr_flags & RERR_NODELETE ? "[D]" : "",
-	    ap->rerr.rerr_dc, length);
-	trunc = n - (i/j);
-	for (; i -= j >= 0; ++dp6) {
+	    ap->rerr_flags & RERR_NODELETE ? "[D]" : "",
+	    ap->rerr_dc, length);
+	dp6 = (struct rerr_unreach6 *)(void *)(ap + 1);
+	for (dc = ap->rerr_dc; dc != 0 && i >= sizeof(*dp6);
+	    ++dp6, --dc, i -= sizeof(*dp6)) {
 		printf(" {%s}(%ld)", ip6addr_string(&dp6->u_da),
 		    (unsigned long)EXTRACT_32BITS(&dp6->u_ds));
 	}
-	if (trunc)
+	if ((i % sizeof(*dp6)) != 0)
 		printf("[|rerr]");
 #else
 	printf(" rerr %u", length);
@@ -283,9 +292,9 @@ aodv_v6_rerr(const union aodv *ap _U_, u_int length)
 
 static void
 #ifdef INET6
-aodv_v6_draft_01_rreq(const union aodv *ap, const u_char *dat, u_int length)
+aodv_v6_draft_01_rreq(const struct aodv_rreq6_draft_01 *ap, const u_char *dat, u_int length)
 #else
-aodv_v6_draft_01_rreq(const union aodv *ap _U_, const u_char *dat _U_,
+aodv_v6_draft_01_rreq(const struct aodv_rreq6_draft_01 *ap _U_, const u_char *dat _U_,
     u_int length)
 #endif
 {
@@ -297,26 +306,27 @@ aodv_v6_draft_01_rreq(const union aodv *ap _U_, const u_char *dat _U_,
 		return;
 	}
 	i = min(length, (u_int)(snapend - dat));
-	if (i < sizeof(ap->rreq6_draft_01)) {
+	if (i < sizeof(*ap)) {
 		printf(" [|rreq6]");
 		return;
 	}
-	i -= sizeof(ap->rreq6_draft_01);
+	i -= sizeof(*ap);
 	printf(" rreq %u %s%s%s%s%shops %u id 0x%08lx\n"
 	    "\tdst %s seq %lu src %s seq %lu", length,
-	    ap->rreq6_draft_01.rreq_type & RREQ_JOIN ? "[J]" : "",
-	    ap->rreq6_draft_01.rreq_type & RREQ_REPAIR ? "[R]" : "",
-	    ap->rreq6_draft_01.rreq_type & RREQ_GRAT ? "[G]" : "",
-	    ap->rreq6_draft_01.rreq_type & RREQ_DEST ? "[D]" : "",
-	    ap->rreq6_draft_01.rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
-	    ap->rreq6_draft_01.rreq_hops,
-	    (unsigned long)EXTRACT_32BITS(&ap->rreq6_draft_01.rreq_id),
-	    ip6addr_string(&ap->rreq6_draft_01.rreq_da),
-	    (unsigned long)EXTRACT_32BITS(&ap->rreq6_draft_01.rreq_ds),
-	    ip6addr_string(&ap->rreq6_draft_01.rreq_oa),
-	    (unsigned long)EXTRACT_32BITS(&ap->rreq6_draft_01.rreq_os));
+               ap->rreq_type & RREQ_JOIN ? "[J]" : "",
+               ap->rreq_type & RREQ_REPAIR ? "[R]" : "",
+               ap->rreq_type & RREQ_GRAT ? "[G]" : "",
+               ap->rreq_type & RREQ_DEST ? "[D]" : "",
+               ap->rreq_type & RREQ_UNKNOWN ? "[U] " : " ",
+               ap->rreq_hops,
+               (unsigned long)EXTRACT_32BITS(&ap->rreq_id),
+               ip6addr_string(&ap->rreq_da),
+               (unsigned long)EXTRACT_32BITS(&ap->rreq_ds),
+               ip6addr_string(&ap->rreq_oa),
+               (unsigned long)EXTRACT_32BITS(&ap->rreq_os));
+
 	if (i >= sizeof(struct aodv_ext))
-		aodv_extension((void *)(&ap->rreq6_draft_01 + 1), i);
+		aodv_extension((void *)(ap + 1), i);
 #else
 	printf(" rreq %u", length);
 #endif
@@ -324,9 +334,9 @@ aodv_v6_draft_01_rreq(const union aodv *ap _U_, const u_char *dat _U_,
 
 static void
 #ifdef INET6
-aodv_v6_draft_01_rrep(const union aodv *ap, const u_char *dat, u_int length)
+aodv_v6_draft_01_rrep(const struct aodv_rrep6_draft_01 *ap, const u_char *dat, u_int length)
 #else
-aodv_v6_draft_01_rrep(const union aodv *ap _U_, const u_char *dat _U_,
+aodv_v6_draft_01_rrep(const struct aodv_rrep6_draft_01 *ap _U_, const u_char *dat _U_,
     u_int length)
 #endif
 {
@@ -338,23 +348,24 @@ aodv_v6_draft_01_rrep(const union aodv *ap _U_, const u_char *dat _U_,
 		return;
 	}
 	i = min(length, (u_int)(snapend - dat));
-	if (i < sizeof(ap->rrep6_draft_01)) {
+	if (i < sizeof(*ap)) {
 		printf(" [|rrep6]");
 		return;
 	}
-	i -= sizeof(ap->rrep6_draft_01);
+	i -= sizeof(*ap);
 	printf(" rrep %u %s%sprefix %u hops %u\n"
 	   "\tdst %s dseq %lu src %s %lu ms", length,
-	    ap->rrep6_draft_01.rrep_type & RREP_REPAIR ? "[R]" : "",
-	    ap->rrep6_draft_01.rrep_type & RREP_ACK ? "[A] " : " ",
-	    ap->rrep6_draft_01.rrep_ps & RREP_PREFIX_MASK,
-	    ap->rrep6_draft_01.rrep_hops,
-	    ip6addr_string(&ap->rrep6_draft_01.rrep_da),
-	    (unsigned long)EXTRACT_32BITS(&ap->rrep6_draft_01.rrep_ds),
-	    ip6addr_string(&ap->rrep6_draft_01.rrep_oa),
-	    (unsigned long)EXTRACT_32BITS(&ap->rrep6_draft_01.rrep_life));
+               ap->rrep_type & RREP_REPAIR ? "[R]" : "",
+               ap->rrep_type & RREP_ACK ? "[A] " : " ",
+               ap->rrep_ps & RREP_PREFIX_MASK,
+               ap->rrep_hops,
+               ip6addr_string(&ap->rrep_da),
+               (unsigned long)EXTRACT_32BITS(&ap->rrep_ds),
+               ip6addr_string(&ap->rrep_oa),
+               (unsigned long)EXTRACT_32BITS(&ap->rrep_life));
+
 	if (i >= sizeof(struct aodv_ext))
-		aodv_extension((void *)(&ap->rrep6_draft_01 + 1), i);
+		aodv_extension((void *)(ap + 1), i);
 #else
 	printf(" rrep %u", length);
 #endif
@@ -362,28 +373,36 @@ aodv_v6_draft_01_rrep(const union aodv *ap _U_, const u_char *dat _U_,
 
 static void
 #ifdef INET6
-aodv_v6_draft_01_rerr(const union aodv *ap, u_int length)
+aodv_v6_draft_01_rerr(const struct aodv_rerr *ap, const u_char *dat, u_int length)
 #else
-aodv_v6_draft_01_rerr(const union aodv *ap _U_, u_int length)
+aodv_v6_draft_01_rerr(const struct aodv_rerr *ap _U_, const u_char *dat, u_int length)
 #endif
 {
 #ifdef INET6
-	const struct rerr_unreach6_draft_01 *dp6 = NULL;
-	int i, j, n, trunc;
+        u_int i, dc;
+	const struct rerr_unreach6_draft_01 *dp6;
+
+        if (snapend < dat) {
+		printf(" [|aodv]");
+		return;
+	}
+	i = min(length, (u_int)(snapend - dat));
+	if (i < sizeof(*ap)) {
+		printf(" [|rerr]");
+		return;
+	}
+	i -= sizeof(*ap);
 
-	i = length - offsetof(struct aodv_rerr, r);
-	j = sizeof(ap->rerr.r.dest6_draft_01[0]);
-	dp6 = &ap->rerr.r.dest6_draft_01[0];
-	n = ap->rerr.rerr_dc * j;
 	printf(" rerr %s [items %u] [%u]:",
-	    ap->rerr.rerr_flags & RERR_NODELETE ? "[D]" : "",
-	    ap->rerr.rerr_dc, length);
-	trunc = n - (i/j);
-	for (; i -= j >= 0; ++dp6) {
+	    ap->rerr_flags & RERR_NODELETE ? "[D]" : "",
+	    ap->rerr_dc, length);
+        dp6 = (struct rerr_unreach6_draft_01 *)(void *)(ap + 1);
+	for (dc = ap->rerr_dc; dc != 0 && i >= sizeof(*dp6);
+	    ++dp6, --dc, i -= sizeof(*dp6)) {
 		printf(" {%s}(%ld)", ip6addr_string(&dp6->u_da),
 		    (unsigned long)EXTRACT_32BITS(&dp6->u_ds));
 	}
-	if (trunc)
+        if ((i % sizeof(*dp6)) != 0)
 		printf("[|rerr]");
 #else
 	printf(" rerr %u", length);
@@ -393,40 +412,38 @@ aodv_v6_draft_01_rerr(const union aodv *ap _U_, u_int length)
 void
 aodv_print(const u_char *dat, u_int length, int is_ip6)
 {
-	const union aodv *ap;
+        uint8_t msg_type;
+
+	/*
+	 * The message type is the first byte; make sure we have it
+	 * and then fetch it.
+	 */
+	TCHECK(*dat);
+	msg_type = *dat;
 
-	ap = (union aodv *)dat;
-	if (snapend < dat) {
-		printf(" [|aodv]");
-		return;
-	}
-	if (min(length, (u_int)(snapend - dat)) < sizeof(ap->rrep_ack)) {
-		printf(" [|aodv]");
-		return;
-	}
 	printf(" aodv");
 
-	switch (ap->rerr.rerr_type) {
+	switch (msg_type) {
 
 	case AODV_RREQ:
 		if (is_ip6)
-			aodv_v6_rreq(ap, dat, length);
+			aodv_v6_rreq((const struct aodv_rreq6 *) dat, dat, length);
 		else
-			aodv_rreq(ap, dat, length);
+			aodv_rreq((const struct aodv_rreq *) dat, dat, length);
 		break;
 
 	case AODV_RREP:
 		if (is_ip6)
-			aodv_v6_rrep(ap, dat, length);
+			aodv_v6_rrep((const struct aodv_rrep6 *) dat, dat, length);
 		else
-			aodv_rrep(ap, dat, length);
+			aodv_rrep((const struct aodv_rrep *) dat, dat, length);
 		break;
 
 	case AODV_RERR:
 		if (is_ip6)
-			aodv_v6_rerr(ap, length);
+			aodv_v6_rerr((const struct aodv_rerr *) dat, dat, length);
 		else
-			aodv_rerr(ap, dat, length);
+			aodv_rerr((const struct aodv_rerr *) dat, dat, length);
 		break;
 
 	case AODV_RREP_ACK:
@@ -434,15 +451,15 @@ aodv_print(const u_char *dat, u_int length, int is_ip6)
 		break;
 
 	case AODV_V6_DRAFT_01_RREQ:
-		aodv_v6_draft_01_rreq(ap, dat, length);
+		aodv_v6_draft_01_rreq((const struct aodv_rreq6_draft_01 *) dat, dat, length);
 		break;
 
 	case AODV_V6_DRAFT_01_RREP:
-		aodv_v6_draft_01_rrep(ap, dat, length);
+		aodv_v6_draft_01_rrep((const struct aodv_rrep6_draft_01 *) dat, dat, length);
 		break;
 
 	case AODV_V6_DRAFT_01_RERR:
-		aodv_v6_draft_01_rerr(ap, length);
+		aodv_v6_draft_01_rerr((const struct aodv_rerr *) dat, dat, length);
 		break;
 
 	case AODV_V6_DRAFT_01_RREP_ACK:
@@ -450,6 +467,10 @@ aodv_print(const u_char *dat, u_int length, int is_ip6)
 		break;
 
 	default:
-		printf(" %u %u", ap->rreq.rreq_type, length);
+		printf(" %u %u", msg_type, length);
 	}
+        return;
+
+trunc:
+        printf(" [|aodv]");
 }
-- 
1.8.3.1