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