diff options
-rw-r--r-- | include/linux/skbuff.h | 9 | ||||
-rw-r--r-- | net/core/dev.c | 25 | ||||
-rw-r--r-- | net/core/skbuff.c | 2 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 2 | ||||
-rw-r--r-- | net/ipv4/udp.c | 1 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 2 |
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); | |||
1155 | int skb_checksum_help(struct sk_buff *skb) | 1155 | int 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); |
1183 | out_set_summed: | 1184 | out_set_summed: |
1184 | skb->ip_summed = CHECKSUM_NONE; | 1185 | skb->ip_summed = CHECKSUM_NONE; |
1185 | out: | 1186 | out: |
@@ -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 | ||
1441 | gso: | 1446 | gso: |
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; |