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