On Sun, Oct 02, 2011 at 04:44:46PM +0200, Stefan Sperling wrote:
[...]
> The problem is that the IPv6 input path uses IP6_EXTHDR_GET() to
> obtain a pointer to the carp header when verifying the carp header's
> checksum. IP6_EXTHDR_GET() internally uses m_pulldown(), which might
> return a pointer to a different mbuf in the chain. However, there is
> no way for the caller of IP6_EXTHDR_GET() to get at the different mbuf
> pointer returned by m_pulldown().
[...]
I think it's easier to just use m_pullup here.
m_pulldown() is usually more efficient, since it doesn't have
have to start from the beginning of the chain, but that doesn't
matter for the carp case.
Does this fix your problem as well?
Index: ip_carp.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_carp.c,v
retrieving revision 1.190
diff -p -u -p -u -r1.190 ip_carp.c
--- ip_carp.c 6 Sep 2011 16:00:22 -0000 1.190
+++ ip_carp.c 5 Oct 2011 07:57:33 -0000
@@ -650,13 +650,12 @@ carp6_proto_input(struct mbuf **mp, int
/* verify that we have a complete carp packet */
len = m->m_len;
- IP6_EXTHDR_GET(ch, struct carp_header *, m, *offp, sizeof(*ch));
- if (ch == NULL) {
+ if ((m = m_pullup(m, *offp + sizeof(*ch))) == NULL) {
carpstats.carps_badlen++;
CARP_LOG(LOG_INFO, sc, ("packet size %u too small", len));
return (IPPROTO_DONE);
}
-
+ ch = (struct carp_header *)(mtod(m, caddr_t) + *offp);
/* verify the CARP checksum */
m->m_data += *offp;