diff options
Diffstat (limited to 'net/ipv6/ah6.c')
-rw-r--r-- | net/ipv6/ah6.c | 354 |
1 files changed, 273 insertions, 81 deletions
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index c1589e2f1dc9..c2f300c314be 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 | |||
42 | struct 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 | |||
50 | struct 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 | |||
57 | static 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 | |||
76 | static inline struct tmp_ext *ah_tmp_ext(void *base) | ||
77 | { | ||
78 | return base + IPV6HDR_BASELEN; | ||
79 | } | ||
80 | |||
81 | static inline u8 *ah_tmp_auth(u8 *tmp, unsigned int offset) | ||
82 | { | ||
83 | return tmp + offset; | ||
84 | } | ||
85 | |||
86 | static 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 | |||
92 | static 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 | |||
105 | static 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 | |||
39 | static int zero_out_mutable_opts(struct ipv6_opt_hdr *opthdr) | 113 | static 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 | ||
295 | static 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 | |||
221 | static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) | 332 | static 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 |
303 | error_free_iph: | ||
304 | kfree(tmp_ext); | ||
305 | } | 440 | } |
306 | 441 | ||
307 | error: | 442 | out_free: |
443 | kfree(iph_base); | ||
444 | out: | ||
308 | return err; | 445 | return err; |
309 | } | 446 | } |
310 | 447 | ||
448 | static 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; | ||
474 | out: | ||
475 | kfree(AH_SKB_CB(skb)->tmp); | ||
476 | xfrm_input_resume(skb, err); | ||
477 | } | ||
478 | |||
479 | |||
480 | |||
311 | static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) | 481 | static 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 | } |
386 | unlock: | ||
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; | 599 | out_free: |
400 | 600 | kfree(work_iph); | |
401 | free_out: | ||
402 | kfree(tmp_hdr); | ||
403 | out: | 601 | out: |
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,22 +659,18 @@ 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 | } |
470 | 668 | ||
471 | ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; | 669 | ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; |
472 | ahp->icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8; | 670 | ahp->icv_trunc_len = x->aalg->alg_trunc_len/8; |
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 | ||
496 | error: | 690 | error: |
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 | ||