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_) */

Reply via email to