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>
This commit is contained in:
Родитель
3f823c15d5
Коммит
d52eb0d46f
|
@ -1199,42 +1199,40 @@ static int checksum_setup_ip(struct xenvif *vif, struct sk_buff *skb,
|
||||||
|
|
||||||
switch (ip_hdr(skb)->protocol) {
|
switch (ip_hdr(skb)->protocol) {
|
||||||
case IPPROTO_TCP:
|
case IPPROTO_TCP:
|
||||||
|
err = maybe_pull_tail(skb,
|
||||||
|
off + sizeof(struct tcphdr),
|
||||||
|
MAX_IP_HDR_LEN);
|
||||||
|
if (err < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (!skb_partial_csum_set(skb, off,
|
if (!skb_partial_csum_set(skb, off,
|
||||||
offsetof(struct tcphdr, check)))
|
offsetof(struct tcphdr, check)))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (recalculate_partial_csum) {
|
if (recalculate_partial_csum)
|
||||||
err = maybe_pull_tail(skb,
|
|
||||||
off + sizeof(struct tcphdr),
|
|
||||||
MAX_IP_HDR_LEN);
|
|
||||||
if (err < 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
tcp_hdr(skb)->check =
|
tcp_hdr(skb)->check =
|
||||||
~csum_tcpudp_magic(ip_hdr(skb)->saddr,
|
~csum_tcpudp_magic(ip_hdr(skb)->saddr,
|
||||||
ip_hdr(skb)->daddr,
|
ip_hdr(skb)->daddr,
|
||||||
skb->len - off,
|
skb->len - off,
|
||||||
IPPROTO_TCP, 0);
|
IPPROTO_TCP, 0);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case IPPROTO_UDP:
|
case IPPROTO_UDP:
|
||||||
|
err = maybe_pull_tail(skb,
|
||||||
|
off + sizeof(struct udphdr),
|
||||||
|
MAX_IP_HDR_LEN);
|
||||||
|
if (err < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (!skb_partial_csum_set(skb, off,
|
if (!skb_partial_csum_set(skb, off,
|
||||||
offsetof(struct udphdr, check)))
|
offsetof(struct udphdr, check)))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (recalculate_partial_csum) {
|
if (recalculate_partial_csum)
|
||||||
err = maybe_pull_tail(skb,
|
|
||||||
off + sizeof(struct udphdr),
|
|
||||||
MAX_IP_HDR_LEN);
|
|
||||||
if (err < 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
udp_hdr(skb)->check =
|
udp_hdr(skb)->check =
|
||||||
~csum_tcpudp_magic(ip_hdr(skb)->saddr,
|
~csum_tcpudp_magic(ip_hdr(skb)->saddr,
|
||||||
ip_hdr(skb)->daddr,
|
ip_hdr(skb)->daddr,
|
||||||
skb->len - off,
|
skb->len - off,
|
||||||
IPPROTO_UDP, 0);
|
IPPROTO_UDP, 0);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -1342,42 +1340,40 @@ static int checksum_setup_ipv6(struct xenvif *vif, struct sk_buff *skb,
|
||||||
|
|
||||||
switch (nexthdr) {
|
switch (nexthdr) {
|
||||||
case IPPROTO_TCP:
|
case IPPROTO_TCP:
|
||||||
|
err = maybe_pull_tail(skb,
|
||||||
|
off + sizeof(struct tcphdr),
|
||||||
|
MAX_IPV6_HDR_LEN);
|
||||||
|
if (err < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (!skb_partial_csum_set(skb, off,
|
if (!skb_partial_csum_set(skb, off,
|
||||||
offsetof(struct tcphdr, check)))
|
offsetof(struct tcphdr, check)))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (recalculate_partial_csum) {
|
if (recalculate_partial_csum)
|
||||||
err = maybe_pull_tail(skb,
|
|
||||||
off + sizeof(struct tcphdr),
|
|
||||||
MAX_IPV6_HDR_LEN);
|
|
||||||
if (err < 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
tcp_hdr(skb)->check =
|
tcp_hdr(skb)->check =
|
||||||
~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
|
~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
|
||||||
&ipv6_hdr(skb)->daddr,
|
&ipv6_hdr(skb)->daddr,
|
||||||
skb->len - off,
|
skb->len - off,
|
||||||
IPPROTO_TCP, 0);
|
IPPROTO_TCP, 0);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case IPPROTO_UDP:
|
case IPPROTO_UDP:
|
||||||
|
err = maybe_pull_tail(skb,
|
||||||
|
off + sizeof(struct udphdr),
|
||||||
|
MAX_IPV6_HDR_LEN);
|
||||||
|
if (err < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (!skb_partial_csum_set(skb, off,
|
if (!skb_partial_csum_set(skb, off,
|
||||||
offsetof(struct udphdr, check)))
|
offsetof(struct udphdr, check)))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (recalculate_partial_csum) {
|
if (recalculate_partial_csum)
|
||||||
err = maybe_pull_tail(skb,
|
|
||||||
off + sizeof(struct udphdr),
|
|
||||||
MAX_IPV6_HDR_LEN);
|
|
||||||
if (err < 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
udp_hdr(skb)->check =
|
udp_hdr(skb)->check =
|
||||||
~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
|
~csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
|
||||||
&ipv6_hdr(skb)->daddr,
|
&ipv6_hdr(skb)->daddr,
|
||||||
skb->len - off,
|
skb->len - off,
|
||||||
IPPROTO_UDP, 0);
|
IPPROTO_UDP, 0);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
goto out;
|
goto out;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче