diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/core/skbuff.c | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 18e224af05a6..b8d0abb26433 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -2582,6 +2582,65 @@ err: | |||
2582 | 2582 | ||
2583 | EXPORT_SYMBOL_GPL(skb_segment); | 2583 | EXPORT_SYMBOL_GPL(skb_segment); |
2584 | 2584 | ||
2585 | int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) | ||
2586 | { | ||
2587 | struct sk_buff *p = *head; | ||
2588 | struct sk_buff *nskb; | ||
2589 | unsigned int headroom; | ||
2590 | unsigned int hlen = p->data - skb_mac_header(p); | ||
2591 | |||
2592 | if (hlen + p->len + skb->len >= 65536) | ||
2593 | return -E2BIG; | ||
2594 | |||
2595 | if (skb_shinfo(p)->frag_list) | ||
2596 | goto merge; | ||
2597 | |||
2598 | headroom = skb_headroom(p); | ||
2599 | nskb = netdev_alloc_skb(p->dev, headroom); | ||
2600 | if (unlikely(!nskb)) | ||
2601 | return -ENOMEM; | ||
2602 | |||
2603 | __copy_skb_header(nskb, p); | ||
2604 | nskb->mac_len = p->mac_len; | ||
2605 | |||
2606 | skb_reserve(nskb, headroom); | ||
2607 | |||
2608 | skb_set_mac_header(nskb, -hlen); | ||
2609 | skb_set_network_header(nskb, skb_network_offset(p)); | ||
2610 | skb_set_transport_header(nskb, skb_transport_offset(p)); | ||
2611 | |||
2612 | memcpy(skb_mac_header(nskb), skb_mac_header(p), hlen); | ||
2613 | |||
2614 | *NAPI_GRO_CB(nskb) = *NAPI_GRO_CB(p); | ||
2615 | skb_shinfo(nskb)->frag_list = p; | ||
2616 | skb_header_release(p); | ||
2617 | nskb->prev = p; | ||
2618 | |||
2619 | nskb->data_len += p->len; | ||
2620 | nskb->truesize += p->len; | ||
2621 | nskb->len += p->len; | ||
2622 | |||
2623 | *head = nskb; | ||
2624 | nskb->next = p->next; | ||
2625 | p->next = NULL; | ||
2626 | |||
2627 | p = nskb; | ||
2628 | |||
2629 | merge: | ||
2630 | NAPI_GRO_CB(p)->count++; | ||
2631 | p->prev->next = skb; | ||
2632 | p->prev = skb; | ||
2633 | skb_header_release(skb); | ||
2634 | |||
2635 | p->data_len += skb->len; | ||
2636 | p->truesize += skb->len; | ||
2637 | p->len += skb->len; | ||
2638 | |||
2639 | NAPI_GRO_CB(skb)->same_flow = 1; | ||
2640 | return 0; | ||
2641 | } | ||
2642 | EXPORT_SYMBOL_GPL(skb_gro_receive); | ||
2643 | |||
2585 | void __init skb_init(void) | 2644 | void __init skb_init(void) |
2586 | { | 2645 | { |
2587 | skbuff_head_cache = kmem_cache_create("skbuff_head_cache", | 2646 | skbuff_head_cache = kmem_cache_create("skbuff_head_cache", |