diff options
Diffstat (limited to 'net/ipv6/ipcomp6.c')
-rw-r--r-- | net/ipv6/ipcomp6.c | 38 |
1 files changed, 8 insertions, 30 deletions
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 48636436028..f28cd37feed 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c | |||
@@ -65,38 +65,25 @@ static LIST_HEAD(ipcomp6_tfms_list); | |||
65 | 65 | ||
66 | static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb) | 66 | static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb) |
67 | { | 67 | { |
68 | int err = 0; | 68 | int err = -ENOMEM; |
69 | u8 nexthdr = 0; | ||
70 | int hdr_len = skb->h.raw - skb->nh.raw; | ||
71 | unsigned char *tmp_hdr = NULL; | ||
72 | struct ipv6hdr *iph; | 69 | struct ipv6hdr *iph; |
70 | struct ipv6_comp_hdr *ipch; | ||
73 | int plen, dlen; | 71 | int plen, dlen; |
74 | struct ipcomp_data *ipcd = x->data; | 72 | struct ipcomp_data *ipcd = x->data; |
75 | u8 *start, *scratch; | 73 | u8 *start, *scratch; |
76 | struct crypto_tfm *tfm; | 74 | struct crypto_tfm *tfm; |
77 | int cpu; | 75 | int cpu; |
78 | 76 | ||
79 | if ((skb_is_nonlinear(skb) || skb_cloned(skb)) && | 77 | if (skb_linearize_cow(skb)) |
80 | skb_linearize(skb, GFP_ATOMIC) != 0) { | ||
81 | err = -ENOMEM; | ||
82 | goto out; | 78 | goto out; |
83 | } | ||
84 | 79 | ||
85 | skb->ip_summed = CHECKSUM_NONE; | 80 | skb->ip_summed = CHECKSUM_NONE; |
86 | 81 | ||
87 | /* Remove ipcomp header and decompress original payload */ | 82 | /* Remove ipcomp header and decompress original payload */ |
88 | iph = skb->nh.ipv6h; | 83 | iph = skb->nh.ipv6h; |
89 | tmp_hdr = kmalloc(hdr_len, GFP_ATOMIC); | 84 | ipch = (void *)skb->data; |
90 | if (!tmp_hdr) | 85 | skb->h.raw = skb->nh.raw + sizeof(*ipch); |
91 | goto out; | 86 | __skb_pull(skb, sizeof(*ipch)); |
92 | memcpy(tmp_hdr, iph, hdr_len); | ||
93 | nexthdr = *(u8 *)skb->data; | ||
94 | skb_pull(skb, sizeof(struct ipv6_comp_hdr)); | ||
95 | skb->nh.raw += sizeof(struct ipv6_comp_hdr); | ||
96 | memcpy(skb->nh.raw, tmp_hdr, hdr_len); | ||
97 | iph = skb->nh.ipv6h; | ||
98 | iph->payload_len = htons(ntohs(iph->payload_len) - sizeof(struct ipv6_comp_hdr)); | ||
99 | skb->h.raw = skb->data; | ||
100 | 87 | ||
101 | /* decompression */ | 88 | /* decompression */ |
102 | plen = skb->len; | 89 | plen = skb->len; |
@@ -125,18 +112,11 @@ static int ipcomp6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
125 | 112 | ||
126 | skb_put(skb, dlen - plen); | 113 | skb_put(skb, dlen - plen); |
127 | memcpy(skb->data, scratch, dlen); | 114 | memcpy(skb->data, scratch, dlen); |
115 | err = ipch->nexthdr; | ||
128 | 116 | ||
129 | iph = skb->nh.ipv6h; | ||
130 | iph->payload_len = htons(skb->len); | ||
131 | |||
132 | out_put_cpu: | 117 | out_put_cpu: |
133 | put_cpu(); | 118 | put_cpu(); |
134 | out: | 119 | out: |
135 | kfree(tmp_hdr); | ||
136 | if (err) | ||
137 | goto error_out; | ||
138 | return nexthdr; | ||
139 | error_out: | ||
140 | return err; | 120 | return err; |
141 | } | 121 | } |
142 | 122 | ||
@@ -159,10 +139,8 @@ static int ipcomp6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
159 | goto out_ok; | 139 | goto out_ok; |
160 | } | 140 | } |
161 | 141 | ||
162 | if ((skb_is_nonlinear(skb) || skb_cloned(skb)) && | 142 | if (skb_linearize_cow(skb)) |
163 | skb_linearize(skb, GFP_ATOMIC) != 0) { | ||
164 | goto out_ok; | 143 | goto out_ok; |
165 | } | ||
166 | 144 | ||
167 | /* compression */ | 145 | /* compression */ |
168 | plen = skb->len - hdr_len; | 146 | plen = skb->len - hdr_len; |