mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-22 17:01:14 +00:00
net: gre: recompute gre csum for sctp over gre tunnels
[ Upstream commit622e32b7d4
] The GRE tunnel can be used to transport traffic that does not rely on a Internet checksum (e.g. SCTP). The issue can be triggered creating a GRE or GRETAP tunnel and transmitting SCTP traffic ontop of it where CRC offload has been disabled. In order to fix the issue we need to recompute the GRE csum in gre_gso_segment() not relying on the inner checksum. The issue is still present when we have the CRC offload enabled. In this case we need to disable the CRC offload if we require GRE checksum since otherwise skb_checksum() will report a wrong value. Fixes:90017accff
("sctp: Add GSO support") Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org> Reviewed-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
236a93cb8a
commit
b3e3feb569
1 changed files with 11 additions and 2 deletions
|
@ -19,12 +19,12 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
|
||||||
netdev_features_t features)
|
netdev_features_t features)
|
||||||
{
|
{
|
||||||
int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb);
|
int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb);
|
||||||
|
bool need_csum, need_recompute_csum, gso_partial;
|
||||||
struct sk_buff *segs = ERR_PTR(-EINVAL);
|
struct sk_buff *segs = ERR_PTR(-EINVAL);
|
||||||
u16 mac_offset = skb->mac_header;
|
u16 mac_offset = skb->mac_header;
|
||||||
__be16 protocol = skb->protocol;
|
__be16 protocol = skb->protocol;
|
||||||
u16 mac_len = skb->mac_len;
|
u16 mac_len = skb->mac_len;
|
||||||
int gre_offset, outer_hlen;
|
int gre_offset, outer_hlen;
|
||||||
bool need_csum, gso_partial;
|
|
||||||
|
|
||||||
if (!skb->encapsulation)
|
if (!skb->encapsulation)
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -45,6 +45,7 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
|
||||||
skb->protocol = skb->inner_protocol;
|
skb->protocol = skb->inner_protocol;
|
||||||
|
|
||||||
need_csum = !!(skb_shinfo(skb)->gso_type & SKB_GSO_GRE_CSUM);
|
need_csum = !!(skb_shinfo(skb)->gso_type & SKB_GSO_GRE_CSUM);
|
||||||
|
need_recompute_csum = skb->csum_not_inet;
|
||||||
skb->encap_hdr_csum = need_csum;
|
skb->encap_hdr_csum = need_csum;
|
||||||
|
|
||||||
features &= skb->dev->hw_enc_features;
|
features &= skb->dev->hw_enc_features;
|
||||||
|
@ -102,7 +103,15 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
|
||||||
}
|
}
|
||||||
|
|
||||||
*(pcsum + 1) = 0;
|
*(pcsum + 1) = 0;
|
||||||
|
if (need_recompute_csum && !skb_is_gso(skb)) {
|
||||||
|
__wsum csum;
|
||||||
|
|
||||||
|
csum = skb_checksum(skb, gre_offset,
|
||||||
|
skb->len - gre_offset, 0);
|
||||||
|
*pcsum = csum_fold(csum);
|
||||||
|
} else {
|
||||||
*pcsum = gso_make_checksum(skb, 0);
|
*pcsum = gso_make_checksum(skb, 0);
|
||||||
|
}
|
||||||
} while ((skb = skb->next));
|
} while ((skb = skb->next));
|
||||||
out:
|
out:
|
||||||
return segs;
|
return segs;
|
||||||
|
|
Loading…
Reference in a new issue