diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2006-07-30 20:20:28 -0700 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-08-02 13:38:16 -0700 |
commit | f4d26fb336f3c08066bffbe907d3104be4fb91a8 (patch) | |
tree | 5502b74f0c32355986a5cb73136c3d70c305d51f /net/core/skbuff.c | |
parent | 9cd3ecd674cf3194e07435b5b9559c4d432026d5 (diff) | |
download | linux-3.10-f4d26fb336f3c08066bffbe907d3104be4fb91a8.tar.gz linux-3.10-f4d26fb336f3c08066bffbe907d3104be4fb91a8.tar.bz2 linux-3.10-f4d26fb336f3c08066bffbe907d3104be4fb91a8.zip |
[NET]: Fix ___pskb_trim when entire frag_list needs dropping
When the trim point is within the head and there is no paged data,
___pskb_trim fails to drop the first element in the frag_list.
This patch fixes this by moving the len <= offset case out of the
page data loop.
This patch also adds a missing kfree_skb on the frag that we just
cloned.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/skbuff.c')
-rw-r--r-- | net/core/skbuff.c | 14 |
1 files changed, 10 insertions, 4 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 476aa397850..d236f02c646 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -846,7 +846,11 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len) unlikely((err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))) return err; - for (i = 0; i < nfrags; i++) { + i = 0; + if (offset >= len) + goto drop_pages; + + for (; i < nfrags; i++) { int end = offset + skb_shinfo(skb)->frags[i].size; if (end < len) { @@ -854,9 +858,9 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len) continue; } - if (len > offset) - skb_shinfo(skb)->frags[i++].size = len - offset; + skb_shinfo(skb)->frags[i++].size = len - offset; +drop_pages: skb_shinfo(skb)->nr_frags = i; for (; i < nfrags; i++) @@ -864,7 +868,7 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len) if (skb_shinfo(skb)->frag_list) skb_drop_fraglist(skb); - break; + goto done; } for (fragp = &skb_shinfo(skb)->frag_list; (frag = *fragp); @@ -879,6 +883,7 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len) return -ENOMEM; nfrag->next = frag->next; + kfree_skb(frag); frag = nfrag; *fragp = frag; } @@ -897,6 +902,7 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len) break; } +done: if (len > skb_headlen(skb)) { skb->data_len -= skb->len - len; skb->len = len; |