summaryrefslogtreecommitdiff
path: root/sys/netinet6/ip6_output.c
diff options
context:
space:
mode:
authorChristian Weisgerber <naddy@cvs.openbsd.org>2014-01-22 14:27:21 +0000
committerChristian Weisgerber <naddy@cvs.openbsd.org>2014-01-22 14:27:21 +0000
commitd58a2a454a81c098056ad0bbe8955816c929c526 (patch)
treecd49cdaf2e24cca140c5eb02b83a8b3bf466a36d /sys/netinet6/ip6_output.c
parent67dba4aa0297de97a87c6c57f9001fd41683c6f6 (diff)
Split the checksum calculation for IPv6 like for IPv4:
Always calculate the pseudo-header checksum. Complete the checksum if hardware offload is not available. Parts originally from NetBSD; ok henning@
Diffstat (limited to 'sys/netinet6/ip6_output.c')
-rw-r--r--sys/netinet6/ip6_output.c27
1 files changed, 25 insertions, 2 deletions
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index f547e635db8..2efda0435f3 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ip6_output.c,v 1.150 2014/01/21 10:18:26 mpi Exp $ */
+/* $OpenBSD: ip6_output.c,v 1.151 2014/01/22 14:27:20 naddy Exp $ */
/* $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $ */
/*
@@ -3211,7 +3211,7 @@ in6_delayed_cksum(struct mbuf *m, u_int8_t nxt)
if (offset <= 0 || nxtp != nxt)
/* If the desired next protocol isn't found, punt. */
return;
- csum = (u_int16_t)(in6_cksum(m, nxt, offset, m->m_pkthdr.len - offset));
+ csum = (u_int16_t)(in6_cksum(m, 0, offset, m->m_pkthdr.len - offset));
switch (nxt) {
case IPPROTO_TCP:
@@ -3238,6 +3238,29 @@ in6_delayed_cksum(struct mbuf *m, u_int8_t nxt)
void
in6_proto_cksum_out(struct mbuf *m, struct ifnet *ifp)
{
+ /* some hw and in6_delayed_cksum need the pseudo header cksum */
+ if (m->m_pkthdr.csum_flags &
+ (M_TCP_CSUM_OUT|M_UDP_CSUM_OUT|M_ICMP_CSUM_OUT)) {
+ struct ip6_hdr *ip6;
+ int nxt, offset;
+ u_int16_t csum;
+
+ ip6 = mtod(m, struct ip6_hdr *);
+ offset = ip6_lasthdr(m, 0, IPPROTO_IPV6, &nxt);
+ csum = in6_cksum_phdr(&ip6->ip6_src, &ip6->ip6_dst,
+ htonl(m->m_pkthdr.len - offset), htonl(nxt));
+ if (nxt == IPPROTO_TCP)
+ offset += offsetof(struct tcphdr, th_sum);
+ else if (nxt == IPPROTO_UDP)
+ offset += offsetof(struct udphdr, uh_sum);
+ else if (nxt == IPPROTO_ICMPV6)
+ offset += offsetof(struct icmp6_hdr, icmp6_cksum);
+ if ((offset + sizeof(u_int16_t)) > m->m_len)
+ m_copyback(m, offset, sizeof(csum), &csum, M_NOWAIT);
+ else
+ *(u_int16_t *)(mtod(m, caddr_t) + offset) = csum;
+ }
+
if (m->m_pkthdr.csum_flags & M_TCP_CSUM_OUT) {
if (!ifp || !(ifp->if_capabilities & IFCAP_CSUM_TCPv6) ||
ifp->if_bridgeport != NULL) {