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: