aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/skbuff.h2
-rw-r--r--net/core/skbuff.c59
2 files changed, 61 insertions, 0 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index acf17af45af9..cf2cb50f77d1 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1687,6 +1687,8 @@ extern int skb_shift(struct sk_buff *tgt, struct sk_buff *skb,
1687 int shiftlen); 1687 int shiftlen);
1688 1688
1689extern struct sk_buff *skb_segment(struct sk_buff *skb, int features); 1689extern struct sk_buff *skb_segment(struct sk_buff *skb, int features);
1690extern int skb_gro_receive(struct sk_buff **head,
1691 struct sk_buff *skb);
1690 1692
1691static inline void *skb_header_pointer(const struct sk_buff *skb, int offset, 1693static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
1692 int len, void *buffer) 1694 int len, void *buffer)
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
2583EXPORT_SYMBOL_GPL(skb_segment); 2583EXPORT_SYMBOL_GPL(skb_segment);
2584 2584
2585int 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
2629merge:
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}
2642EXPORT_SYMBOL_GPL(skb_gro_receive);
2643
2585void __init skb_init(void) 2644void __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",