diff options
Diffstat (limited to 'net/core/skbuff.c')
-rw-r--r-- | net/core/skbuff.c | 23 |
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; |