aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ah6.c
diff options
context:
space:
mode:
authorSteffen Klassert <steffen.klassert@secunet.com>2009-10-07 18:49:01 -0400
committerDavid S. Miller <davem@davemloft.net>2009-10-19 00:31:59 -0400
commit8631e9bdfea189b2e5efe3b03825cc24ebb6cfb7 (patch)
tree14b2c37263e5a528ad7a140171ed3a71b18936df /net/ipv6/ah6.c
parentdff3bb0626279bae04ed10ed61ab726d6b3ef4b4 (diff)
ah6: convert to ahash
This patch converts ah6 to the new ahash interface. Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/ah6.c')
-rw-r--r--net/ipv6/ah6.c352
1 files changed, 272 insertions, 80 deletions
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index c1589e2f1dc9..0f526f8ea518 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -24,18 +24,92 @@
24 * This file is derived from net/ipv4/ah.c. 24 * This file is derived from net/ipv4/ah.c.
25 */ 25 */
26 26
27#include <crypto/hash.h>
27#include <linux/module.h> 28#include <linux/module.h>
28#include <net/ip.h> 29#include <net/ip.h>
29#include <net/ah.h> 30#include <net/ah.h>
30#include <linux/crypto.h> 31#include <linux/crypto.h>
31#include <linux/pfkeyv2.h> 32#include <linux/pfkeyv2.h>
32#include <linux/spinlock.h>
33#include <linux/string.h> 33#include <linux/string.h>
34#include <linux/scatterlist.h>
34#include <net/icmp.h> 35#include <net/icmp.h>
35#include <net/ipv6.h> 36#include <net/ipv6.h>
36#include <net/protocol.h> 37#include <net/protocol.h>
37#include <net/xfrm.h> 38#include <net/xfrm.h>
38 39
40#define IPV6HDR_BASELEN 8
41
42struct tmp_ext {
43#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
44 struct in6_addr saddr;
45#endif
46 struct in6_addr daddr;
47 char hdrs[0];
48};
49
50struct ah_skb_cb {
51 struct xfrm_skb_cb xfrm;
52 void *tmp;
53};
54
55#define AH_SKB_CB(__skb) ((struct ah_skb_cb *)&((__skb)->cb[0]))
56
57static void *ah_alloc_tmp(struct crypto_ahash *ahash, int nfrags,
58 unsigned int size)
59{
60 unsigned int len;
61
62 len = size + crypto_ahash_digestsize(ahash) +
63 (crypto_ahash_alignmask(ahash) &
64 ~(crypto_tfm_ctx_alignment() - 1));
65
66 len = ALIGN(len, crypto_tfm_ctx_alignment());
67
68 len += sizeof(struct ahash_request) + crypto_ahash_reqsize(ahash);
69 len = ALIGN(len, __alignof__(struct scatterlist));
70
71 len += sizeof(struct scatterlist) * nfrags;
72
73 return kmalloc(len, GFP_ATOMIC);
74}
75
76static inline struct tmp_ext *ah_tmp_ext(void *base)
77{
78 return base + IPV6HDR_BASELEN;
79}
80
81static inline u8 *ah_tmp_auth(u8 *tmp, unsigned int offset)
82{
83 return tmp + offset;
84}
85
86static inline u8 *ah_tmp_icv(struct crypto_ahash *ahash, void *tmp,
87 unsigned int offset)
88{
89 return PTR_ALIGN((u8 *)tmp + offset, crypto_ahash_alignmask(ahash) + 1);
90}
91
92static inline struct ahash_request *ah_tmp_req(struct crypto_ahash *ahash,
93 u8 *icv)
94{
95 struct ahash_request *req;
96
97 req = (void *)PTR_ALIGN(icv + crypto_ahash_digestsize(ahash),
98 crypto_tfm_ctx_alignment());
99
100 ahash_request_set_tfm(req, ahash);
101
102 return req;
103}
104
105static inline struct scatterlist *ah_req_sg(struct crypto_ahash *ahash,
106 struct ahash_request *req)
107{
108 return (void *)ALIGN((unsigned long)(req + 1) +
109 crypto_ahash_reqsize(ahash),
110 __alignof__(struct scatterlist));
111}
112
39static int zero_out_mutable_opts(struct ipv6_opt_hdr *opthdr) 113static int zero_out_mutable_opts(struct ipv6_opt_hdr *opthdr)
40{ 114{
41 u8 *opt = (u8 *)opthdr; 115 u8 *opt = (u8 *)opthdr;
@@ -218,24 +292,85 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir)
218 return 0; 292 return 0;
219} 293}
220 294
295static void ah6_output_done(struct crypto_async_request *base, int err)
296{
297 int extlen;
298 u8 *iph_base;
299 u8 *icv;
300 struct sk_buff *skb = base->data;
301 struct xfrm_state *x = skb_dst(skb)->xfrm;
302 struct ah_data *ahp = x->data;
303 struct ipv6hdr *top_iph = ipv6_hdr(skb);
304 struct ip_auth_hdr *ah = ip_auth_hdr(skb);
305 struct tmp_ext *iph_ext;
306
307 extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr);
308 if (extlen)
309 extlen += sizeof(*iph_ext);
310
311 iph_base = AH_SKB_CB(skb)->tmp;
312 iph_ext = ah_tmp_ext(iph_base);
313 icv = ah_tmp_icv(ahp->ahash, iph_ext, extlen);
314
315 memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
316 memcpy(top_iph, iph_base, IPV6HDR_BASELEN);
317
318 if (extlen) {
319#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
320 memcpy(&top_iph->saddr, iph_ext, extlen);
321#else
322 memcpy(&top_iph->daddr, iph_ext, extlen);
323#endif
324 }
325
326 err = ah->nexthdr;
327
328 kfree(AH_SKB_CB(skb)->tmp);
329 xfrm_output_resume(skb, err);
330}
331
221static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) 332static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
222{ 333{
223 int err; 334 int err;
335 int nfrags;
224 int extlen; 336 int extlen;
337 u8 *iph_base;
338 u8 *icv;
339 u8 nexthdr;
340 struct sk_buff *trailer;
341 struct crypto_ahash *ahash;
342 struct ahash_request *req;
343 struct scatterlist *sg;
225 struct ipv6hdr *top_iph; 344 struct ipv6hdr *top_iph;
226 struct ip_auth_hdr *ah; 345 struct ip_auth_hdr *ah;
227 struct ah_data *ahp; 346 struct ah_data *ahp;
228 u8 nexthdr; 347 struct tmp_ext *iph_ext;
229 char tmp_base[8]; 348
230 struct { 349 ahp = x->data;
231#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 350 ahash = ahp->ahash;
232 struct in6_addr saddr; 351
233#endif 352 if ((err = skb_cow_data(skb, 0, &trailer)) < 0)
234 struct in6_addr daddr; 353 goto out;
235 char hdrs[0]; 354 nfrags = err;
236 } *tmp_ext;
237 355
238 skb_push(skb, -skb_network_offset(skb)); 356 skb_push(skb, -skb_network_offset(skb));
357 extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr);
358 if (extlen)
359 extlen += sizeof(*iph_ext);
360
361 err = -ENOMEM;
362 iph_base = ah_alloc_tmp(ahash, nfrags, IPV6HDR_BASELEN + extlen);
363 if (!iph_base)
364 goto out;
365
366 iph_ext = ah_tmp_ext(iph_base);
367 icv = ah_tmp_icv(ahash, iph_ext, extlen);
368 req = ah_tmp_req(ahash, icv);
369 sg = ah_req_sg(ahash, req);
370
371 ah = ip_auth_hdr(skb);
372 memset(ah->auth_data, 0, ahp->icv_trunc_len);
373
239 top_iph = ipv6_hdr(skb); 374 top_iph = ipv6_hdr(skb);
240 top_iph->payload_len = htons(skb->len - sizeof(*top_iph)); 375 top_iph->payload_len = htons(skb->len - sizeof(*top_iph));
241 376
@@ -245,31 +380,22 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
245 /* When there are no extension headers, we only need to save the first 380 /* When there are no extension headers, we only need to save the first
246 * 8 bytes of the base IP header. 381 * 8 bytes of the base IP header.
247 */ 382 */
248 memcpy(tmp_base, top_iph, sizeof(tmp_base)); 383 memcpy(iph_base, top_iph, IPV6HDR_BASELEN);
249 384
250 tmp_ext = NULL;
251 extlen = skb_transport_offset(skb) - sizeof(struct ipv6hdr);
252 if (extlen) { 385 if (extlen) {
253 extlen += sizeof(*tmp_ext);
254 tmp_ext = kmalloc(extlen, GFP_ATOMIC);
255 if (!tmp_ext) {
256 err = -ENOMEM;
257 goto error;
258 }
259#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 386#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
260 memcpy(tmp_ext, &top_iph->saddr, extlen); 387 memcpy(iph_ext, &top_iph->saddr, extlen);
261#else 388#else
262 memcpy(tmp_ext, &top_iph->daddr, extlen); 389 memcpy(iph_ext, &top_iph->daddr, extlen);
263#endif 390#endif
264 err = ipv6_clear_mutable_options(top_iph, 391 err = ipv6_clear_mutable_options(top_iph,
265 extlen - sizeof(*tmp_ext) + 392 extlen - sizeof(*iph_ext) +
266 sizeof(*top_iph), 393 sizeof(*top_iph),
267 XFRM_POLICY_OUT); 394 XFRM_POLICY_OUT);
268 if (err) 395 if (err)
269 goto error_free_iph; 396 goto out_free;
270 } 397 }
271 398
272 ah = ip_auth_hdr(skb);
273 ah->nexthdr = nexthdr; 399 ah->nexthdr = nexthdr;
274 400
275 top_iph->priority = 0; 401 top_iph->priority = 0;
@@ -278,36 +404,80 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
278 top_iph->flow_lbl[2] = 0; 404 top_iph->flow_lbl[2] = 0;
279 top_iph->hop_limit = 0; 405 top_iph->hop_limit = 0;
280 406
281 ahp = x->data;
282 ah->hdrlen = (XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len) >> 2) - 2; 407 ah->hdrlen = (XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len) >> 2) - 2;
283 408
284 ah->reserved = 0; 409 ah->reserved = 0;
285 ah->spi = x->id.spi; 410 ah->spi = x->id.spi;
286 ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output); 411 ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output);
287 412
288 spin_lock_bh(&x->lock); 413 sg_init_table(sg, nfrags);
289 err = ah_mac_digest(ahp, skb, ah->auth_data); 414 skb_to_sgvec(skb, sg, 0, skb->len);
290 memcpy(ah->auth_data, ahp->work_icv, ahp->icv_trunc_len);
291 spin_unlock_bh(&x->lock);
292 415
293 if (err) 416 ahash_request_set_crypt(req, sg, icv, skb->len);
294 goto error_free_iph; 417 ahash_request_set_callback(req, 0, ah6_output_done, skb);
418
419 AH_SKB_CB(skb)->tmp = iph_base;
295 420
296 memcpy(top_iph, tmp_base, sizeof(tmp_base)); 421 err = crypto_ahash_digest(req);
297 if (tmp_ext) { 422 if (err) {
423 if (err == -EINPROGRESS)
424 goto out;
425
426 if (err == -EBUSY)
427 err = NET_XMIT_DROP;
428 goto out_free;
429 }
430
431 memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
432 memcpy(top_iph, iph_base, IPV6HDR_BASELEN);
433
434 if (extlen) {
298#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 435#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
299 memcpy(&top_iph->saddr, tmp_ext, extlen); 436 memcpy(&top_iph->saddr, iph_ext, extlen);
300#else 437#else
301 memcpy(&top_iph->daddr, tmp_ext, extlen); 438 memcpy(&top_iph->daddr, iph_ext, extlen);
302#endif 439#endif
303error_free_iph:
304 kfree(tmp_ext);
305 } 440 }
306 441
307error: 442out_free:
443 kfree(iph_base);
444out:
308 return err; 445 return err;
309} 446}
310 447
448static void ah6_input_done(struct crypto_async_request *base, int err)
449{
450 u8 *auth_data;
451 u8 *icv;
452 u8 *work_iph;
453 struct sk_buff *skb = base->data;
454 struct xfrm_state *x = xfrm_input_state(skb);
455 struct ah_data *ahp = x->data;
456 struct ip_auth_hdr *ah = ip_auth_hdr(skb);
457 int hdr_len = skb_network_header_len(skb);
458 int ah_hlen = (ah->hdrlen + 2) << 2;
459
460 work_iph = AH_SKB_CB(skb)->tmp;
461 auth_data = ah_tmp_auth(work_iph, hdr_len);
462 icv = ah_tmp_icv(ahp->ahash, auth_data, ahp->icv_trunc_len);
463
464 err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG: 0;
465 if (err)
466 goto out;
467
468 skb->network_header += ah_hlen;
469 memcpy(skb_network_header(skb), work_iph, hdr_len);
470 __skb_pull(skb, ah_hlen + hdr_len);
471 skb_set_transport_header(skb, -hdr_len);
472
473 err = ah->nexthdr;
474out:
475 kfree(AH_SKB_CB(skb)->tmp);
476 xfrm_input_resume(skb, err);
477}
478
479
480
311static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) 481static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
312{ 482{
313 /* 483 /*
@@ -325,14 +495,21 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
325 * There is offset of AH before IPv6 header after the process. 495 * There is offset of AH before IPv6 header after the process.
326 */ 496 */
327 497
498 u8 *auth_data;
499 u8 *icv;
500 u8 *work_iph;
501 struct sk_buff *trailer;
502 struct crypto_ahash *ahash;
503 struct ahash_request *req;
504 struct scatterlist *sg;
328 struct ip_auth_hdr *ah; 505 struct ip_auth_hdr *ah;
329 struct ipv6hdr *ip6h; 506 struct ipv6hdr *ip6h;
330 struct ah_data *ahp; 507 struct ah_data *ahp;
331 unsigned char *tmp_hdr = NULL;
332 u16 hdr_len; 508 u16 hdr_len;
333 u16 ah_hlen; 509 u16 ah_hlen;
334 int nexthdr; 510 int nexthdr;
335 int err = -EINVAL; 511 int nfrags;
512 int err = -ENOMEM;
336 513
337 if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr))) 514 if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr)))
338 goto out; 515 goto out;
@@ -345,9 +522,11 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
345 522
346 skb->ip_summed = CHECKSUM_NONE; 523 skb->ip_summed = CHECKSUM_NONE;
347 524
348 hdr_len = skb->data - skb_network_header(skb); 525 hdr_len = skb_network_header_len(skb);
349 ah = (struct ip_auth_hdr *)skb->data; 526 ah = (struct ip_auth_hdr *)skb->data;
350 ahp = x->data; 527 ahp = x->data;
528 ahash = ahp->ahash;
529
351 nexthdr = ah->nexthdr; 530 nexthdr = ah->nexthdr;
352 ah_hlen = (ah->hdrlen + 2) << 2; 531 ah_hlen = (ah->hdrlen + 2) << 2;
353 532
@@ -358,48 +537,67 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
358 if (!pskb_may_pull(skb, ah_hlen)) 537 if (!pskb_may_pull(skb, ah_hlen))
359 goto out; 538 goto out;
360 539
361 tmp_hdr = kmemdup(skb_network_header(skb), hdr_len, GFP_ATOMIC);
362 if (!tmp_hdr)
363 goto out;
364 ip6h = ipv6_hdr(skb); 540 ip6h = ipv6_hdr(skb);
541
542 skb_push(skb, hdr_len);
543
544 if ((err = skb_cow_data(skb, 0, &trailer)) < 0)
545 goto out;
546 nfrags = err;
547
548 work_iph = ah_alloc_tmp(ahash, nfrags, hdr_len + ahp->icv_trunc_len);
549 if (!work_iph)
550 goto out;
551
552 auth_data = ah_tmp_auth(work_iph, hdr_len);
553 icv = ah_tmp_icv(ahash, auth_data, ahp->icv_trunc_len);
554 req = ah_tmp_req(ahash, icv);
555 sg = ah_req_sg(ahash, req);
556
557 memcpy(work_iph, ip6h, hdr_len);
558 memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
559 memset(ah->auth_data, 0, ahp->icv_trunc_len);
560
365 if (ipv6_clear_mutable_options(ip6h, hdr_len, XFRM_POLICY_IN)) 561 if (ipv6_clear_mutable_options(ip6h, hdr_len, XFRM_POLICY_IN))
366 goto free_out; 562 goto out_free;
563
367 ip6h->priority = 0; 564 ip6h->priority = 0;
368 ip6h->flow_lbl[0] = 0; 565 ip6h->flow_lbl[0] = 0;
369 ip6h->flow_lbl[1] = 0; 566 ip6h->flow_lbl[1] = 0;
370 ip6h->flow_lbl[2] = 0; 567 ip6h->flow_lbl[2] = 0;
371 ip6h->hop_limit = 0; 568 ip6h->hop_limit = 0;
372 569
373 spin_lock(&x->lock); 570 sg_init_table(sg, nfrags);
374 { 571 skb_to_sgvec(skb, sg, 0, skb->len);
375 u8 auth_data[MAX_AH_AUTH_LEN];
376 572
377 memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); 573 ahash_request_set_crypt(req, sg, icv, skb->len);
378 memset(ah->auth_data, 0, ahp->icv_trunc_len); 574 ahash_request_set_callback(req, 0, ah6_input_done, skb);
379 skb_push(skb, hdr_len); 575
380 err = ah_mac_digest(ahp, skb, ah->auth_data); 576 AH_SKB_CB(skb)->tmp = work_iph;
381 if (err) 577
382 goto unlock; 578 err = crypto_ahash_digest(req);
383 if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) 579 if (err) {
384 err = -EBADMSG; 580 if (err == -EINPROGRESS)
581 goto out;
582
583 if (err == -EBUSY)
584 err = NET_XMIT_DROP;
585 goto out_free;
385 } 586 }
386unlock:
387 spin_unlock(&x->lock);
388 587
588 err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG: 0;
389 if (err) 589 if (err)
390 goto free_out; 590 goto out_free;
391 591
392 skb->network_header += ah_hlen; 592 skb->network_header += ah_hlen;
393 memcpy(skb_network_header(skb), tmp_hdr, hdr_len); 593 memcpy(skb_network_header(skb), work_iph, hdr_len);
394 skb->transport_header = skb->network_header; 594 skb->transport_header = skb->network_header;
395 __skb_pull(skb, ah_hlen + hdr_len); 595 __skb_pull(skb, ah_hlen + hdr_len);
396 596
397 kfree(tmp_hdr); 597 err = nexthdr;
398 598
399 return nexthdr; 599out_free:
400 600 kfree(work_iph);
401free_out:
402 kfree(tmp_hdr);
403out: 601out:
404 return err; 602 return err;
405} 603}
@@ -430,7 +628,7 @@ static int ah6_init_state(struct xfrm_state *x)
430{ 628{
431 struct ah_data *ahp = NULL; 629 struct ah_data *ahp = NULL;
432 struct xfrm_algo_desc *aalg_desc; 630 struct xfrm_algo_desc *aalg_desc;
433 struct crypto_hash *tfm; 631 struct crypto_ahash *ahash;
434 632
435 if (!x->aalg) 633 if (!x->aalg)
436 goto error; 634 goto error;
@@ -442,12 +640,12 @@ static int ah6_init_state(struct xfrm_state *x)
442 if (ahp == NULL) 640 if (ahp == NULL)
443 return -ENOMEM; 641 return -ENOMEM;
444 642
445 tfm = crypto_alloc_hash(x->aalg->alg_name, 0, CRYPTO_ALG_ASYNC); 643 ahash = crypto_alloc_ahash(x->aalg->alg_name, 0, 0);
446 if (IS_ERR(tfm)) 644 if (IS_ERR(ahash))
447 goto error; 645 goto error;
448 646
449 ahp->tfm = tfm; 647 ahp->ahash = ahash;
450 if (crypto_hash_setkey(tfm, x->aalg->alg_key, 648 if (crypto_ahash_setkey(ahash, x->aalg->alg_key,
451 (x->aalg->alg_key_len + 7) / 8)) 649 (x->aalg->alg_key_len + 7) / 8))
452 goto error; 650 goto error;
453 651
@@ -461,9 +659,9 @@ static int ah6_init_state(struct xfrm_state *x)
461 BUG_ON(!aalg_desc); 659 BUG_ON(!aalg_desc);
462 660
463 if (aalg_desc->uinfo.auth.icv_fullbits/8 != 661 if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
464 crypto_hash_digestsize(tfm)) { 662 crypto_ahash_digestsize(ahash)) {
465 printk(KERN_INFO "AH: %s digestsize %u != %hu\n", 663 printk(KERN_INFO "AH: %s digestsize %u != %hu\n",
466 x->aalg->alg_name, crypto_hash_digestsize(tfm), 664 x->aalg->alg_name, crypto_ahash_digestsize(ahash),
467 aalg_desc->uinfo.auth.icv_fullbits/8); 665 aalg_desc->uinfo.auth.icv_fullbits/8);
468 goto error; 666 goto error;
469 } 667 }
@@ -473,10 +671,6 @@ static int ah6_init_state(struct xfrm_state *x)
473 671
474 BUG_ON(ahp->icv_trunc_len > MAX_AH_AUTH_LEN); 672 BUG_ON(ahp->icv_trunc_len > MAX_AH_AUTH_LEN);
475 673
476 ahp->work_icv = kmalloc(ahp->icv_full_len, GFP_KERNEL);
477 if (!ahp->work_icv)
478 goto error;
479
480 x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + 674 x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) +
481 ahp->icv_trunc_len); 675 ahp->icv_trunc_len);
482 switch (x->props.mode) { 676 switch (x->props.mode) {
@@ -495,8 +689,7 @@ static int ah6_init_state(struct xfrm_state *x)
495 689
496error: 690error:
497 if (ahp) { 691 if (ahp) {
498 kfree(ahp->work_icv); 692 crypto_free_ahash(ahp->ahash);
499 crypto_free_hash(ahp->tfm);
500 kfree(ahp); 693 kfree(ahp);
501 } 694 }
502 return -EINVAL; 695 return -EINVAL;
@@ -509,8 +702,7 @@ static void ah6_destroy(struct xfrm_state *x)
509 if (!ahp) 702 if (!ahp)
510 return; 703 return;
511 704
512 kfree(ahp->work_icv); 705 crypto_free_ahash(ahp->ahash);
513 crypto_free_hash(ahp->tfm);
514 kfree(ahp); 706 kfree(ahp);
515} 707}
516 708