Commit f4d26fb3 authored by Herbert Xu's avatar Herbert Xu Committed by David S. Miller

[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: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9cd3ecd6
...@@ -846,7 +846,11 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len) ...@@ -846,7 +846,11 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len)
unlikely((err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))) unlikely((err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))))
return err; 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; int end = offset + skb_shinfo(skb)->frags[i].size;
if (end < len) { if (end < len) {
...@@ -854,9 +858,9 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len) ...@@ -854,9 +858,9 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len)
continue; 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; skb_shinfo(skb)->nr_frags = i;
for (; i < nfrags; i++) for (; i < nfrags; i++)
...@@ -864,7 +868,7 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len) ...@@ -864,7 +868,7 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len)
if (skb_shinfo(skb)->frag_list) if (skb_shinfo(skb)->frag_list)
skb_drop_fraglist(skb); skb_drop_fraglist(skb);
break; goto done;
} }
for (fragp = &skb_shinfo(skb)->frag_list; (frag = *fragp); for (fragp = &skb_shinfo(skb)->frag_list; (frag = *fragp);
...@@ -879,6 +883,7 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len) ...@@ -879,6 +883,7 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len)
return -ENOMEM; return -ENOMEM;
nfrag->next = frag->next; nfrag->next = frag->next;
kfree_skb(frag);
frag = nfrag; frag = nfrag;
*fragp = frag; *fragp = frag;
} }
...@@ -897,6 +902,7 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len) ...@@ -897,6 +902,7 @@ int ___pskb_trim(struct sk_buff *skb, unsigned int len)
break; break;
} }
done:
if (len > skb_headlen(skb)) { if (len > skb_headlen(skb)) {
skb->data_len -= skb->len - len; skb->data_len -= skb->len - len;
skb->len = len; skb->len = len;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment