diff options
| -rw-r--r-- | net/xfrm/xfrm_ipcomp.c | 48 |
1 files changed, 42 insertions, 6 deletions
diff --git a/net/xfrm/xfrm_ipcomp.c b/net/xfrm/xfrm_ipcomp.c index b51e804fbbad..800f669083fb 100644 --- a/net/xfrm/xfrm_ipcomp.c +++ b/net/xfrm/xfrm_ipcomp.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | 17 | ||
| 18 | #include <linux/crypto.h> | 18 | #include <linux/crypto.h> |
| 19 | #include <linux/err.h> | 19 | #include <linux/err.h> |
| 20 | #include <linux/gfp.h> | ||
| 20 | #include <linux/list.h> | 21 | #include <linux/list.h> |
| 21 | #include <linux/module.h> | 22 | #include <linux/module.h> |
| 22 | #include <linux/mutex.h> | 23 | #include <linux/mutex.h> |
| @@ -49,6 +50,7 @@ static int ipcomp_decompress(struct xfrm_state *x, struct sk_buff *skb) | |||
| 49 | u8 *scratch = *per_cpu_ptr(ipcomp_scratches, cpu); | 50 | u8 *scratch = *per_cpu_ptr(ipcomp_scratches, cpu); |
| 50 | struct crypto_comp *tfm = *per_cpu_ptr(ipcd->tfms, cpu); | 51 | struct crypto_comp *tfm = *per_cpu_ptr(ipcd->tfms, cpu); |
| 51 | int err = crypto_comp_decompress(tfm, start, plen, scratch, &dlen); | 52 | int err = crypto_comp_decompress(tfm, start, plen, scratch, &dlen); |
| 53 | int len; | ||
| 52 | 54 | ||
| 53 | if (err) | 55 | if (err) |
| 54 | goto out; | 56 | goto out; |
| @@ -58,13 +60,47 @@ static int ipcomp_decompress(struct xfrm_state *x, struct sk_buff *skb) | |||
| 58 | goto out; | 60 | goto out; |
| 59 | } | 61 | } |
| 60 | 62 | ||
| 61 | err = pskb_expand_head(skb, 0, dlen - plen, GFP_ATOMIC); | 63 | len = dlen - plen; |
| 62 | if (err) | 64 | if (len > skb_tailroom(skb)) |
| 63 | goto out; | 65 | len = skb_tailroom(skb); |
| 66 | |||
| 67 | skb->truesize += len; | ||
| 68 | __skb_put(skb, len); | ||
| 69 | |||
| 70 | len += plen; | ||
| 71 | skb_copy_to_linear_data(skb, scratch, len); | ||
| 72 | |||
| 73 | while ((scratch += len, dlen -= len) > 0) { | ||
| 74 | skb_frag_t *frag; | ||
| 75 | |||
| 76 | err = -EMSGSIZE; | ||
| 77 | if (WARN_ON(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS)) | ||
| 78 | goto out; | ||
| 79 | |||
| 80 | frag = skb_shinfo(skb)->frags + skb_shinfo(skb)->nr_frags; | ||
| 81 | frag->page = alloc_page(GFP_ATOMIC); | ||
| 82 | |||
| 83 | err = -ENOMEM; | ||
| 84 | if (!frag->page) | ||
| 85 | goto out; | ||
| 86 | |||
| 87 | len = PAGE_SIZE; | ||
| 88 | if (dlen < len) | ||
| 89 | len = dlen; | ||
| 90 | |||
| 91 | memcpy(page_address(frag->page), scratch, len); | ||
| 92 | |||
| 93 | frag->page_offset = 0; | ||
| 94 | frag->size = len; | ||
| 95 | skb->truesize += len; | ||
| 96 | skb->data_len += len; | ||
| 97 | skb->len += len; | ||
| 98 | |||
| 99 | skb_shinfo(skb)->nr_frags++; | ||
| 100 | } | ||
| 101 | |||
| 102 | err = 0; | ||
| 64 | 103 | ||
| 65 | skb->truesize += dlen - plen; | ||
| 66 | __skb_put(skb, dlen - plen); | ||
| 67 | skb_copy_to_linear_data(skb, scratch, dlen); | ||
| 68 | out: | 104 | out: |
| 69 | put_cpu(); | 105 | put_cpu(); |
| 70 | return err; | 106 | return err; |
