in6_delayed_cksum() incorrectly assumes that the ICMPv6 header or checksum field is in the first mbuf of an mbuf chain before setting it to 0. This diff fixes it.
OK? Index: ip6_output.c =================================================================== RCS file: /cvs/src/sys/netinet6/ip6_output.c,v retrieving revision 1.143 diff -U5 -p -r1.143 ip6_output.c --- ip6_output.c 31 Jul 2013 15:41:52 -0000 1.143 +++ ip6_output.c 5 Aug 2013 02:44:43 -0000 @@ -3174,22 +3174,21 @@ ip6_randomid_init(void) */ void in6_delayed_cksum(struct mbuf *m, u_int8_t nxt) { int nxtp, offset; - u_int16_t csum; + u_int16_t csum = 0; offset = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxtp); if (offset <= 0 || nxtp != nxt) /* If the desired next protocol isn't found, punt. */ return; - if (nxt == IPPROTO_ICMPV6) { - struct icmp6_hdr *icmp6; - icmp6 = (struct icmp6_hdr *)(mtod(m, caddr_t) + offset); - icmp6->icmp6_cksum = 0; - } + if (nxt == IPPROTO_ICMPV6) + if (m_copyback(m, offset + offsetof(struct icmp6_hdr, icmp6_cksum), + sizeof(csum), &csum, M_NOWAIT)) + return; csum = (u_int16_t)(in6_cksum(m, nxt, offset, m->m_pkthdr.len - offset)); switch (nxt) { case IPPROTO_TCP: