diff options
Diffstat (limited to 'net/ipv4/ah4.c')
-rw-r--r-- | net/ipv4/ah4.c | 300 |
1 files changed, 239 insertions, 61 deletions
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index 5c662703eb1e..880a5ec6dce0 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c | |||
@@ -1,14 +1,73 @@ | |||
1 | #include <crypto/hash.h> | ||
1 | #include <linux/err.h> | 2 | #include <linux/err.h> |
2 | #include <linux/module.h> | 3 | #include <linux/module.h> |
4 | #include <linux/slab.h> | ||
3 | #include <net/ip.h> | 5 | #include <net/ip.h> |
4 | #include <net/xfrm.h> | 6 | #include <net/xfrm.h> |
5 | #include <net/ah.h> | 7 | #include <net/ah.h> |
6 | #include <linux/crypto.h> | 8 | #include <linux/crypto.h> |
7 | #include <linux/pfkeyv2.h> | 9 | #include <linux/pfkeyv2.h> |
8 | #include <linux/spinlock.h> | 10 | #include <linux/scatterlist.h> |
9 | #include <net/icmp.h> | 11 | #include <net/icmp.h> |
10 | #include <net/protocol.h> | 12 | #include <net/protocol.h> |
11 | 13 | ||
14 | struct ah_skb_cb { | ||
15 | struct xfrm_skb_cb xfrm; | ||
16 | void *tmp; | ||
17 | }; | ||
18 | |||
19 | #define AH_SKB_CB(__skb) ((struct ah_skb_cb *)&((__skb)->cb[0])) | ||
20 | |||
21 | static void *ah_alloc_tmp(struct crypto_ahash *ahash, int nfrags, | ||
22 | unsigned int size) | ||
23 | { | ||
24 | unsigned int len; | ||
25 | |||
26 | len = size + crypto_ahash_digestsize(ahash) + | ||
27 | (crypto_ahash_alignmask(ahash) & | ||
28 | ~(crypto_tfm_ctx_alignment() - 1)); | ||
29 | |||
30 | len = ALIGN(len, crypto_tfm_ctx_alignment()); | ||
31 | |||
32 | len += sizeof(struct ahash_request) + crypto_ahash_reqsize(ahash); | ||
33 | len = ALIGN(len, __alignof__(struct scatterlist)); | ||
34 | |||
35 | len += sizeof(struct scatterlist) * nfrags; | ||
36 | |||
37 | return kmalloc(len, GFP_ATOMIC); | ||
38 | } | ||
39 | |||
40 | static inline u8 *ah_tmp_auth(void *tmp, unsigned int offset) | ||
41 | { | ||
42 | return tmp + offset; | ||
43 | } | ||
44 | |||
45 | static inline u8 *ah_tmp_icv(struct crypto_ahash *ahash, void *tmp, | ||
46 | unsigned int offset) | ||
47 | { | ||
48 | return PTR_ALIGN((u8 *)tmp + offset, crypto_ahash_alignmask(ahash) + 1); | ||
49 | } | ||
50 | |||
51 | static inline struct ahash_request *ah_tmp_req(struct crypto_ahash *ahash, | ||
52 | u8 *icv) | ||
53 | { | ||
54 | struct ahash_request *req; | ||
55 | |||
56 | req = (void *)PTR_ALIGN(icv + crypto_ahash_digestsize(ahash), | ||
57 | crypto_tfm_ctx_alignment()); | ||
58 | |||
59 | ahash_request_set_tfm(req, ahash); | ||
60 | |||
61 | return req; | ||
62 | } | ||
63 | |||
64 | static inline struct scatterlist *ah_req_sg(struct crypto_ahash *ahash, | ||
65 | struct ahash_request *req) | ||
66 | { | ||
67 | return (void *)ALIGN((unsigned long)(req + 1) + | ||
68 | crypto_ahash_reqsize(ahash), | ||
69 | __alignof__(struct scatterlist)); | ||
70 | } | ||
12 | 71 | ||
13 | /* Clear mutable options and find final destination to substitute | 72 | /* Clear mutable options and find final destination to substitute |
14 | * into IP header for icv calculation. Options are already checked | 73 | * into IP header for icv calculation. Options are already checked |
@@ -54,20 +113,72 @@ static int ip_clear_mutable_options(struct iphdr *iph, __be32 *daddr) | |||
54 | return 0; | 113 | return 0; |
55 | } | 114 | } |
56 | 115 | ||
116 | static void ah_output_done(struct crypto_async_request *base, int err) | ||
117 | { | ||
118 | u8 *icv; | ||
119 | struct iphdr *iph; | ||
120 | struct sk_buff *skb = base->data; | ||
121 | struct xfrm_state *x = skb_dst(skb)->xfrm; | ||
122 | struct ah_data *ahp = x->data; | ||
123 | struct iphdr *top_iph = ip_hdr(skb); | ||
124 | struct ip_auth_hdr *ah = ip_auth_hdr(skb); | ||
125 | int ihl = ip_hdrlen(skb); | ||
126 | |||
127 | iph = AH_SKB_CB(skb)->tmp; | ||
128 | icv = ah_tmp_icv(ahp->ahash, iph, ihl); | ||
129 | memcpy(ah->auth_data, icv, ahp->icv_trunc_len); | ||
130 | |||
131 | top_iph->tos = iph->tos; | ||
132 | top_iph->ttl = iph->ttl; | ||
133 | top_iph->frag_off = iph->frag_off; | ||
134 | if (top_iph->ihl != 5) { | ||
135 | top_iph->daddr = iph->daddr; | ||
136 | memcpy(top_iph+1, iph+1, top_iph->ihl*4 - sizeof(struct iphdr)); | ||
137 | } | ||
138 | |||
139 | err = ah->nexthdr; | ||
140 | |||
141 | kfree(AH_SKB_CB(skb)->tmp); | ||
142 | xfrm_output_resume(skb, err); | ||
143 | } | ||
144 | |||
57 | static int ah_output(struct xfrm_state *x, struct sk_buff *skb) | 145 | static int ah_output(struct xfrm_state *x, struct sk_buff *skb) |
58 | { | 146 | { |
59 | int err; | 147 | int err; |
148 | int nfrags; | ||
149 | int ihl; | ||
150 | u8 *icv; | ||
151 | struct sk_buff *trailer; | ||
152 | struct crypto_ahash *ahash; | ||
153 | struct ahash_request *req; | ||
154 | struct scatterlist *sg; | ||
60 | struct iphdr *iph, *top_iph; | 155 | struct iphdr *iph, *top_iph; |
61 | struct ip_auth_hdr *ah; | 156 | struct ip_auth_hdr *ah; |
62 | struct ah_data *ahp; | 157 | struct ah_data *ahp; |
63 | union { | 158 | |
64 | struct iphdr iph; | 159 | ahp = x->data; |
65 | char buf[60]; | 160 | ahash = ahp->ahash; |
66 | } tmp_iph; | 161 | |
162 | if ((err = skb_cow_data(skb, 0, &trailer)) < 0) | ||
163 | goto out; | ||
164 | nfrags = err; | ||
67 | 165 | ||
68 | skb_push(skb, -skb_network_offset(skb)); | 166 | skb_push(skb, -skb_network_offset(skb)); |
167 | ah = ip_auth_hdr(skb); | ||
168 | ihl = ip_hdrlen(skb); | ||
169 | |||
170 | err = -ENOMEM; | ||
171 | iph = ah_alloc_tmp(ahash, nfrags, ihl); | ||
172 | if (!iph) | ||
173 | goto out; | ||
174 | |||
175 | icv = ah_tmp_icv(ahash, iph, ihl); | ||
176 | req = ah_tmp_req(ahash, icv); | ||
177 | sg = ah_req_sg(ahash, req); | ||
178 | |||
179 | memset(ah->auth_data, 0, ahp->icv_trunc_len); | ||
180 | |||
69 | top_iph = ip_hdr(skb); | 181 | top_iph = ip_hdr(skb); |
70 | iph = &tmp_iph.iph; | ||
71 | 182 | ||
72 | iph->tos = top_iph->tos; | 183 | iph->tos = top_iph->tos; |
73 | iph->ttl = top_iph->ttl; | 184 | iph->ttl = top_iph->ttl; |
@@ -78,10 +189,9 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb) | |||
78 | memcpy(iph+1, top_iph+1, top_iph->ihl*4 - sizeof(struct iphdr)); | 189 | memcpy(iph+1, top_iph+1, top_iph->ihl*4 - sizeof(struct iphdr)); |
79 | err = ip_clear_mutable_options(top_iph, &top_iph->daddr); | 190 | err = ip_clear_mutable_options(top_iph, &top_iph->daddr); |
80 | if (err) | 191 | if (err) |
81 | goto error; | 192 | goto out_free; |
82 | } | 193 | } |
83 | 194 | ||
84 | ah = ip_auth_hdr(skb); | ||
85 | ah->nexthdr = *skb_mac_header(skb); | 195 | ah->nexthdr = *skb_mac_header(skb); |
86 | *skb_mac_header(skb) = IPPROTO_AH; | 196 | *skb_mac_header(skb) = IPPROTO_AH; |
87 | 197 | ||
@@ -91,20 +201,31 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb) | |||
91 | top_iph->ttl = 0; | 201 | top_iph->ttl = 0; |
92 | top_iph->check = 0; | 202 | top_iph->check = 0; |
93 | 203 | ||
94 | ahp = x->data; | ||
95 | ah->hdrlen = (XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len) >> 2) - 2; | 204 | ah->hdrlen = (XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len) >> 2) - 2; |
96 | 205 | ||
97 | ah->reserved = 0; | 206 | ah->reserved = 0; |
98 | ah->spi = x->id.spi; | 207 | ah->spi = x->id.spi; |
99 | ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output); | 208 | ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output); |
100 | 209 | ||
101 | spin_lock_bh(&x->lock); | 210 | sg_init_table(sg, nfrags); |
102 | err = ah_mac_digest(ahp, skb, ah->auth_data); | 211 | skb_to_sgvec(skb, sg, 0, skb->len); |
103 | memcpy(ah->auth_data, ahp->work_icv, ahp->icv_trunc_len); | ||
104 | spin_unlock_bh(&x->lock); | ||
105 | 212 | ||
106 | if (err) | 213 | ahash_request_set_crypt(req, sg, icv, skb->len); |
107 | goto error; | 214 | ahash_request_set_callback(req, 0, ah_output_done, skb); |
215 | |||
216 | AH_SKB_CB(skb)->tmp = iph; | ||
217 | |||
218 | err = crypto_ahash_digest(req); | ||
219 | if (err) { | ||
220 | if (err == -EINPROGRESS) | ||
221 | goto out; | ||
222 | |||
223 | if (err == -EBUSY) | ||
224 | err = NET_XMIT_DROP; | ||
225 | goto out_free; | ||
226 | } | ||
227 | |||
228 | memcpy(ah->auth_data, icv, ahp->icv_trunc_len); | ||
108 | 229 | ||
109 | top_iph->tos = iph->tos; | 230 | top_iph->tos = iph->tos; |
110 | top_iph->ttl = iph->ttl; | 231 | top_iph->ttl = iph->ttl; |
@@ -114,28 +235,67 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb) | |||
114 | memcpy(top_iph+1, iph+1, top_iph->ihl*4 - sizeof(struct iphdr)); | 235 | memcpy(top_iph+1, iph+1, top_iph->ihl*4 - sizeof(struct iphdr)); |
115 | } | 236 | } |
116 | 237 | ||
117 | err = 0; | 238 | out_free: |
118 | 239 | kfree(iph); | |
119 | error: | 240 | out: |
120 | return err; | 241 | return err; |
121 | } | 242 | } |
122 | 243 | ||
244 | static void ah_input_done(struct crypto_async_request *base, int err) | ||
245 | { | ||
246 | u8 *auth_data; | ||
247 | u8 *icv; | ||
248 | struct iphdr *work_iph; | ||
249 | struct sk_buff *skb = base->data; | ||
250 | struct xfrm_state *x = xfrm_input_state(skb); | ||
251 | struct ah_data *ahp = x->data; | ||
252 | struct ip_auth_hdr *ah = ip_auth_hdr(skb); | ||
253 | int ihl = ip_hdrlen(skb); | ||
254 | int ah_hlen = (ah->hdrlen + 2) << 2; | ||
255 | |||
256 | work_iph = AH_SKB_CB(skb)->tmp; | ||
257 | auth_data = ah_tmp_auth(work_iph, ihl); | ||
258 | icv = ah_tmp_icv(ahp->ahash, auth_data, ahp->icv_trunc_len); | ||
259 | |||
260 | err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG: 0; | ||
261 | if (err) | ||
262 | goto out; | ||
263 | |||
264 | skb->network_header += ah_hlen; | ||
265 | memcpy(skb_network_header(skb), work_iph, ihl); | ||
266 | __skb_pull(skb, ah_hlen + ihl); | ||
267 | skb_set_transport_header(skb, -ihl); | ||
268 | |||
269 | err = ah->nexthdr; | ||
270 | out: | ||
271 | kfree(AH_SKB_CB(skb)->tmp); | ||
272 | xfrm_input_resume(skb, err); | ||
273 | } | ||
274 | |||
123 | static int ah_input(struct xfrm_state *x, struct sk_buff *skb) | 275 | static int ah_input(struct xfrm_state *x, struct sk_buff *skb) |
124 | { | 276 | { |
125 | int ah_hlen; | 277 | int ah_hlen; |
126 | int ihl; | 278 | int ihl; |
127 | int nexthdr; | 279 | int nexthdr; |
128 | int err = -EINVAL; | 280 | int nfrags; |
129 | struct iphdr *iph; | 281 | u8 *auth_data; |
282 | u8 *icv; | ||
283 | struct sk_buff *trailer; | ||
284 | struct crypto_ahash *ahash; | ||
285 | struct ahash_request *req; | ||
286 | struct scatterlist *sg; | ||
287 | struct iphdr *iph, *work_iph; | ||
130 | struct ip_auth_hdr *ah; | 288 | struct ip_auth_hdr *ah; |
131 | struct ah_data *ahp; | 289 | struct ah_data *ahp; |
132 | char work_buf[60]; | 290 | int err = -ENOMEM; |
133 | 291 | ||
134 | if (!pskb_may_pull(skb, sizeof(*ah))) | 292 | if (!pskb_may_pull(skb, sizeof(*ah))) |
135 | goto out; | 293 | goto out; |
136 | 294 | ||
137 | ah = (struct ip_auth_hdr *)skb->data; | 295 | ah = (struct ip_auth_hdr *)skb->data; |
138 | ahp = x->data; | 296 | ahp = x->data; |
297 | ahash = ahp->ahash; | ||
298 | |||
139 | nexthdr = ah->nexthdr; | 299 | nexthdr = ah->nexthdr; |
140 | ah_hlen = (ah->hdrlen + 2) << 2; | 300 | ah_hlen = (ah->hdrlen + 2) << 2; |
141 | 301 | ||
@@ -156,9 +316,24 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb) | |||
156 | 316 | ||
157 | ah = (struct ip_auth_hdr *)skb->data; | 317 | ah = (struct ip_auth_hdr *)skb->data; |
158 | iph = ip_hdr(skb); | 318 | iph = ip_hdr(skb); |
319 | ihl = ip_hdrlen(skb); | ||
320 | |||
321 | if ((err = skb_cow_data(skb, 0, &trailer)) < 0) | ||
322 | goto out; | ||
323 | nfrags = err; | ||
324 | |||
325 | work_iph = ah_alloc_tmp(ahash, nfrags, ihl + ahp->icv_trunc_len); | ||
326 | if (!work_iph) | ||
327 | goto out; | ||
328 | |||
329 | auth_data = ah_tmp_auth(work_iph, ihl); | ||
330 | icv = ah_tmp_icv(ahash, auth_data, ahp->icv_trunc_len); | ||
331 | req = ah_tmp_req(ahash, icv); | ||
332 | sg = ah_req_sg(ahash, req); | ||
159 | 333 | ||
160 | ihl = skb->data - skb_network_header(skb); | 334 | memcpy(work_iph, iph, ihl); |
161 | memcpy(work_buf, iph, ihl); | 335 | memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); |
336 | memset(ah->auth_data, 0, ahp->icv_trunc_len); | ||
162 | 337 | ||
163 | iph->ttl = 0; | 338 | iph->ttl = 0; |
164 | iph->tos = 0; | 339 | iph->tos = 0; |
@@ -166,35 +341,44 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb) | |||
166 | iph->check = 0; | 341 | iph->check = 0; |
167 | if (ihl > sizeof(*iph)) { | 342 | if (ihl > sizeof(*iph)) { |
168 | __be32 dummy; | 343 | __be32 dummy; |
169 | if (ip_clear_mutable_options(iph, &dummy)) | 344 | err = ip_clear_mutable_options(iph, &dummy); |
170 | goto out; | 345 | if (err) |
346 | goto out_free; | ||
171 | } | 347 | } |
172 | 348 | ||
173 | spin_lock(&x->lock); | 349 | skb_push(skb, ihl); |
174 | { | ||
175 | u8 auth_data[MAX_AH_AUTH_LEN]; | ||
176 | 350 | ||
177 | memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); | 351 | sg_init_table(sg, nfrags); |
178 | skb_push(skb, ihl); | 352 | skb_to_sgvec(skb, sg, 0, skb->len); |
179 | err = ah_mac_digest(ahp, skb, ah->auth_data); | 353 | |
180 | if (err) | 354 | ahash_request_set_crypt(req, sg, icv, skb->len); |
181 | goto unlock; | 355 | ahash_request_set_callback(req, 0, ah_input_done, skb); |
182 | if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) | 356 | |
183 | err = -EBADMSG; | 357 | AH_SKB_CB(skb)->tmp = work_iph; |
358 | |||
359 | err = crypto_ahash_digest(req); | ||
360 | if (err) { | ||
361 | if (err == -EINPROGRESS) | ||
362 | goto out; | ||
363 | |||
364 | if (err == -EBUSY) | ||
365 | err = NET_XMIT_DROP; | ||
366 | goto out_free; | ||
184 | } | 367 | } |
185 | unlock: | ||
186 | spin_unlock(&x->lock); | ||
187 | 368 | ||
369 | err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG: 0; | ||
188 | if (err) | 370 | if (err) |
189 | goto out; | 371 | goto out_free; |
190 | 372 | ||
191 | skb->network_header += ah_hlen; | 373 | skb->network_header += ah_hlen; |
192 | memcpy(skb_network_header(skb), work_buf, ihl); | 374 | memcpy(skb_network_header(skb), work_iph, ihl); |
193 | skb->transport_header = skb->network_header; | ||
194 | __skb_pull(skb, ah_hlen + ihl); | 375 | __skb_pull(skb, ah_hlen + ihl); |
376 | skb_set_transport_header(skb, -ihl); | ||
195 | 377 | ||
196 | return nexthdr; | 378 | err = nexthdr; |
197 | 379 | ||
380 | out_free: | ||
381 | kfree (work_iph); | ||
198 | out: | 382 | out: |
199 | return err; | 383 | return err; |
200 | } | 384 | } |
@@ -210,7 +394,7 @@ static void ah4_err(struct sk_buff *skb, u32 info) | |||
210 | icmp_hdr(skb)->code != ICMP_FRAG_NEEDED) | 394 | icmp_hdr(skb)->code != ICMP_FRAG_NEEDED) |
211 | return; | 395 | return; |
212 | 396 | ||
213 | x = xfrm_state_lookup(net, (xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET); | 397 | x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET); |
214 | if (!x) | 398 | if (!x) |
215 | return; | 399 | return; |
216 | printk(KERN_DEBUG "pmtu discovery on SA AH/%08x/%08x\n", | 400 | printk(KERN_DEBUG "pmtu discovery on SA AH/%08x/%08x\n", |
@@ -222,7 +406,7 @@ static int ah_init_state(struct xfrm_state *x) | |||
222 | { | 406 | { |
223 | struct ah_data *ahp = NULL; | 407 | struct ah_data *ahp = NULL; |
224 | struct xfrm_algo_desc *aalg_desc; | 408 | struct xfrm_algo_desc *aalg_desc; |
225 | struct crypto_hash *tfm; | 409 | struct crypto_ahash *ahash; |
226 | 410 | ||
227 | if (!x->aalg) | 411 | if (!x->aalg) |
228 | goto error; | 412 | goto error; |
@@ -231,44 +415,40 @@ static int ah_init_state(struct xfrm_state *x) | |||
231 | goto error; | 415 | goto error; |
232 | 416 | ||
233 | ahp = kzalloc(sizeof(*ahp), GFP_KERNEL); | 417 | ahp = kzalloc(sizeof(*ahp), GFP_KERNEL); |
234 | if (ahp == NULL) | 418 | if (!ahp) |
235 | return -ENOMEM; | 419 | return -ENOMEM; |
236 | 420 | ||
237 | tfm = crypto_alloc_hash(x->aalg->alg_name, 0, CRYPTO_ALG_ASYNC); | 421 | ahash = crypto_alloc_ahash(x->aalg->alg_name, 0, 0); |
238 | if (IS_ERR(tfm)) | 422 | if (IS_ERR(ahash)) |
239 | goto error; | 423 | goto error; |
240 | 424 | ||
241 | ahp->tfm = tfm; | 425 | ahp->ahash = ahash; |
242 | if (crypto_hash_setkey(tfm, x->aalg->alg_key, | 426 | if (crypto_ahash_setkey(ahash, x->aalg->alg_key, |
243 | (x->aalg->alg_key_len + 7) / 8)) | 427 | (x->aalg->alg_key_len + 7) / 8)) |
244 | goto error; | 428 | goto error; |
245 | 429 | ||
246 | /* | 430 | /* |
247 | * Lookup the algorithm description maintained by xfrm_algo, | 431 | * Lookup the algorithm description maintained by xfrm_algo, |
248 | * verify crypto transform properties, and store information | 432 | * verify crypto transform properties, and store information |
249 | * we need for AH processing. This lookup cannot fail here | 433 | * we need for AH processing. This lookup cannot fail here |
250 | * after a successful crypto_alloc_hash(). | 434 | * after a successful crypto_alloc_ahash(). |
251 | */ | 435 | */ |
252 | aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0); | 436 | aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0); |
253 | BUG_ON(!aalg_desc); | 437 | BUG_ON(!aalg_desc); |
254 | 438 | ||
255 | if (aalg_desc->uinfo.auth.icv_fullbits/8 != | 439 | if (aalg_desc->uinfo.auth.icv_fullbits/8 != |
256 | crypto_hash_digestsize(tfm)) { | 440 | crypto_ahash_digestsize(ahash)) { |
257 | printk(KERN_INFO "AH: %s digestsize %u != %hu\n", | 441 | printk(KERN_INFO "AH: %s digestsize %u != %hu\n", |
258 | x->aalg->alg_name, crypto_hash_digestsize(tfm), | 442 | x->aalg->alg_name, crypto_ahash_digestsize(ahash), |
259 | aalg_desc->uinfo.auth.icv_fullbits/8); | 443 | aalg_desc->uinfo.auth.icv_fullbits/8); |
260 | goto error; | 444 | goto error; |
261 | } | 445 | } |
262 | 446 | ||
263 | ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; | 447 | ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; |
264 | ahp->icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8; | 448 | ahp->icv_trunc_len = x->aalg->alg_trunc_len/8; |
265 | 449 | ||
266 | BUG_ON(ahp->icv_trunc_len > MAX_AH_AUTH_LEN); | 450 | BUG_ON(ahp->icv_trunc_len > MAX_AH_AUTH_LEN); |
267 | 451 | ||
268 | ahp->work_icv = kmalloc(ahp->icv_full_len, GFP_KERNEL); | ||
269 | if (!ahp->work_icv) | ||
270 | goto error; | ||
271 | |||
272 | x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + | 452 | x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + |
273 | ahp->icv_trunc_len); | 453 | ahp->icv_trunc_len); |
274 | if (x->props.mode == XFRM_MODE_TUNNEL) | 454 | if (x->props.mode == XFRM_MODE_TUNNEL) |
@@ -279,8 +459,7 @@ static int ah_init_state(struct xfrm_state *x) | |||
279 | 459 | ||
280 | error: | 460 | error: |
281 | if (ahp) { | 461 | if (ahp) { |
282 | kfree(ahp->work_icv); | 462 | crypto_free_ahash(ahp->ahash); |
283 | crypto_free_hash(ahp->tfm); | ||
284 | kfree(ahp); | 463 | kfree(ahp); |
285 | } | 464 | } |
286 | return -EINVAL; | 465 | return -EINVAL; |
@@ -293,8 +472,7 @@ static void ah_destroy(struct xfrm_state *x) | |||
293 | if (!ahp) | 472 | if (!ahp) |
294 | return; | 473 | return; |
295 | 474 | ||
296 | kfree(ahp->work_icv); | 475 | crypto_free_ahash(ahp->ahash); |
297 | crypto_free_hash(ahp->tfm); | ||
298 | kfree(ahp); | 476 | kfree(ahp); |
299 | } | 477 | } |
300 | 478 | ||