|
@@ -3460,6 +3460,19 @@ void *skb_pull_rcsum(struct sk_buff *skb, unsigned int len)
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(skb_pull_rcsum);
|
|
|
|
|
|
+static inline skb_frag_t skb_head_frag_to_page_desc(struct sk_buff *frag_skb)
|
|
|
+{
|
|
|
+ skb_frag_t head_frag;
|
|
|
+ struct page *page;
|
|
|
+
|
|
|
+ page = virt_to_head_page(frag_skb->head);
|
|
|
+ head_frag.page.p = page;
|
|
|
+ head_frag.page_offset = frag_skb->data -
|
|
|
+ (unsigned char *)page_address(page);
|
|
|
+ head_frag.size = skb_headlen(frag_skb);
|
|
|
+ return head_frag;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* skb_segment - Perform protocol segmentation on skb.
|
|
|
* @head_skb: buffer to segment
|
|
@@ -3664,15 +3677,19 @@ normal:
|
|
|
|
|
|
while (pos < offset + len) {
|
|
|
if (i >= nfrags) {
|
|
|
- BUG_ON(skb_headlen(list_skb));
|
|
|
-
|
|
|
i = 0;
|
|
|
nfrags = skb_shinfo(list_skb)->nr_frags;
|
|
|
frag = skb_shinfo(list_skb)->frags;
|
|
|
frag_skb = list_skb;
|
|
|
+ if (!skb_headlen(list_skb)) {
|
|
|
+ BUG_ON(!nfrags);
|
|
|
+ } else {
|
|
|
+ BUG_ON(!list_skb->head_frag);
|
|
|
|
|
|
- BUG_ON(!nfrags);
|
|
|
-
|
|
|
+ /* to make room for head_frag. */
|
|
|
+ i--;
|
|
|
+ frag--;
|
|
|
+ }
|
|
|
if (skb_orphan_frags(frag_skb, GFP_ATOMIC) ||
|
|
|
skb_zerocopy_clone(nskb, frag_skb,
|
|
|
GFP_ATOMIC))
|
|
@@ -3689,7 +3706,7 @@ normal:
|
|
|
goto err;
|
|
|
}
|
|
|
|
|
|
- *nskb_frag = *frag;
|
|
|
+ *nskb_frag = (i < 0) ? skb_head_frag_to_page_desc(frag_skb) : *frag;
|
|
|
__skb_frag_ref(nskb_frag);
|
|
|
size = skb_frag_size(nskb_frag);
|
|
|
|