diff options
Diffstat (limited to 'net/ipv4/esp4.c')
-rw-r--r-- | net/ipv4/esp4.c | 59 |
1 files changed, 35 insertions, 24 deletions
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 31041127eeb8..47c95e8ef045 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c | |||
@@ -21,13 +21,14 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) | |||
21 | struct blkcipher_desc desc; | 21 | struct blkcipher_desc desc; |
22 | struct esp_data *esp; | 22 | struct esp_data *esp; |
23 | struct sk_buff *trailer; | 23 | struct sk_buff *trailer; |
24 | u8 *tail; | ||
24 | int blksize; | 25 | int blksize; |
25 | int clen; | 26 | int clen; |
26 | int alen; | 27 | int alen; |
27 | int nfrags; | 28 | int nfrags; |
28 | 29 | ||
29 | /* Strip IP+ESP header. */ | 30 | /* Strip IP+ESP header. */ |
30 | __skb_pull(skb, skb->h.raw - skb->data); | 31 | __skb_pull(skb, skb_transport_offset(skb)); |
31 | /* Now skb is pure payload to encrypt */ | 32 | /* Now skb is pure payload to encrypt */ |
32 | 33 | ||
33 | err = -ENOMEM; | 34 | err = -ENOMEM; |
@@ -49,19 +50,21 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) | |||
49 | goto error; | 50 | goto error; |
50 | 51 | ||
51 | /* Fill padding... */ | 52 | /* Fill padding... */ |
53 | tail = skb_tail_pointer(trailer); | ||
52 | do { | 54 | do { |
53 | int i; | 55 | int i; |
54 | for (i=0; i<clen-skb->len - 2; i++) | 56 | for (i=0; i<clen-skb->len - 2; i++) |
55 | *(u8*)(trailer->tail + i) = i+1; | 57 | tail[i] = i + 1; |
56 | } while (0); | 58 | } while (0); |
57 | *(u8*)(trailer->tail + clen-skb->len - 2) = (clen - skb->len)-2; | 59 | tail[clen - skb->len - 2] = (clen - skb->len) - 2; |
58 | pskb_put(skb, trailer, clen - skb->len); | 60 | pskb_put(skb, trailer, clen - skb->len); |
59 | 61 | ||
60 | __skb_push(skb, skb->data - skb->nh.raw); | 62 | __skb_push(skb, skb->data - skb_network_header(skb)); |
61 | top_iph = skb->nh.iph; | 63 | top_iph = ip_hdr(skb); |
62 | esph = (struct ip_esp_hdr *)(skb->nh.raw + top_iph->ihl*4); | 64 | esph = (struct ip_esp_hdr *)(skb_network_header(skb) + |
65 | top_iph->ihl * 4); | ||
63 | top_iph->tot_len = htons(skb->len + alen); | 66 | top_iph->tot_len = htons(skb->len + alen); |
64 | *(u8*)(trailer->tail - 1) = top_iph->protocol; | 67 | *(skb_tail_pointer(trailer) - 1) = top_iph->protocol; |
65 | 68 | ||
66 | /* this is non-NULL only with UDP Encapsulation */ | 69 | /* this is non-NULL only with UDP Encapsulation */ |
67 | if (x->encap) { | 70 | if (x->encap) { |
@@ -217,12 +220,12 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb) | |||
217 | 220 | ||
218 | /* ... check padding bits here. Silly. :-) */ | 221 | /* ... check padding bits here. Silly. :-) */ |
219 | 222 | ||
220 | iph = skb->nh.iph; | 223 | iph = ip_hdr(skb); |
221 | ihl = iph->ihl * 4; | 224 | ihl = iph->ihl * 4; |
222 | 225 | ||
223 | if (x->encap) { | 226 | if (x->encap) { |
224 | struct xfrm_encap_tmpl *encap = x->encap; | 227 | struct xfrm_encap_tmpl *encap = x->encap; |
225 | struct udphdr *uh = (void *)(skb->nh.raw + ihl); | 228 | struct udphdr *uh = (void *)(skb_network_header(skb) + ihl); |
226 | 229 | ||
227 | /* | 230 | /* |
228 | * 1) if the NAT-T peer's IP or port changed then | 231 | * 1) if the NAT-T peer's IP or port changed then |
@@ -260,7 +263,8 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb) | |||
260 | 263 | ||
261 | iph->protocol = nexthdr[1]; | 264 | iph->protocol = nexthdr[1]; |
262 | pskb_trim(skb, skb->len - alen - padlen - 2); | 265 | pskb_trim(skb, skb->len - alen - padlen - 2); |
263 | skb->h.raw = __skb_pull(skb, sizeof(*esph) + esp->conf.ivlen) - ihl; | 266 | __skb_pull(skb, sizeof(*esph) + esp->conf.ivlen); |
267 | skb_set_transport_header(skb, -ihl); | ||
264 | 268 | ||
265 | return 0; | 269 | return 0; |
266 | 270 | ||
@@ -268,32 +272,33 @@ out: | |||
268 | return -EINVAL; | 272 | return -EINVAL; |
269 | } | 273 | } |
270 | 274 | ||
271 | static u32 esp4_get_max_size(struct xfrm_state *x, int mtu) | 275 | static u32 esp4_get_mtu(struct xfrm_state *x, int mtu) |
272 | { | 276 | { |
273 | struct esp_data *esp = x->data; | 277 | struct esp_data *esp = x->data; |
274 | u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4); | 278 | u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4); |
275 | int enclen = 0; | 279 | u32 align = max_t(u32, blksize, esp->conf.padlen); |
280 | u32 rem; | ||
281 | |||
282 | mtu -= x->props.header_len + esp->auth.icv_trunc_len; | ||
283 | rem = mtu & (align - 1); | ||
284 | mtu &= ~(align - 1); | ||
276 | 285 | ||
277 | switch (x->props.mode) { | 286 | switch (x->props.mode) { |
278 | case XFRM_MODE_TUNNEL: | 287 | case XFRM_MODE_TUNNEL: |
279 | mtu = ALIGN(mtu +2, blksize); | ||
280 | break; | 288 | break; |
281 | default: | 289 | default: |
282 | case XFRM_MODE_TRANSPORT: | 290 | case XFRM_MODE_TRANSPORT: |
283 | /* The worst case */ | 291 | /* The worst case */ |
284 | mtu = ALIGN(mtu + 2, 4) + blksize - 4; | 292 | mtu -= blksize - 4; |
293 | mtu += min_t(u32, blksize - 4, rem); | ||
285 | break; | 294 | break; |
286 | case XFRM_MODE_BEET: | 295 | case XFRM_MODE_BEET: |
287 | /* The worst case. */ | 296 | /* The worst case. */ |
288 | enclen = IPV4_BEET_PHMAXLEN; | 297 | mtu += min_t(u32, IPV4_BEET_PHMAXLEN, rem); |
289 | mtu = ALIGN(mtu + enclen + 2, blksize); | ||
290 | break; | 298 | break; |
291 | } | 299 | } |
292 | 300 | ||
293 | if (esp->conf.padlen) | 301 | return mtu - 2; |
294 | mtu = ALIGN(mtu, esp->conf.padlen); | ||
295 | |||
296 | return mtu + x->props.header_len + esp->auth.icv_trunc_len - enclen; | ||
297 | } | 302 | } |
298 | 303 | ||
299 | static void esp4_err(struct sk_buff *skb, u32 info) | 304 | static void esp4_err(struct sk_buff *skb, u32 info) |
@@ -302,8 +307,8 @@ static void esp4_err(struct sk_buff *skb, u32 info) | |||
302 | struct ip_esp_hdr *esph = (struct ip_esp_hdr*)(skb->data+(iph->ihl<<2)); | 307 | struct ip_esp_hdr *esph = (struct ip_esp_hdr*)(skb->data+(iph->ihl<<2)); |
303 | struct xfrm_state *x; | 308 | struct xfrm_state *x; |
304 | 309 | ||
305 | if (skb->h.icmph->type != ICMP_DEST_UNREACH || | 310 | if (icmp_hdr(skb)->type != ICMP_DEST_UNREACH || |
306 | skb->h.icmph->code != ICMP_FRAG_NEEDED) | 311 | icmp_hdr(skb)->code != ICMP_FRAG_NEEDED) |
307 | return; | 312 | return; |
308 | 313 | ||
309 | x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET); | 314 | x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET); |
@@ -336,6 +341,7 @@ static int esp_init_state(struct xfrm_state *x) | |||
336 | { | 341 | { |
337 | struct esp_data *esp = NULL; | 342 | struct esp_data *esp = NULL; |
338 | struct crypto_blkcipher *tfm; | 343 | struct crypto_blkcipher *tfm; |
344 | u32 align; | ||
339 | 345 | ||
340 | /* null auth and encryption can have zero length keys */ | 346 | /* null auth and encryption can have zero length keys */ |
341 | if (x->aalg) { | 347 | if (x->aalg) { |
@@ -402,6 +408,8 @@ static int esp_init_state(struct xfrm_state *x) | |||
402 | x->props.header_len = sizeof(struct ip_esp_hdr) + esp->conf.ivlen; | 408 | x->props.header_len = sizeof(struct ip_esp_hdr) + esp->conf.ivlen; |
403 | if (x->props.mode == XFRM_MODE_TUNNEL) | 409 | if (x->props.mode == XFRM_MODE_TUNNEL) |
404 | x->props.header_len += sizeof(struct iphdr); | 410 | x->props.header_len += sizeof(struct iphdr); |
411 | else if (x->props.mode == XFRM_MODE_BEET) | ||
412 | x->props.header_len += IPV4_BEET_PHMAXLEN; | ||
405 | if (x->encap) { | 413 | if (x->encap) { |
406 | struct xfrm_encap_tmpl *encap = x->encap; | 414 | struct xfrm_encap_tmpl *encap = x->encap; |
407 | 415 | ||
@@ -417,7 +425,10 @@ static int esp_init_state(struct xfrm_state *x) | |||
417 | } | 425 | } |
418 | } | 426 | } |
419 | x->data = esp; | 427 | x->data = esp; |
420 | x->props.trailer_len = esp4_get_max_size(x, 0) - x->props.header_len; | 428 | align = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4); |
429 | if (esp->conf.padlen) | ||
430 | align = max_t(u32, align, esp->conf.padlen); | ||
431 | x->props.trailer_len = align + 1 + esp->auth.icv_trunc_len; | ||
421 | return 0; | 432 | return 0; |
422 | 433 | ||
423 | error: | 434 | error: |
@@ -434,7 +445,7 @@ static struct xfrm_type esp_type = | |||
434 | .proto = IPPROTO_ESP, | 445 | .proto = IPPROTO_ESP, |
435 | .init_state = esp_init_state, | 446 | .init_state = esp_init_state, |
436 | .destructor = esp_destroy, | 447 | .destructor = esp_destroy, |
437 | .get_max_size = esp4_get_max_size, | 448 | .get_mtu = esp4_get_mtu, |
438 | .input = esp_input, | 449 | .input = esp_input, |
439 | .output = esp_output | 450 | .output = esp_output |
440 | }; | 451 | }; |