From 6d3db9f2433cfb32826278bd7e7ab2677d2a64cb Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Fri, 25 Jul 2008 02:55:33 -0700 Subject: [PATCH] --- yaml --- r: 106135 b: refs/heads/master c: 7d7e5a60c62e88cb8782760bb6c4d3bd1577a6c6 h: refs/heads/master i: 106133: 75502eca8af3fd5ba8b6275758dc062de2c8dd10 106131: 73662fc1bb11c95e9f06e634a5a5e85fea5ef6f6 106127: c64999868a64ad79f6e524c7868c11f88c838134 v: v3 --- [refs] | 2 +- trunk/net/xfrm/xfrm_ipcomp.c | 48 +++++++++++++++++++++++++++++++----- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/[refs] b/[refs] index 797a8ee082a1..53f66dc48c47 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 6fccab671f2f0a24b799f29a4ec878f62d34656c +refs/heads/master: 7d7e5a60c62e88cb8782760bb6c4d3bd1577a6c6 diff --git a/trunk/net/xfrm/xfrm_ipcomp.c b/trunk/net/xfrm/xfrm_ipcomp.c index b51e804fbbad..800f669083fb 100644 --- a/trunk/net/xfrm/xfrm_ipcomp.c +++ b/trunk/net/xfrm/xfrm_ipcomp.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -49,6 +50,7 @@ static int ipcomp_decompress(struct xfrm_state *x, struct sk_buff *skb) u8 *scratch = *per_cpu_ptr(ipcomp_scratches, cpu); struct crypto_comp *tfm = *per_cpu_ptr(ipcd->tfms, cpu); int err = crypto_comp_decompress(tfm, start, plen, scratch, &dlen); + int len; if (err) goto out; @@ -58,13 +60,47 @@ static int ipcomp_decompress(struct xfrm_state *x, struct sk_buff *skb) goto out; } - err = pskb_expand_head(skb, 0, dlen - plen, GFP_ATOMIC); - if (err) - goto out; + len = dlen - plen; + if (len > skb_tailroom(skb)) + len = skb_tailroom(skb); + + skb->truesize += len; + __skb_put(skb, len); + + len += plen; + skb_copy_to_linear_data(skb, scratch, len); + + while ((scratch += len, dlen -= len) > 0) { + skb_frag_t *frag; + + err = -EMSGSIZE; + if (WARN_ON(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS)) + goto out; + + frag = skb_shinfo(skb)->frags + skb_shinfo(skb)->nr_frags; + frag->page = alloc_page(GFP_ATOMIC); + + err = -ENOMEM; + if (!frag->page) + goto out; + + len = PAGE_SIZE; + if (dlen < len) + len = dlen; + + memcpy(page_address(frag->page), scratch, len); + + frag->page_offset = 0; + frag->size = len; + skb->truesize += len; + skb->data_len += len; + skb->len += len; + + skb_shinfo(skb)->nr_frags++; + } + + err = 0; - skb->truesize += dlen - plen; - __skb_put(skb, dlen - plen); - skb_copy_to_linear_data(skb, scratch, dlen); out: put_cpu(); return err;