aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2007-04-09 14:59:07 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-04-26 01:28:40 -0400
commit663ead3bb8d5b561e70fc3bb3861c9220b5a77eb (patch)
tree551d031fc9c904487ced4d8d3363e5ed8f369794 /net/ipv4
parentac758e3c55c529714354fc268892ca4d23ca1e99 (diff)
[NET]: Use csum_start offset instead of skb_transport_header
The skb transport pointer is currently used to specify the start of the checksum region for transmit checksum offload. Unfortunately, the same pointer is also used during receive side processing. This creates a problem when we want to retransmit a received packet with partial checksums since the skb transport pointer would be overwritten. This patch solves this problem by creating a new 16-bit csum_start offset value to replace the skb transport header for the purpose of checksums. This offset is calculated from skb->head so that it does not have to change when skb->data changes. No extra space is required since csum_offset itself fits within a 16-bit word so we can use the other 16 bits for csum_start. For backwards compatibility, just before we push a packet with partial checksums off into the device driver, we set the skb transport header to what it would have been under the old scheme. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/tcp_ipv4.c2
-rw-r--r--net/ipv4/udp.c1
2 files changed, 3 insertions, 0 deletions
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index e11eaf4cc269..a091a99ad263 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -504,6 +504,7 @@ void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb)
504 if (skb->ip_summed == CHECKSUM_PARTIAL) { 504 if (skb->ip_summed == CHECKSUM_PARTIAL) {
505 th->check = ~tcp_v4_check(len, inet->saddr, 505 th->check = ~tcp_v4_check(len, inet->saddr,
506 inet->daddr, 0); 506 inet->daddr, 0);
507 skb->csum_start = skb_transport_header(skb) - skb->head;
507 skb->csum_offset = offsetof(struct tcphdr, check); 508 skb->csum_offset = offsetof(struct tcphdr, check);
508 } else { 509 } else {
509 th->check = tcp_v4_check(len, inet->saddr, inet->daddr, 510 th->check = tcp_v4_check(len, inet->saddr, inet->daddr,
@@ -526,6 +527,7 @@ int tcp_v4_gso_send_check(struct sk_buff *skb)
526 527
527 th->check = 0; 528 th->check = 0;
528 th->check = ~tcp_v4_check(skb->len, iph->saddr, iph->daddr, 0); 529 th->check = ~tcp_v4_check(skb->len, iph->saddr, iph->daddr, 0);
530 skb->csum_start = skb_transport_header(skb) - skb->head;
529 skb->csum_offset = offsetof(struct tcphdr, check); 531 skb->csum_offset = offsetof(struct tcphdr, check);
530 skb->ip_summed = CHECKSUM_PARTIAL; 532 skb->ip_summed = CHECKSUM_PARTIAL;
531 return 0; 533 return 0;
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 71b0b60ba538..5ad7a26e3091 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -427,6 +427,7 @@ static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb,
427 /* 427 /*
428 * Only one fragment on the socket. 428 * Only one fragment on the socket.
429 */ 429 */
430 skb->csum_start = skb_transport_header(skb) - skb->head;
430 skb->csum_offset = offsetof(struct udphdr, check); 431 skb->csum_offset = offsetof(struct udphdr, check);
431 uh->check = ~csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, 0); 432 uh->check = ~csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, 0);
432 } else { 433 } else {