|
@@ -2582,6 +2582,65 @@ err:
|
|
|
|
|
|
EXPORT_SYMBOL_GPL(skb_segment);
|
|
EXPORT_SYMBOL_GPL(skb_segment);
|
|
|
|
|
|
|
|
+int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
|
|
|
|
+{
|
|
|
|
+ struct sk_buff *p = *head;
|
|
|
|
+ struct sk_buff *nskb;
|
|
|
|
+ unsigned int headroom;
|
|
|
|
+ unsigned int hlen = p->data - skb_mac_header(p);
|
|
|
|
+
|
|
|
|
+ if (hlen + p->len + skb->len >= 65536)
|
|
|
|
+ return -E2BIG;
|
|
|
|
+
|
|
|
|
+ if (skb_shinfo(p)->frag_list)
|
|
|
|
+ goto merge;
|
|
|
|
+
|
|
|
|
+ headroom = skb_headroom(p);
|
|
|
|
+ nskb = netdev_alloc_skb(p->dev, headroom);
|
|
|
|
+ if (unlikely(!nskb))
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+
|
|
|
|
+ __copy_skb_header(nskb, p);
|
|
|
|
+ nskb->mac_len = p->mac_len;
|
|
|
|
+
|
|
|
|
+ skb_reserve(nskb, headroom);
|
|
|
|
+
|
|
|
|
+ skb_set_mac_header(nskb, -hlen);
|
|
|
|
+ skb_set_network_header(nskb, skb_network_offset(p));
|
|
|
|
+ skb_set_transport_header(nskb, skb_transport_offset(p));
|
|
|
|
+
|
|
|
|
+ memcpy(skb_mac_header(nskb), skb_mac_header(p), hlen);
|
|
|
|
+
|
|
|
|
+ *NAPI_GRO_CB(nskb) = *NAPI_GRO_CB(p);
|
|
|
|
+ skb_shinfo(nskb)->frag_list = p;
|
|
|
|
+ skb_header_release(p);
|
|
|
|
+ nskb->prev = p;
|
|
|
|
+
|
|
|
|
+ nskb->data_len += p->len;
|
|
|
|
+ nskb->truesize += p->len;
|
|
|
|
+ nskb->len += p->len;
|
|
|
|
+
|
|
|
|
+ *head = nskb;
|
|
|
|
+ nskb->next = p->next;
|
|
|
|
+ p->next = NULL;
|
|
|
|
+
|
|
|
|
+ p = nskb;
|
|
|
|
+
|
|
|
|
+merge:
|
|
|
|
+ NAPI_GRO_CB(p)->count++;
|
|
|
|
+ p->prev->next = skb;
|
|
|
|
+ p->prev = skb;
|
|
|
|
+ skb_header_release(skb);
|
|
|
|
+
|
|
|
|
+ p->data_len += skb->len;
|
|
|
|
+ p->truesize += skb->len;
|
|
|
|
+ p->len += skb->len;
|
|
|
|
+
|
|
|
|
+ NAPI_GRO_CB(skb)->same_flow = 1;
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL_GPL(skb_gro_receive);
|
|
|
|
+
|
|
void __init skb_init(void)
|
|
void __init skb_init(void)
|
|
{
|
|
{
|
|
skbuff_head_cache = kmem_cache_create("skbuff_head_cache",
|
|
skbuff_head_cache = kmem_cache_create("skbuff_head_cache",
|