aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/skbuff.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/core/skbuff.c')
-rw-r--r--net/core/skbuff.c23
1 files changed, 15 insertions, 8 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 2e5f2ca3bdcd..f9f4065a7e9b 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -2584,17 +2584,21 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
2584 struct sk_buff *p = *head; 2584 struct sk_buff *p = *head;
2585 struct sk_buff *nskb; 2585 struct sk_buff *nskb;
2586 unsigned int headroom; 2586 unsigned int headroom;
2587 unsigned int hlen = p->data - skb_mac_header(p); 2587 unsigned int len = skb_gro_len(skb);
2588 unsigned int len = skb->len;
2589 2588
2590 if (hlen + p->len + len >= 65536) 2589 if (p->len + len >= 65536)
2591 return -E2BIG; 2590 return -E2BIG;
2592 2591
2593 if (skb_shinfo(p)->frag_list) 2592 if (skb_shinfo(p)->frag_list)
2594 goto merge; 2593 goto merge;
2595 else if (!skb_headlen(p) && !skb_headlen(skb) && 2594 else if (skb_headlen(skb) <= skb_gro_offset(skb) &&
2596 skb_shinfo(p)->nr_frags + skb_shinfo(skb)->nr_frags < 2595 skb_shinfo(p)->nr_frags + skb_shinfo(skb)->nr_frags <=
2597 MAX_SKB_FRAGS) { 2596 MAX_SKB_FRAGS) {
2597 skb_shinfo(skb)->frags[0].page_offset +=
2598 skb_gro_offset(skb) - skb_headlen(skb);
2599 skb_shinfo(skb)->frags[0].size -=
2600 skb_gro_offset(skb) - skb_headlen(skb);
2601
2598 memcpy(skb_shinfo(p)->frags + skb_shinfo(p)->nr_frags, 2602 memcpy(skb_shinfo(p)->frags + skb_shinfo(p)->nr_frags,
2599 skb_shinfo(skb)->frags, 2603 skb_shinfo(skb)->frags,
2600 skb_shinfo(skb)->nr_frags * sizeof(skb_frag_t)); 2604 skb_shinfo(skb)->nr_frags * sizeof(skb_frag_t));
@@ -2611,7 +2615,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
2611 } 2615 }
2612 2616
2613 headroom = skb_headroom(p); 2617 headroom = skb_headroom(p);
2614 nskb = netdev_alloc_skb(p->dev, headroom); 2618 nskb = netdev_alloc_skb(p->dev, headroom + skb_gro_offset(p));
2615 if (unlikely(!nskb)) 2619 if (unlikely(!nskb))
2616 return -ENOMEM; 2620 return -ENOMEM;
2617 2621
@@ -2619,12 +2623,15 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
2619 nskb->mac_len = p->mac_len; 2623 nskb->mac_len = p->mac_len;
2620 2624
2621 skb_reserve(nskb, headroom); 2625 skb_reserve(nskb, headroom);
2626 __skb_put(nskb, skb_gro_offset(p));
2622 2627
2623 skb_set_mac_header(nskb, -hlen); 2628 skb_set_mac_header(nskb, skb_mac_header(p) - p->data);
2624 skb_set_network_header(nskb, skb_network_offset(p)); 2629 skb_set_network_header(nskb, skb_network_offset(p));
2625 skb_set_transport_header(nskb, skb_transport_offset(p)); 2630 skb_set_transport_header(nskb, skb_transport_offset(p));
2626 2631
2627 memcpy(skb_mac_header(nskb), skb_mac_header(p), hlen); 2632 __skb_pull(p, skb_gro_offset(p));
2633 memcpy(skb_mac_header(nskb), skb_mac_header(p),
2634 p->data - skb_mac_header(p));
2628 2635
2629 *NAPI_GRO_CB(nskb) = *NAPI_GRO_CB(p); 2636 *NAPI_GRO_CB(nskb) = *NAPI_GRO_CB(p);
2630 skb_shinfo(nskb)->frag_list = p; 2637 skb_shinfo(nskb)->frag_list = p;