From: Guo-Fu Tseng <coolda...@cooldavid.org>

Add a field in struct io_buffer to pass checksum status from hardware.
If the hardware dose not support just ignore this field, it'll work as
usual.

I see that net/ipv6 does not check for checksum, so I temporary ignored
it.

Signed-off-by: Guo-Fu Tseng <coolda...@cooldavid.org>
---
 src/core/iobuf.c         |    1 +
 src/include/gpxe/iobuf.h |   13 +++++++++++++
 src/net/ipv4.c           |    8 +++++---
 src/net/tcp.c            |   18 ++++++++++--------
 src/net/udp.c            |    2 +-
 5 files changed, 30 insertions(+), 12 deletions(-)

diff --git a/src/core/iobuf.c b/src/core/iobuf.c
index 1ce7890..731a3c7 100644
--- a/src/core/iobuf.c
+++ b/src/core/iobuf.c
@@ -58,6 +58,7 @@ struct io_buffer * alloc_iob ( size_t len ) {
        iobuf = ( struct io_buffer * ) ( data + len );
        iobuf->head = iobuf->data = iobuf->tail = data;
        iobuf->end = iobuf;
+       iobuf->csum_stat = 0;
        return iobuf;
 }
 
diff --git a/src/include/gpxe/iobuf.h b/src/include/gpxe/iobuf.h
index 8f05f9e..423500b 100644
--- a/src/include/gpxe/iobuf.h
+++ b/src/include/gpxe/iobuf.h
@@ -34,6 +34,16 @@ FILE_LICENCE ( GPL2_OR_LATER );
 #define IOB_ZLEN 64
 
 /**
+ * Checksum Offloading Status
+ *
+ * Checksum status definitions. Currently only used for RX path.
+ */
+#define CHECKSUM_NONE 0
+#define CHECKSUM_UNNECESSARY 1
+#define CHECKSUM_COMPLETE 2
+#define CHECKSUM_PARTIAL 3
+
+/**
  * A persistent I/O buffer
  *
  * This data structure encapsulates a long-lived I/O buffer.  The
@@ -57,6 +67,9 @@ struct io_buffer {
        void *tail;
        /** End of the buffer */
         void *end;
+
+       /** Checksum Offloading Status **/
+       uint32_t csum_stat;
 };
 
 /**
diff --git a/src/net/ipv4.c b/src/net/ipv4.c
index 92d0684..f065ca6 100644
--- a/src/net/ipv4.c
+++ b/src/net/ipv4.c
@@ -390,7 +390,7 @@ static int ipv4_rx ( struct io_buffer *iobuf, struct 
net_device *netdev __unused
                struct sockaddr_tcpip st;
        } src, dest;
        uint16_t csum;
-       uint16_t pshdr_csum;
+       uint16_t pshdr_csum = 0;
        int rc;
 
        /* Sanity check the IPv4 header */
@@ -414,7 +414,8 @@ static int ipv4_rx ( struct io_buffer *iobuf, struct 
net_device *netdev __unused
                      "(packet is %zd bytes)\n", hdrlen, iob_len ( iobuf ) );
                goto err;
        }
-       if ( ( csum = tcpip_chksum ( iphdr, hdrlen ) ) != 0 ) {
+       if ( ( iobuf->csum_stat != CHECKSUM_COMPLETE ) &&
+            ( csum = tcpip_chksum ( iphdr, hdrlen ) ) != 0 ) {
                DBG ( "IPv4 checksum incorrect (is %04x including checksum "
                      "field, should be 0000)\n", csum );
                goto err;
@@ -441,7 +442,8 @@ static int ipv4_rx ( struct io_buffer *iobuf, struct 
net_device *netdev __unused
         * checksum and then strip off the IPv4 header.
         */
        iob_unput ( iobuf, ( iob_len ( iobuf ) - len ) );
-       pshdr_csum = ipv4_pshdr_chksum ( iobuf, TCPIP_EMPTY_CSUM );
+       if ( iobuf->csum_stat != CHECKSUM_COMPLETE )
+               pshdr_csum = ipv4_pshdr_chksum ( iobuf, TCPIP_EMPTY_CSUM );
        iob_pull ( iobuf, hdrlen );
 
        /* Fragment reassembly */
diff --git a/src/net/tcp.c b/src/net/tcp.c
index f9fd409..6a7b340 100644
--- a/src/net/tcp.c
+++ b/src/net/tcp.c
@@ -924,15 +924,17 @@ static int tcp_rx ( struct io_buffer *iobuf,
                rc = -EINVAL;
                goto discard;
        }
-       csum = tcpip_continue_chksum ( pshdr_csum, iobuf->data,
-                                      iob_len ( iobuf ) );
-       if ( csum != 0 ) {
-               DBG ( "TCP checksum incorrect (is %04x including checksum "
-                     "field, should be 0000)\n", csum );
-               rc = -EINVAL;
-               goto discard;
+       if ( iobuf->csum_stat != CHECKSUM_COMPLETE ) {
+               csum = tcpip_continue_chksum ( pshdr_csum, iobuf->data,
+                                              iob_len ( iobuf ) );
+               if ( csum != 0 ) {
+                       DBG ( "TCP checksum incorrect (is %04x including 
checksum "
+                             "field, should be 0000)\n", csum );
+                       rc = -EINVAL;
+                       goto discard;
+               }
        }
-       
+
        /* Parse parameters from header and strip header */
        tcp = tcp_demux ( tcphdr->dest );
        start_seq = seq = ntohl ( tcphdr->seq );
diff --git a/src/net/udp.c b/src/net/udp.c
index 1441d53..26c4c28 100644
--- a/src/net/udp.c
+++ b/src/net/udp.c
@@ -298,7 +298,7 @@ static int udp_rx ( struct io_buffer *iobuf, struct 
sockaddr_tcpip *st_src,
                rc = -EINVAL;
                goto done;
        }
-       if ( udphdr->chksum ) {
+       if ( udphdr->chksum && ( iobuf->csum_stat != CHECKSUM_COMPLETE ) ) {
                csum = tcpip_continue_chksum ( pshdr_csum, iobuf->data, ulen );
                if ( csum != 0 ) {
                        DBG ( "UDP checksum incorrect (is %04x including "
-- 
1.7.1

_______________________________________________
gPXE-devel mailing list
gPXE-devel@etherboot.org
http://etherboot.org/mailman/listinfo/gpxe-devel

Reply via email to