Module Name: src Committed By: matt Date: Sat Dec 11 22:37:47 UTC 2010
Modified Files: src/sys/netinet: in_offload.c in_offload.h ip_input.c src/sys/netinet6: in6_offload.c in6_offload.h Log Message: Add routines to calculate a checkesum if the driver concludes that the h/w can't do it. To generate a diff of this commit: cvs rdiff -u -r1.2 -r1.3 src/sys/netinet/in_offload.c cvs rdiff -u -r1.6 -r1.7 src/sys/netinet/in_offload.h cvs rdiff -u -r1.291 -r1.292 src/sys/netinet/ip_input.c cvs rdiff -u -r1.4 -r1.5 src/sys/netinet6/in6_offload.c cvs rdiff -u -r1.5 -r1.6 src/sys/netinet6/in6_offload.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/netinet/in_offload.c diff -u src/sys/netinet/in_offload.c:1.2 src/sys/netinet/in_offload.c:1.3 --- src/sys/netinet/in_offload.c:1.2 Tue Apr 24 23:43:50 2007 +++ src/sys/netinet/in_offload.c Sat Dec 11 22:37:46 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: in_offload.c,v 1.2 2007/04/24 23:43:50 dyoung Exp $ */ +/* $NetBSD: in_offload.c,v 1.3 2010/12/11 22:37:46 matt Exp $ */ /*- * Copyright (c)2005, 2006 YAMAMOTO Takashi, @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: in_offload.c,v 1.2 2007/04/24 23:43:50 dyoung Exp $"); +__KERNEL_RCSID(0, "$NetBSD: in_offload.c,v 1.3 2010/12/11 22:37:46 matt Exp $"); #include <sys/param.h> #include <sys/mbuf.h> @@ -195,3 +195,57 @@ return error; } + +void +ip_undefer_csum(struct mbuf *m, size_t hdrlen, int csum_flags) +{ + KASSERT(m->m_flags & M_PKTHDR); + KASSERT((m->m_pkthdr.csum_flags & csum_flags) == csum_flags); + uint16_t csum; + uint16_t ip_len; + uint16_t *csump; + size_t iphdrlen; + + if (__predict_true(hdrlen + sizeof(struct ip) <= m->m_len)) { + struct ip *ip = (struct ip *)(mtod(m, uint8_t *) + hdrlen); + ip_len = ip->ip_len; + iphdrlen = ip->ip_hl << 2; + csump = &ip->ip_sum; + } else { + uint8_t ip_vhl; + const size_t ip_len_offset = hdrlen + offsetof(struct ip, ip_len); + m_copydata(m, hdrlen, sizeof(ip_vhl), &ip_vhl); + m_copydata(m, ip_len_offset, sizeof(ip_len), &ip_len); + iphdrlen = (ip_vhl & 0x0f) << 2; + csump = NULL; + } + + if (csum_flags & M_CSUM_IPv4) { + const size_t offset = hdrlen + offsetof(struct ip, ip_sum); + csum = in4_cksum(m, 0, hdrlen, iphdrlen); + if (csump != NULL) { + *csump = csum; + } else { + m_copyback(m, offset, sizeof(uint16_t), &csum); + } + } + + if (csum_flags & (M_CSUM_UDPv4|M_CSUM_TCPv4)) { + size_t l4offset = hdrlen + + M_CSUM_DATA_IPv4_IPHL(m->m_pkthdr.csum_data); + + csum = in4_cksum(m, 0, hdrlen + l4offset, ip_len - l4offset); + if (csum == 0 && (csum_flags & M_CSUM_UDPv4) != 0) + csum = 0xffff; + + l4offset += M_CSUM_DATA_IPv4_OFFSET(m->m_pkthdr.csum_data); + + if (__predict_true(l4offset + sizeof(uint16_t) <= m->m_len)) { + *(uint16_t *)(mtod(m, char *) + l4offset) = csum; + } else { + m_copyback(m, l4offset, sizeof(csum), (void *) &csum); + } + } + + m->m_pkthdr.csum_flags ^= csum_flags; +} Index: src/sys/netinet/in_offload.h diff -u src/sys/netinet/in_offload.h:1.6 src/sys/netinet/in_offload.h:1.7 --- src/sys/netinet/in_offload.h:1.6 Wed Nov 28 04:14:11 2007 +++ src/sys/netinet/in_offload.h Sat Dec 11 22:37:46 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: in_offload.h,v 1.6 2007/11/28 04:14:11 dyoung Exp $ */ +/* $NetBSD: in_offload.h,v 1.7 2010/12/11 22:37:46 matt Exp $ */ /*- * Copyright (c)2005, 2006 YAMAMOTO Takashi, @@ -36,6 +36,7 @@ int tcp4_segment(struct mbuf *, int (*)(void *, struct mbuf *), void *); int ip_tso_output(struct ifnet *, struct mbuf *, const struct sockaddr *, struct rtentry *); +void ip_undefer_csum(struct mbuf *, size_t, int); /* * offloading related sysctl variables. Index: src/sys/netinet/ip_input.c diff -u src/sys/netinet/ip_input.c:1.291 src/sys/netinet/ip_input.c:1.292 --- src/sys/netinet/ip_input.c:1.291 Fri Nov 5 01:35:57 2010 +++ src/sys/netinet/ip_input.c Sat Dec 11 22:37:46 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: ip_input.c,v 1.291 2010/11/05 01:35:57 rmind Exp $ */ +/* $NetBSD: ip_input.c,v 1.292 2010/12/11 22:37:46 matt Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -91,7 +91,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.291 2010/11/05 01:35:57 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.292 2010/12/11 22:37:46 matt Exp $"); #include "opt_inet.h" #include "opt_compat_netbsd.h" @@ -390,7 +390,9 @@ IF_DEQUEUE(&lcl_intrq, m); if (m == NULL) break; + KERNEL_UNLOCK_ONE(NULL); ip_input(m); + KERNEL_LOCK(1, NULL); } mutex_exit(softnet_lock); } Index: src/sys/netinet6/in6_offload.c diff -u src/sys/netinet6/in6_offload.c:1.4 src/sys/netinet6/in6_offload.c:1.5 --- src/sys/netinet6/in6_offload.c:1.4 Wed May 2 20:40:26 2007 +++ src/sys/netinet6/in6_offload.c Sat Dec 11 22:37:47 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: in6_offload.c,v 1.4 2007/05/02 20:40:26 dyoung Exp $ */ +/* $NetBSD: in6_offload.c,v 1.5 2010/12/11 22:37:47 matt Exp $ */ /*- * Copyright (c)2006 YAMAMOTO Takashi, @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: in6_offload.c,v 1.4 2007/05/02 20:40:26 dyoung Exp $"); +__KERNEL_RCSID(0, "$NetBSD: in6_offload.c,v 1.5 2010/12/11 22:37:47 matt Exp $"); #include <sys/param.h> #include <sys/mbuf.h> @@ -191,3 +191,37 @@ return error; } + +void +ip6_undefer_csum(struct mbuf *m, size_t hdrlen, int csum_flags) +{ + KASSERT(m->m_flags & M_PKTHDR); + KASSERT((m->m_pkthdr.csum_flags & csum_flags) == csum_flags); + KASSERT(csum_flags == M_CSUM_UDPv6 || csum_flags == M_CSUM_TCPv6); + + const size_t ip6_plen_offset = hdrlen + offsetof(struct ip6_hdr, ip6_plen); + uint16_t plen; + + if (__predict_true(hdrlen + sizeof(struct ip6_hdr) <= m->m_len)) { + plen = *(uint16_t *)(mtod(m, char *) + ip6_plen_offset); + } else { + m_copydata(m, ip6_plen_offset, sizeof(plen), &plen); + } + + const size_t l4hdroff = M_CSUM_DATA_IPv6_HL(m->m_pkthdr.csum_data); + size_t l4offset = hdrlen + l4hdroff; + uint16_t csum = in6_cksum(m, 0, l4offset, plen - l4hdroff); + + if (csum == 0 && (csum_flags & M_CSUM_UDPv6) != 0) + csum = 0xffff; + + l4offset += M_CSUM_DATA_IPv6_OFFSET(m->m_pkthdr.csum_data); + + if (__predict_true((l4offset + sizeof(uint16_t)) <= m->m_len)) { + *(uint16_t *)(mtod(m, char *) + l4offset) = csum; + } else { + m_copyback(m, l4offset, sizeof(csum), (void *) &csum); + } + + m->m_pkthdr.csum_flags ^= csum_flags; +} Index: src/sys/netinet6/in6_offload.h diff -u src/sys/netinet6/in6_offload.h:1.5 src/sys/netinet6/in6_offload.h:1.6 --- src/sys/netinet6/in6_offload.h:1.5 Wed May 2 20:40:26 2007 +++ src/sys/netinet6/in6_offload.h Sat Dec 11 22:37:47 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: in6_offload.h,v 1.5 2007/05/02 20:40:26 dyoung Exp $ */ +/* $NetBSD: in6_offload.h,v 1.6 2010/12/11 22:37:47 matt Exp $ */ /*- * Copyright (c)2005, 2006 YAMAMOTO Takashi, @@ -36,5 +36,6 @@ int tcp6_segment(struct mbuf *, int (*)(void *, struct mbuf *), void *); int ip6_tso_output(struct ifnet *, struct ifnet *, struct mbuf *, const struct sockaddr_in6 *, struct rtentry *); +void ip6_undefer_csum(struct mbuf *, size_t, int); #endif /* !defined(_NETINET6_IN6_OFFLOAD_H_) */