diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2006-07-30 23:20:28 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-08-02 16:38:16 -0400 |
commit | f4d26fb336f3c08066bffbe907d3104be4fb91a8 (patch) | |
tree | 5502b74f0c32355986a5cb73136c3d70c305d51f /net | |
parent | 9cd3ecd674cf3194e07435b5b9559c4d432026d5 (diff) |
[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')
-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 476aa3978504..d236f02c6467 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) | |||
846 | unlikely((err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))) | 846 | unlikely((err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))) |
847 | return err; | 847 | return err; |
848 | 848 | ||
849 | for (i = 0; i < nfrags; i++) { | 849 | i = 0; |
850 | if (offset >= len) | ||
851 | goto drop_pages; | ||
852 | |||
853 | for (; i < nfrags; i++) { | ||
850 | int end = offset + skb_shinfo(skb)->frags[i].size; | 854 | int end = offset + skb_shinfo(skb)->frags[i].size; |
851 | 855 | ||
852 | if (end < len) { | 856 | if (end < len) { |
@@ -854,9 +858,9 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len) | |||
854 | continue; | 858 | continue; |
855 | } | 859 | } |
856 | 860 | ||
857 | if (len > offset) | 861 | skb_shinfo(skb)->frags[i++].size = len - offset; |
858 | skb_shinfo(skb)->frags[i++].size = len - offset; | ||
859 | 862 | ||
863 | drop_pages: | ||
860 | skb_shinfo(skb)->nr_frags = i; | 864 | skb_shinfo(skb)->nr_frags = i; |
861 | 865 | ||
862 | for (; i < nfrags; i++) | 866 | for (; i < nfrags; i++) |
@@ -864,7 +868,7 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len) | |||
864 | 868 | ||
865 | if (skb_shinfo(skb)->frag_list) | 869 | if (skb_shinfo(skb)->frag_list) |
866 | skb_drop_fraglist(skb); | 870 | skb_drop_fraglist(skb); |
867 | break; | 871 | goto done; |
868 | } | 872 | } |
869 | 873 | ||
870 | for (fragp = &skb_shinfo(skb)->frag_list; (frag = *fragp); | 874 | for (fragp = &skb_shinfo(skb)->frag_list; (frag = *fragp); |
@@ -879,6 +883,7 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len) | |||
879 | return -ENOMEM; | 883 | return -ENOMEM; |
880 | 884 | ||
881 | nfrag->next = frag->next; | 885 | nfrag->next = frag->next; |
886 | kfree_skb(frag); | ||
882 | frag = nfrag; | 887 | frag = nfrag; |
883 | *fragp = frag; | 888 | *fragp = frag; |
884 | } | 889 | } |
@@ -897,6 +902,7 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len) | |||
897 | break; | 902 | break; |
898 | } | 903 | } |
899 | 904 | ||
905 | done: | ||
900 | if (len > skb_headlen(skb)) { | 906 | if (len > skb_headlen(skb)) { |
901 | skb->data_len -= skb->len - len; | 907 | skb->data_len -= skb->len - len; |
902 | skb->len = len; | 908 | skb->len = len; |