[NET]: Fix ___pskb_trim when entire frag_list needs dropping
authorHerbert Xu <herbert@gondor.apana.org.au>
Mon, 31 Jul 2006 03:20:28 +0000 (20:20 -0700)
committerDavid S. Miller <davem@sunset.davemloft.net>
Wed, 2 Aug 2006 20:38:16 +0000 (13:38 -0700)
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>
net/core/skbuff.c

index 476aa397850451555cd1e88661f38200b42a4fb7..d236f02c646768c6549e8e6a845ad9460d1c69ca 100644 (file)
@@ -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;