aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Durrant <Paul.Durrant@citrix.com>2013-12-11 11:37:40 -0500
committerDavid S. Miller <davem@davemloft.net>2013-12-11 16:46:24 -0500
commitd52eb0d46f3606b9de9965cebb2beb2202a0dc62 (patch)
tree7f8e6d1ee20d74baa55d354e1e218feac10b1d5e
parent3f823c15d53dc78b50d6f561caf36e8109df1193 (diff)
xen-netback: make sure skb linear area covers checksum field
skb_partial_csum_set requires that the linear area of the skb covers the checksum field. The checksum setup code in netback was only doing that pullup in the case when the pseudo header checksum was being recalculated though. This patch makes that pullup unconditional. (I pullup the whole transport header just for simplicity; the requirement is only for the check field but in the case of UDP this is the last field in the header and in the case of TCP it's the last but one). The lack of pullup manifested as failures running Microsoft HCK network tests on a pair of Windows 8 VMs and it has been verified that this patch fixes the problem. Suggested-by: Jan Beulich <jbeulich@suse.com> Signed-off-by: Paul Durrant <paul.durrant@citrix.com> Cc: Wei Liu <wei.liu2@citrix.com> Cc: Ian Campbell <ian.campbell@citrix.com> Cc: David Vrabel <david.vrabel@citrix.com> Reviewed-by: Jan Beulich <jbeulich@suse.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/xen-netback/netback.c60
1 files changed, 28 insertions, 32 deletions
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index acf13920e6d1..d158fc40cff2 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -1199,42 +1199,40 @@ static int checksum_setup_ip(struct xenvif *vif, struct sk_buff *skb,
1199 1199
1200 switch (ip_hdr(skb)->protocol) { 1200 switch (ip_hdr(skb)->protocol) {
1201 case IPPROTO_TCP: 1201 case IPPROTO_TCP:
1202 err = maybe_pull_tail(skb,
1203 off + sizeof(struct tcphdr),
1204 MAX_IP_HDR_LEN);
1205 if (err < 0)
1206 goto out;
1207
1202 if (!skb_partial_csum_set(skb, off, 1208 if (!skb_partial_csum_set(skb, off,
1203 offsetof(struct tcphdr, check))) 1209 offsetof(struct tcphdr, check)))
1204 goto out; 1210 goto out;
1205 1211
1206 if (recalculate_partial_csum) { 1212 if (recalculate_partial_csum)
1207 err = maybe_pull_tail(skb,
1208 off + sizeof(struct tcphdr),
1209 MAX_IP_HDR_LEN);
1210 if (err < 0)
1211 goto out;
1212
1213 tcp_hdr(skb)->check = 1213 tcp_hdr(skb)->check =
1214 ~csum_tcpudp_magic(ip_hdr(skb)->saddr, 1214 ~csum_tcpudp_magic(ip_hdr(skb)->saddr,
1215 ip_hdr(skb)->daddr, 1215 ip_hdr(skb)->daddr,
1216 skb->len - off, 1216 skb->len - off,
1217 IPPROTO_TCP, 0); 1217 IPPROTO_TCP, 0);
1218 }
1219 break; 1218 break;
1220 case IPPROTO_UDP: 1219 case IPPROTO_UDP:
1220 err = maybe_pull_tail(skb,
1221 off + sizeof(struct udphdr),
1222 MAX_IP_HDR_LEN);
1223 if (err < 0)
1224 goto out;
1225
1221 if (!skb_partial_csum_set(skb, off, 1226 if (!skb_partial_csum_set(skb, off,
1222 offsetof(struct udphdr, check))) 1227 offsetof(struct udphdr, check)))
1223 goto out; 1228 goto out;
1224 1229
1225 if (recalculate_partial_csum) { 1230 if (recalculate_partial_csum)
1226 err = maybe_pull_tail(skb,
1227 off + sizeof(struct udphdr),
1228 MAX_IP_HDR_LEN);
1229 if (err < 0)
1230 goto out;
1231
1232 udp_hdr(skb)->check = 1231 udp_hdr(skb)->check =
1233 ~csum_tcpudp_magic(ip_hdr(skb)->saddr, 1232 ~csum_tcpudp_magic(ip_hdr(skb)->saddr,
1234 ip_hdr(skb)->daddr, 1233 ip_hdr(skb)->daddr,
1235 skb->len - off, 1234 skb->len - off,
1236 IPPROTO_UDP, 0); 1235 IPPROTO_UDP, 0);
1237 }
1238 break; 1236 break;
1239 default: 1237 default:
1240 goto out; 1238 goto out;
@@ -1342,42 +1340,40 @@ static int checksum_setup_ipv6(struct xenvif *vif, struct sk_buff *skb,
1342 1340
1343 switch (nexthdr) { 1341 switch (nexthdr) {
1344 case IPPROTO_TCP: 1342 case IPPROTO_TCP:
1343 err = maybe_pull_tail(skb,
1344 off + sizeof(struct tcphdr),
1345 MAX_IPV6_HDR_LEN);
1346 if (err < 0)
1347 goto out;
1348
1345 if (!skb_partial_csum_set(skb, off, 1349 if (!skb_partial_csum_set(skb, off,
1346 offsetof(struct tcphdr, check))) 1350 offsetof(struct tcphdr, check)))
1347 goto out; 1351 goto out;
1348 1352
1349 if (recalculate_partial_csum) { 1353 if (recalculate_partial_csum)
1350 err = maybe_pull_tail(skb,
1351 off + sizeof(struct tcphdr),
1352 MAX_IPV6_HDR_LEN);
1353 if (err < 0)
1354 goto out;
1355
1356 tcp_hdr(skb)->check = 1354 tcp_hdr(skb)->check =
1357 ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, 1355 ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
1358 &ipv6_hdr(skb)->daddr, 1356 &ipv6_hdr(skb)->daddr,
1359 skb->len - off, 1357 skb->len - off,
1360 IPPROTO_TCP, 0); 1358 IPPROTO_TCP, 0);
1361 }
1362 break; 1359 break;
1363 case IPPROTO_UDP: 1360 case IPPROTO_UDP:
1361 err = maybe_pull_tail(skb,
1362 off + sizeof(struct udphdr),
1363 MAX_IPV6_HDR_LEN);
1364 if (err < 0)
1365 goto out;
1366
1364 if (!skb_partial_csum_set(skb, off, 1367 if (!skb_partial_csum_set(skb, off,
1365 offsetof(struct udphdr, check))) 1368 offsetof(struct udphdr, check)))
1366 goto out; 1369 goto out;
1367 1370
1368 if (recalculate_partial_csum) { 1371 if (recalculate_partial_csum)
1369 err = maybe_pull_tail(skb,
1370 off + sizeof(struct udphdr),
1371 MAX_IPV6_HDR_LEN);
1372 if (err < 0)
1373 goto out;
1374
1375 udp_hdr(skb)->check = 1372 udp_hdr(skb)->check =
1376 ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, 1373 ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
1377 &ipv6_hdr(skb)->daddr, 1374 &ipv6_hdr(skb)->daddr,
1378 skb->len - off, 1375 skb->len - off,
1379 IPPROTO_UDP, 0); 1376 IPPROTO_UDP, 0);
1380 }
1381 break; 1377 break;
1382 default: 1378 default:
1383 goto out; 1379 goto out;