Skip to content

Commit

Permalink
net: gre: recompute gre csum for sctp over gre tunnels
Browse files Browse the repository at this point in the history
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: 90017ac ("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>
  • Loading branch information
Lorenzo Bianconi authored and David S. Miller committed Aug 3, 2020
1 parent fd65e5a commit 622e32b
Showing 1 changed file with 11 additions and 2 deletions.
13 changes: 11 additions & 2 deletions net/ipv4/gre_offload.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
netdev_features_t features)
{
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);
u16 mac_offset = skb->mac_header;
__be16 protocol = skb->protocol;
u16 mac_len = skb->mac_len;
int gre_offset, outer_hlen;
bool need_csum, gso_partial;

if (!skb->encapsulation)
goto out;
Expand All @@ -41,6 +41,7 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
skb->protocol = skb->inner_protocol;

need_csum = !!(skb_shinfo(skb)->gso_type & SKB_GSO_GRE_CSUM);
need_recompute_csum = skb->csum_not_inet;
skb->encap_hdr_csum = need_csum;

features &= skb->dev->hw_enc_features;
Expand Down Expand Up @@ -98,7 +99,15 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
}

*(pcsum + 1) = 0;
*pcsum = gso_make_checksum(skb, 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);
}
} while ((skb = skb->next));
out:
return segs;
Expand Down

0 comments on commit 622e32b

Please sign in to comment.