aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/dev.c
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2009-02-01 04:24:55 -0500
committerDavid S. Miller <davem@davemloft.net>2009-02-01 04:24:55 -0500
commitad0f9904444de1309dedd2b9e365cae8af77d9b1 (patch)
treec60a3572d8a84aaee2b4a1dc63d69815013d2273 /net/core/dev.c
parent3efac5a0012979ae236fe1247b773317ef5f1c88 (diff)
gro: Fix handling of imprecisely split packets
The commit 89a1b249edcf9be884e71f92df84d48355c576aa (gro: Avoid copying headers of unmerged packets) only worked for packets which are either completely linear, completely non-linear, or packets which exactly split at the boundary between headers and payload. Anything else would cause bits in the header to go missing if the packet is held by GRO. This may have broken drivers such as ixgbe. This patch fixes the places that assumed or only worked with the above cases. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/dev.c')
-rw-r--r--net/core/dev.c16
1 files changed, 10 insertions, 6 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index ec5be1c7f2f..220f52a1001 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -217,7 +217,7 @@ static inline struct hlist_head *dev_index_hash(struct net *net, int ifindex)
217 217
218static inline void *skb_gro_mac_header(struct sk_buff *skb) 218static inline void *skb_gro_mac_header(struct sk_buff *skb)
219{ 219{
220 return skb_headlen(skb) ? skb_mac_header(skb) : 220 return skb_mac_header(skb) < skb->data ? skb_mac_header(skb) :
221 page_address(skb_shinfo(skb)->frags[0].page) + 221 page_address(skb_shinfo(skb)->frags[0].page) +
222 skb_shinfo(skb)->frags[0].page_offset; 222 skb_shinfo(skb)->frags[0].page_offset;
223} 223}
@@ -2469,11 +2469,19 @@ int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
2469 napi->gro_list = skb; 2469 napi->gro_list = skb;
2470 ret = GRO_HELD; 2470 ret = GRO_HELD;
2471 2471
2472pull:
2473 if (unlikely(!pskb_may_pull(skb, skb_gro_offset(skb)))) {
2474 if (napi->gro_list == skb)
2475 napi->gro_list = skb->next;
2476 ret = GRO_DROP;
2477 }
2478
2472ok: 2479ok:
2473 return ret; 2480 return ret;
2474 2481
2475normal: 2482normal:
2476 return GRO_NORMAL; 2483 ret = GRO_NORMAL;
2484 goto pull;
2477} 2485}
2478EXPORT_SYMBOL(dev_gro_receive); 2486EXPORT_SYMBOL(dev_gro_receive);
2479 2487
@@ -2589,14 +2597,10 @@ EXPORT_SYMBOL(napi_fraginfo_skb);
2589int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, int ret) 2597int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, int ret)
2590{ 2598{
2591 int err = NET_RX_SUCCESS; 2599 int err = NET_RX_SUCCESS;
2592 int may;
2593 2600
2594 switch (ret) { 2601 switch (ret) {
2595 case GRO_NORMAL: 2602 case GRO_NORMAL:
2596 case GRO_HELD: 2603 case GRO_HELD:
2597 may = pskb_may_pull(skb, skb_gro_offset(skb));
2598 BUG_ON(!may);
2599
2600 skb->protocol = eth_type_trans(skb, napi->dev); 2604 skb->protocol = eth_type_trans(skb, napi->dev);
2601 2605
2602 if (ret == GRO_NORMAL) 2606 if (ret == GRO_NORMAL)