diff options
Diffstat (limited to 'net/ipv6/esp6.c')
-rw-r--r-- | net/ipv6/esp6.c | 148 |
1 files changed, 116 insertions, 32 deletions
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index ee9b93bdd6a2..1ac7938dd9ec 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c | |||
@@ -49,19 +49,25 @@ struct esp_skb_cb { | |||
49 | 49 | ||
50 | #define ESP_SKB_CB(__skb) ((struct esp_skb_cb *)&((__skb)->cb[0])) | 50 | #define ESP_SKB_CB(__skb) ((struct esp_skb_cb *)&((__skb)->cb[0])) |
51 | 51 | ||
52 | static u32 esp6_get_mtu(struct xfrm_state *x, int mtu); | ||
53 | |||
52 | /* | 54 | /* |
53 | * Allocate an AEAD request structure with extra space for SG and IV. | 55 | * Allocate an AEAD request structure with extra space for SG and IV. |
54 | * | 56 | * |
55 | * For alignment considerations the IV is placed at the front, followed | 57 | * For alignment considerations the upper 32 bits of the sequence number are |
56 | * by the request and finally the SG list. | 58 | * placed at the front, if present. Followed by the IV, the request and finally |
59 | * the SG list. | ||
57 | * | 60 | * |
58 | * TODO: Use spare space in skb for this where possible. | 61 | * TODO: Use spare space in skb for this where possible. |
59 | */ | 62 | */ |
60 | static void *esp_alloc_tmp(struct crypto_aead *aead, int nfrags) | 63 | static void *esp_alloc_tmp(struct crypto_aead *aead, int nfrags, int seqihlen) |
61 | { | 64 | { |
62 | unsigned int len; | 65 | unsigned int len; |
63 | 66 | ||
64 | len = crypto_aead_ivsize(aead); | 67 | len = seqihlen; |
68 | |||
69 | len += crypto_aead_ivsize(aead); | ||
70 | |||
65 | if (len) { | 71 | if (len) { |
66 | len += crypto_aead_alignmask(aead) & | 72 | len += crypto_aead_alignmask(aead) & |
67 | ~(crypto_tfm_ctx_alignment() - 1); | 73 | ~(crypto_tfm_ctx_alignment() - 1); |
@@ -76,10 +82,16 @@ static void *esp_alloc_tmp(struct crypto_aead *aead, int nfrags) | |||
76 | return kmalloc(len, GFP_ATOMIC); | 82 | return kmalloc(len, GFP_ATOMIC); |
77 | } | 83 | } |
78 | 84 | ||
79 | static inline u8 *esp_tmp_iv(struct crypto_aead *aead, void *tmp) | 85 | static inline __be32 *esp_tmp_seqhi(void *tmp) |
86 | { | ||
87 | return PTR_ALIGN((__be32 *)tmp, __alignof__(__be32)); | ||
88 | } | ||
89 | |||
90 | static inline u8 *esp_tmp_iv(struct crypto_aead *aead, void *tmp, int seqhilen) | ||
80 | { | 91 | { |
81 | return crypto_aead_ivsize(aead) ? | 92 | return crypto_aead_ivsize(aead) ? |
82 | PTR_ALIGN((u8 *)tmp, crypto_aead_alignmask(aead) + 1) : tmp; | 93 | PTR_ALIGN((u8 *)tmp + seqhilen, |
94 | crypto_aead_alignmask(aead) + 1) : tmp + seqhilen; | ||
83 | } | 95 | } |
84 | 96 | ||
85 | static inline struct aead_givcrypt_request *esp_tmp_givreq( | 97 | static inline struct aead_givcrypt_request *esp_tmp_givreq( |
@@ -140,47 +152,76 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
140 | int blksize; | 152 | int blksize; |
141 | int clen; | 153 | int clen; |
142 | int alen; | 154 | int alen; |
155 | int plen; | ||
156 | int tfclen; | ||
143 | int nfrags; | 157 | int nfrags; |
158 | int assoclen; | ||
159 | int sglists; | ||
160 | int seqhilen; | ||
144 | u8 *iv; | 161 | u8 *iv; |
145 | u8 *tail; | 162 | u8 *tail; |
163 | __be32 *seqhi; | ||
146 | struct esp_data *esp = x->data; | 164 | struct esp_data *esp = x->data; |
147 | 165 | ||
148 | /* skb is pure payload to encrypt */ | 166 | /* skb is pure payload to encrypt */ |
149 | err = -ENOMEM; | 167 | err = -ENOMEM; |
150 | 168 | ||
151 | /* Round to block size */ | ||
152 | clen = skb->len; | ||
153 | |||
154 | aead = esp->aead; | 169 | aead = esp->aead; |
155 | alen = crypto_aead_authsize(aead); | 170 | alen = crypto_aead_authsize(aead); |
156 | 171 | ||
172 | tfclen = 0; | ||
173 | if (x->tfcpad) { | ||
174 | struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb); | ||
175 | u32 padto; | ||
176 | |||
177 | padto = min(x->tfcpad, esp6_get_mtu(x, dst->child_mtu_cached)); | ||
178 | if (skb->len < padto) | ||
179 | tfclen = padto - skb->len; | ||
180 | } | ||
157 | blksize = ALIGN(crypto_aead_blocksize(aead), 4); | 181 | blksize = ALIGN(crypto_aead_blocksize(aead), 4); |
158 | clen = ALIGN(clen + 2, blksize); | 182 | clen = ALIGN(skb->len + 2 + tfclen, blksize); |
159 | if (esp->padlen) | 183 | if (esp->padlen) |
160 | clen = ALIGN(clen, esp->padlen); | 184 | clen = ALIGN(clen, esp->padlen); |
185 | plen = clen - skb->len - tfclen; | ||
161 | 186 | ||
162 | if ((err = skb_cow_data(skb, clen - skb->len + alen, &trailer)) < 0) | 187 | err = skb_cow_data(skb, tfclen + plen + alen, &trailer); |
188 | if (err < 0) | ||
163 | goto error; | 189 | goto error; |
164 | nfrags = err; | 190 | nfrags = err; |
165 | 191 | ||
166 | tmp = esp_alloc_tmp(aead, nfrags + 1); | 192 | assoclen = sizeof(*esph); |
193 | sglists = 1; | ||
194 | seqhilen = 0; | ||
195 | |||
196 | if (x->props.flags & XFRM_STATE_ESN) { | ||
197 | sglists += 2; | ||
198 | seqhilen += sizeof(__be32); | ||
199 | assoclen += seqhilen; | ||
200 | } | ||
201 | |||
202 | tmp = esp_alloc_tmp(aead, nfrags + sglists, seqhilen); | ||
167 | if (!tmp) | 203 | if (!tmp) |
168 | goto error; | 204 | goto error; |
169 | 205 | ||
170 | iv = esp_tmp_iv(aead, tmp); | 206 | seqhi = esp_tmp_seqhi(tmp); |
207 | iv = esp_tmp_iv(aead, tmp, seqhilen); | ||
171 | req = esp_tmp_givreq(aead, iv); | 208 | req = esp_tmp_givreq(aead, iv); |
172 | asg = esp_givreq_sg(aead, req); | 209 | asg = esp_givreq_sg(aead, req); |
173 | sg = asg + 1; | 210 | sg = asg + sglists; |
174 | 211 | ||
175 | /* Fill padding... */ | 212 | /* Fill padding... */ |
176 | tail = skb_tail_pointer(trailer); | 213 | tail = skb_tail_pointer(trailer); |
214 | if (tfclen) { | ||
215 | memset(tail, 0, tfclen); | ||
216 | tail += tfclen; | ||
217 | } | ||
177 | do { | 218 | do { |
178 | int i; | 219 | int i; |
179 | for (i=0; i<clen-skb->len - 2; i++) | 220 | for (i = 0; i < plen - 2; i++) |
180 | tail[i] = i + 1; | 221 | tail[i] = i + 1; |
181 | } while (0); | 222 | } while (0); |
182 | tail[clen-skb->len - 2] = (clen - skb->len) - 2; | 223 | tail[plen - 2] = plen - 2; |
183 | tail[clen - skb->len - 1] = *skb_mac_header(skb); | 224 | tail[plen - 1] = *skb_mac_header(skb); |
184 | pskb_put(skb, trailer, clen - skb->len + alen); | 225 | pskb_put(skb, trailer, clen - skb->len + alen); |
185 | 226 | ||
186 | skb_push(skb, -skb_network_offset(skb)); | 227 | skb_push(skb, -skb_network_offset(skb)); |
@@ -188,19 +229,27 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) | |||
188 | *skb_mac_header(skb) = IPPROTO_ESP; | 229 | *skb_mac_header(skb) = IPPROTO_ESP; |
189 | 230 | ||
190 | esph->spi = x->id.spi; | 231 | esph->spi = x->id.spi; |
191 | esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output); | 232 | esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low); |
192 | 233 | ||
193 | sg_init_table(sg, nfrags); | 234 | sg_init_table(sg, nfrags); |
194 | skb_to_sgvec(skb, sg, | 235 | skb_to_sgvec(skb, sg, |
195 | esph->enc_data + crypto_aead_ivsize(aead) - skb->data, | 236 | esph->enc_data + crypto_aead_ivsize(aead) - skb->data, |
196 | clen + alen); | 237 | clen + alen); |
197 | sg_init_one(asg, esph, sizeof(*esph)); | 238 | |
239 | if ((x->props.flags & XFRM_STATE_ESN)) { | ||
240 | sg_init_table(asg, 3); | ||
241 | sg_set_buf(asg, &esph->spi, sizeof(__be32)); | ||
242 | *seqhi = htonl(XFRM_SKB_CB(skb)->seq.output.hi); | ||
243 | sg_set_buf(asg + 1, seqhi, seqhilen); | ||
244 | sg_set_buf(asg + 2, &esph->seq_no, sizeof(__be32)); | ||
245 | } else | ||
246 | sg_init_one(asg, esph, sizeof(*esph)); | ||
198 | 247 | ||
199 | aead_givcrypt_set_callback(req, 0, esp_output_done, skb); | 248 | aead_givcrypt_set_callback(req, 0, esp_output_done, skb); |
200 | aead_givcrypt_set_crypt(req, sg, sg, clen, iv); | 249 | aead_givcrypt_set_crypt(req, sg, sg, clen, iv); |
201 | aead_givcrypt_set_assoc(req, asg, sizeof(*esph)); | 250 | aead_givcrypt_set_assoc(req, asg, assoclen); |
202 | aead_givcrypt_set_giv(req, esph->enc_data, | 251 | aead_givcrypt_set_giv(req, esph->enc_data, |
203 | XFRM_SKB_CB(skb)->seq.output); | 252 | XFRM_SKB_CB(skb)->seq.output.low); |
204 | 253 | ||
205 | ESP_SKB_CB(skb)->tmp = tmp; | 254 | ESP_SKB_CB(skb)->tmp = tmp; |
206 | err = crypto_aead_givencrypt(req); | 255 | err = crypto_aead_givencrypt(req); |
@@ -276,8 +325,12 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
276 | struct sk_buff *trailer; | 325 | struct sk_buff *trailer; |
277 | int elen = skb->len - sizeof(*esph) - crypto_aead_ivsize(aead); | 326 | int elen = skb->len - sizeof(*esph) - crypto_aead_ivsize(aead); |
278 | int nfrags; | 327 | int nfrags; |
328 | int assoclen; | ||
329 | int sglists; | ||
330 | int seqhilen; | ||
279 | int ret = 0; | 331 | int ret = 0; |
280 | void *tmp; | 332 | void *tmp; |
333 | __be32 *seqhi; | ||
281 | u8 *iv; | 334 | u8 *iv; |
282 | struct scatterlist *sg; | 335 | struct scatterlist *sg; |
283 | struct scatterlist *asg; | 336 | struct scatterlist *asg; |
@@ -298,15 +351,27 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
298 | } | 351 | } |
299 | 352 | ||
300 | ret = -ENOMEM; | 353 | ret = -ENOMEM; |
301 | tmp = esp_alloc_tmp(aead, nfrags + 1); | 354 | |
355 | assoclen = sizeof(*esph); | ||
356 | sglists = 1; | ||
357 | seqhilen = 0; | ||
358 | |||
359 | if (x->props.flags & XFRM_STATE_ESN) { | ||
360 | sglists += 2; | ||
361 | seqhilen += sizeof(__be32); | ||
362 | assoclen += seqhilen; | ||
363 | } | ||
364 | |||
365 | tmp = esp_alloc_tmp(aead, nfrags + sglists, seqhilen); | ||
302 | if (!tmp) | 366 | if (!tmp) |
303 | goto out; | 367 | goto out; |
304 | 368 | ||
305 | ESP_SKB_CB(skb)->tmp = tmp; | 369 | ESP_SKB_CB(skb)->tmp = tmp; |
306 | iv = esp_tmp_iv(aead, tmp); | 370 | seqhi = esp_tmp_seqhi(tmp); |
371 | iv = esp_tmp_iv(aead, tmp, seqhilen); | ||
307 | req = esp_tmp_req(aead, iv); | 372 | req = esp_tmp_req(aead, iv); |
308 | asg = esp_req_sg(aead, req); | 373 | asg = esp_req_sg(aead, req); |
309 | sg = asg + 1; | 374 | sg = asg + sglists; |
310 | 375 | ||
311 | skb->ip_summed = CHECKSUM_NONE; | 376 | skb->ip_summed = CHECKSUM_NONE; |
312 | 377 | ||
@@ -317,11 +382,19 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) | |||
317 | 382 | ||
318 | sg_init_table(sg, nfrags); | 383 | sg_init_table(sg, nfrags); |
319 | skb_to_sgvec(skb, sg, sizeof(*esph) + crypto_aead_ivsize(aead), elen); | 384 | skb_to_sgvec(skb, sg, sizeof(*esph) + crypto_aead_ivsize(aead), elen); |
320 | sg_init_one(asg, esph, sizeof(*esph)); | 385 | |
386 | if ((x->props.flags & XFRM_STATE_ESN)) { | ||
387 | sg_init_table(asg, 3); | ||
388 | sg_set_buf(asg, &esph->spi, sizeof(__be32)); | ||
389 | *seqhi = XFRM_SKB_CB(skb)->seq.input.hi; | ||
390 | sg_set_buf(asg + 1, seqhi, seqhilen); | ||
391 | sg_set_buf(asg + 2, &esph->seq_no, sizeof(__be32)); | ||
392 | } else | ||
393 | sg_init_one(asg, esph, sizeof(*esph)); | ||
321 | 394 | ||
322 | aead_request_set_callback(req, 0, esp_input_done, skb); | 395 | aead_request_set_callback(req, 0, esp_input_done, skb); |
323 | aead_request_set_crypt(req, sg, sg, elen, iv); | 396 | aead_request_set_crypt(req, sg, sg, elen, iv); |
324 | aead_request_set_assoc(req, asg, sizeof(*esph)); | 397 | aead_request_set_assoc(req, asg, assoclen); |
325 | 398 | ||
326 | ret = crypto_aead_decrypt(req); | 399 | ret = crypto_aead_decrypt(req); |
327 | if (ret == -EINPROGRESS) | 400 | if (ret == -EINPROGRESS) |
@@ -357,7 +430,7 @@ static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
357 | u8 type, u8 code, int offset, __be32 info) | 430 | u8 type, u8 code, int offset, __be32 info) |
358 | { | 431 | { |
359 | struct net *net = dev_net(skb->dev); | 432 | struct net *net = dev_net(skb->dev); |
360 | struct ipv6hdr *iph = (struct ipv6hdr*)skb->data; | 433 | const struct ipv6hdr *iph = (const struct ipv6hdr *)skb->data; |
361 | struct ip_esp_hdr *esph = (struct ip_esp_hdr *)(skb->data + offset); | 434 | struct ip_esp_hdr *esph = (struct ip_esp_hdr *)(skb->data + offset); |
362 | struct xfrm_state *x; | 435 | struct xfrm_state *x; |
363 | 436 | ||
@@ -365,7 +438,8 @@ static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
365 | type != ICMPV6_PKT_TOOBIG) | 438 | type != ICMPV6_PKT_TOOBIG) |
366 | return; | 439 | return; |
367 | 440 | ||
368 | x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET6); | 441 | x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr, |
442 | esph->spi, IPPROTO_ESP, AF_INET6); | ||
369 | if (!x) | 443 | if (!x) |
370 | return; | 444 | return; |
371 | printk(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%pI6\n", | 445 | printk(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%pI6\n", |
@@ -427,10 +501,20 @@ static int esp_init_authenc(struct xfrm_state *x) | |||
427 | goto error; | 501 | goto error; |
428 | 502 | ||
429 | err = -ENAMETOOLONG; | 503 | err = -ENAMETOOLONG; |
430 | if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, "authenc(%s,%s)", | 504 | |
431 | x->aalg ? x->aalg->alg_name : "digest_null", | 505 | if ((x->props.flags & XFRM_STATE_ESN)) { |
432 | x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME) | 506 | if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, |
433 | goto error; | 507 | "authencesn(%s,%s)", |
508 | x->aalg ? x->aalg->alg_name : "digest_null", | ||
509 | x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME) | ||
510 | goto error; | ||
511 | } else { | ||
512 | if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, | ||
513 | "authenc(%s,%s)", | ||
514 | x->aalg ? x->aalg->alg_name : "digest_null", | ||
515 | x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME) | ||
516 | goto error; | ||
517 | } | ||
434 | 518 | ||
435 | aead = crypto_alloc_aead(authenc_name, 0, 0); | 519 | aead = crypto_alloc_aead(authenc_name, 0, 0); |
436 | err = PTR_ERR(aead); | 520 | err = PTR_ERR(aead); |