aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/skbuff.h9
-rw-r--r--net/core/dev.c25
-rw-r--r--net/core/skbuff.c2
-rw-r--r--net/ipv4/tcp_ipv4.c2
-rw-r--r--net/ipv4/udp.c1
-rw-r--r--net/ipv6/tcp_ipv6.c2
6 files changed, 28 insertions, 13 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 9b2957d203c9..910560e85561 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -205,7 +205,9 @@ typedef unsigned char *sk_buff_data_t;
205 * @len: Length of actual data 205 * @len: Length of actual data
206 * @data_len: Data length 206 * @data_len: Data length
207 * @mac_len: Length of link layer header 207 * @mac_len: Length of link layer header
208 * @csum: Checksum 208 * @csum: Checksum (must include start/offset pair)
209 * @csum_start: Offset from skb->head where checksumming should start
210 * @csum_offset: Offset from csum_start where checksum should be stored
209 * @local_df: allow local fragmentation 211 * @local_df: allow local fragmentation
210 * @cloned: Head may be cloned (check refcnt to be sure) 212 * @cloned: Head may be cloned (check refcnt to be sure)
211 * @nohdr: Payload reference only, must not modify header 213 * @nohdr: Payload reference only, must not modify header
@@ -261,7 +263,10 @@ struct sk_buff {
261 mac_len; 263 mac_len;
262 union { 264 union {
263 __wsum csum; 265 __wsum csum;
264 __u32 csum_offset; 266 struct {
267 __u16 csum_start;
268 __u16 csum_offset;
269 };
265 }; 270 };
266 __u32 priority; 271 __u32 priority;
267 __u8 local_df:1, 272 __u8 local_df:1,
diff --git a/net/core/dev.c b/net/core/dev.c
index fec8cf27f75d..d23972f56fc7 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1155,7 +1155,7 @@ EXPORT_SYMBOL(netif_device_attach);
1155int skb_checksum_help(struct sk_buff *skb) 1155int skb_checksum_help(struct sk_buff *skb)
1156{ 1156{
1157 __wsum csum; 1157 __wsum csum;
1158 int ret = 0, offset = skb_transport_offset(skb); 1158 int ret = 0, offset;
1159 1159
1160 if (skb->ip_summed == CHECKSUM_COMPLETE) 1160 if (skb->ip_summed == CHECKSUM_COMPLETE)
1161 goto out_set_summed; 1161 goto out_set_summed;
@@ -1171,15 +1171,16 @@ int skb_checksum_help(struct sk_buff *skb)
1171 goto out; 1171 goto out;
1172 } 1172 }
1173 1173
1174 offset = skb->csum_start - skb_headroom(skb);
1174 BUG_ON(offset > (int)skb->len); 1175 BUG_ON(offset > (int)skb->len);
1175 csum = skb_checksum(skb, offset, skb->len-offset, 0); 1176 csum = skb_checksum(skb, offset, skb->len-offset, 0);
1176 1177
1177 offset = skb->tail - skb->transport_header; 1178 offset = skb_headlen(skb) - offset;
1178 BUG_ON(offset <= 0); 1179 BUG_ON(offset <= 0);
1179 BUG_ON(skb->csum_offset + 2 > offset); 1180 BUG_ON(skb->csum_offset + 2 > offset);
1180 1181
1181 *(__sum16 *)(skb_transport_header(skb) + 1182 *(__sum16 *)(skb->head + skb->csum_start + skb->csum_offset) =
1182 skb->csum_offset) = csum_fold(csum); 1183 csum_fold(csum);
1183out_set_summed: 1184out_set_summed:
1184 skb->ip_summed = CHECKSUM_NONE; 1185 skb->ip_summed = CHECKSUM_NONE;
1185out: 1186out:
@@ -1431,12 +1432,16 @@ int dev_queue_xmit(struct sk_buff *skb)
1431 /* If packet is not checksummed and device does not support 1432 /* If packet is not checksummed and device does not support
1432 * checksumming for this protocol, complete checksumming here. 1433 * checksumming for this protocol, complete checksumming here.
1433 */ 1434 */
1434 if (skb->ip_summed == CHECKSUM_PARTIAL && 1435 if (skb->ip_summed == CHECKSUM_PARTIAL) {
1435 (!(dev->features & NETIF_F_GEN_CSUM) && 1436 skb_set_transport_header(skb, skb->csum_start -
1436 (!(dev->features & NETIF_F_IP_CSUM) || 1437 skb_headroom(skb));
1437 skb->protocol != htons(ETH_P_IP)))) 1438
1438 if (skb_checksum_help(skb)) 1439 if (!(dev->features & NETIF_F_GEN_CSUM) &&
1439 goto out_kfree_skb; 1440 (!(dev->features & NETIF_F_IP_CSUM) ||
1441 skb->protocol != htons(ETH_P_IP)))
1442 if (skb_checksum_help(skb))
1443 goto out_kfree_skb;
1444 }
1440 1445
1441gso: 1446gso:
1442 spin_lock_prefetch(&dev->queue_lock); 1447 spin_lock_prefetch(&dev->queue_lock);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 4965df29768b..52a4fdd4f31c 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -1358,7 +1358,7 @@ void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to)
1358 long csstart; 1358 long csstart;
1359 1359
1360 if (skb->ip_summed == CHECKSUM_PARTIAL) 1360 if (skb->ip_summed == CHECKSUM_PARTIAL)
1361 csstart = skb_transport_offset(skb); 1361 csstart = skb->csum_start - skb_headroom(skb);
1362 else 1362 else
1363 csstart = skb_headlen(skb); 1363 csstart = skb_headlen(skb);
1364 1364
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 {
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 4a55da079f5f..7e824b97126d 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -950,6 +950,7 @@ static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb)
950 950
951 if (skb->ip_summed == CHECKSUM_PARTIAL) { 951 if (skb->ip_summed == CHECKSUM_PARTIAL) {
952 th->check = ~csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 0); 952 th->check = ~csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 0);
953 skb->csum_start = skb_transport_header(skb) - skb->head;
953 skb->csum_offset = offsetof(struct tcphdr, check); 954 skb->csum_offset = offsetof(struct tcphdr, check);
954 } else { 955 } else {
955 th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, 956 th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP,
@@ -972,6 +973,7 @@ static int tcp_v6_gso_send_check(struct sk_buff *skb)
972 th->check = 0; 973 th->check = 0;
973 th->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len, 974 th->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, skb->len,
974 IPPROTO_TCP, 0); 975 IPPROTO_TCP, 0);
976 skb->csum_start = skb_transport_header(skb) - skb->head;
975 skb->csum_offset = offsetof(struct tcphdr, check); 977 skb->csum_offset = offsetof(struct tcphdr, check);
976 skb->ip_summed = CHECKSUM_PARTIAL; 978 skb->ip_summed = CHECKSUM_PARTIAL;
977 return 0; 979 return 0;