diff options
author | Pravin B Shelar <pshelar@nicira.com> | 2013-05-02 12:14:19 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-05-03 16:08:58 -0400 |
commit | 9b3eb5edf33897dc9128aa27300066153d4f8b9c (patch) | |
tree | f4881f9cc2e54a7741ba4b0ef9e04e4094c2c43d | |
parent | 83401eb4990ff6af55aeed8f49681558544192e6 (diff) |
gre: Fix GREv4 TCPv6 segmentation.
For ipv6 traffic, GRE can generate packet with strange GSO
bits, e.g. ipv4 packet with SKB_GSO_TCPV6 flag set. Therefore
following patch relaxes check in inet gso handler to allow
such packet for segmentation.
This patch also fixes wrong skb->protocol set that was done in
gre_gso_segment() handler.
Reported-by: Steinar H. Gunderson <sesse@google.com>
CC: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Acked-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/ipv4/af_inet.c | 1 | ||||
-rw-r--r-- | net/ipv4/gre.c | 4 |
2 files changed, 4 insertions, 1 deletions
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index c61b3bb87a16..d01be2a3ae53 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c | |||
@@ -1293,6 +1293,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, | |||
1293 | SKB_GSO_DODGY | | 1293 | SKB_GSO_DODGY | |
1294 | SKB_GSO_TCP_ECN | | 1294 | SKB_GSO_TCP_ECN | |
1295 | SKB_GSO_GRE | | 1295 | SKB_GSO_GRE | |
1296 | SKB_GSO_TCPV6 | | ||
1296 | SKB_GSO_UDP_TUNNEL | | 1297 | SKB_GSO_UDP_TUNNEL | |
1297 | 0))) | 1298 | 0))) |
1298 | goto out; | 1299 | goto out; |
diff --git a/net/ipv4/gre.c b/net/ipv4/gre.c index d2d5a99fba09..cc22363965d2 100644 --- a/net/ipv4/gre.c +++ b/net/ipv4/gre.c | |||
@@ -121,6 +121,7 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb, | |||
121 | int ghl = GRE_HEADER_SECTION; | 121 | int ghl = GRE_HEADER_SECTION; |
122 | struct gre_base_hdr *greh; | 122 | struct gre_base_hdr *greh; |
123 | int mac_len = skb->mac_len; | 123 | int mac_len = skb->mac_len; |
124 | __be16 protocol = skb->protocol; | ||
124 | int tnl_hlen; | 125 | int tnl_hlen; |
125 | bool csum; | 126 | bool csum; |
126 | 127 | ||
@@ -150,7 +151,7 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb, | |||
150 | 151 | ||
151 | /* setup inner skb. */ | 152 | /* setup inner skb. */ |
152 | if (greh->protocol == htons(ETH_P_TEB)) { | 153 | if (greh->protocol == htons(ETH_P_TEB)) { |
153 | struct ethhdr *eth = eth_hdr(skb); | 154 | struct ethhdr *eth = (struct ethhdr *)skb_inner_mac_header(skb); |
154 | skb->protocol = eth->h_proto; | 155 | skb->protocol = eth->h_proto; |
155 | } else { | 156 | } else { |
156 | skb->protocol = greh->protocol; | 157 | skb->protocol = greh->protocol; |
@@ -199,6 +200,7 @@ static struct sk_buff *gre_gso_segment(struct sk_buff *skb, | |||
199 | skb_reset_mac_header(skb); | 200 | skb_reset_mac_header(skb); |
200 | skb_set_network_header(skb, mac_len); | 201 | skb_set_network_header(skb, mac_len); |
201 | skb->mac_len = mac_len; | 202 | skb->mac_len = mac_len; |
203 | skb->protocol = protocol; | ||
202 | } while ((skb = skb->next)); | 204 | } while ((skb = skb->next)); |
203 | out: | 205 | out: |
204 | return segs; | 206 | return segs; |