Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 122712
b: refs/heads/master
c: 89319d3
h: refs/heads/master
v: v3
  • Loading branch information
Herbert Xu authored and David S. Miller committed Dec 16, 2008
1 parent e55a4b2 commit 11b06ca
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 15 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: eb14f019597cd86c21a6c601d7e900f40030c2e7
refs/heads/master: 89319d3801d1d3ac29c7df1f067038986f267d29
73 changes: 59 additions & 14 deletions trunk/net/core/skbuff.c
Original file line number Diff line number Diff line change
Expand Up @@ -2428,6 +2428,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features)
{
struct sk_buff *segs = NULL;
struct sk_buff *tail = NULL;
struct sk_buff *fskb = skb_shinfo(skb)->frag_list;
unsigned int mss = skb_shinfo(skb)->gso_size;
unsigned int doffset = skb->data - skb_mac_header(skb);
unsigned int offset = doffset;
Expand All @@ -2447,7 +2448,6 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features)
struct sk_buff *nskb;
skb_frag_t *frag;
int hsize;
int k;
int size;

len = skb->len - offset;
Expand All @@ -2460,9 +2460,36 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features)
if (hsize > len || !sg)
hsize = len;

nskb = alloc_skb(hsize + doffset + headroom, GFP_ATOMIC);
if (unlikely(!nskb))
goto err;
if (!hsize && i >= nfrags) {
BUG_ON(fskb->len != len);

pos += len;
nskb = skb_clone(fskb, GFP_ATOMIC);
fskb = fskb->next;

if (unlikely(!nskb))
goto err;

hsize = skb_end_pointer(nskb) - nskb->head;
if (skb_cow_head(nskb, doffset + headroom)) {
kfree_skb(nskb);
goto err;
}

nskb->truesize += skb_end_pointer(nskb) - nskb->head -
hsize;
skb_release_head_state(nskb);
__skb_push(nskb, doffset);
} else {
nskb = alloc_skb(hsize + doffset + headroom,
GFP_ATOMIC);

if (unlikely(!nskb))
goto err;

skb_reserve(nskb, headroom);
__skb_put(nskb, doffset);
}

if (segs)
tail->next = nskb;
Expand All @@ -2473,13 +2500,15 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features)
__copy_skb_header(nskb, skb);
nskb->mac_len = skb->mac_len;

skb_reserve(nskb, headroom);
skb_reset_mac_header(nskb);
skb_set_network_header(nskb, skb->mac_len);
nskb->transport_header = (nskb->network_header +
skb_network_header_len(skb));
skb_copy_from_linear_data(skb, skb_put(nskb, doffset),
doffset);
skb_copy_from_linear_data(skb, nskb->data, doffset);

if (pos >= offset + len)
continue;

if (!sg) {
nskb->ip_summed = CHECKSUM_NONE;
nskb->csum = skb_copy_and_csum_bits(skb, offset,
Expand All @@ -2489,14 +2518,11 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features)
}

frag = skb_shinfo(nskb)->frags;
k = 0;

skb_copy_from_linear_data_offset(skb, offset,
skb_put(nskb, hsize), hsize);

while (pos < offset + len) {
BUG_ON(i >= nfrags);

while (pos < offset + len && i < nfrags) {
*frag = skb_shinfo(skb)->frags[i];
get_page(frag->page);
size = frag->size;
Expand All @@ -2506,20 +2532,39 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features)
frag->size -= offset - pos;
}

k++;
skb_shinfo(nskb)->nr_frags++;

if (pos + size <= offset + len) {
i++;
pos += size;
} else {
frag->size -= pos + size - (offset + len);
break;
goto skip_fraglist;
}

frag++;
}

skb_shinfo(nskb)->nr_frags = k;
if (pos < offset + len) {
struct sk_buff *fskb2 = fskb;

BUG_ON(pos + fskb->len != offset + len);

pos += fskb->len;
fskb = fskb->next;

if (fskb2->next) {
fskb2 = skb_clone(fskb2, GFP_ATOMIC);
if (!fskb2)
goto err;
} else
skb_get(fskb2);

BUG_ON(skb_shinfo(nskb)->frag_list);
skb_shinfo(nskb)->frag_list = fskb2;
}

skip_fraglist:
nskb->data_len = len - hsize;
nskb->len += nskb->data_len;
nskb->truesize += nskb->data_len;
Expand Down

0 comments on commit 11b06ca

Please sign in to comment.