aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/ah6.c56
1 files changed, 45 insertions, 11 deletions
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index 81e496a2e008..6c5f0949e0ab 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -346,6 +346,10 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
346 struct ip_auth_hdr *ah; 346 struct ip_auth_hdr *ah;
347 struct ah_data *ahp; 347 struct ah_data *ahp;
348 struct tmp_ext *iph_ext; 348 struct tmp_ext *iph_ext;
349 int seqhi_len = 0;
350 __be32 *seqhi;
351 int sglists = 0;
352 struct scatterlist *seqhisg;
349 353
350 ahp = x->data; 354 ahp = x->data;
351 ahash = ahp->ahash; 355 ahash = ahp->ahash;
@@ -359,15 +363,22 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
359 if (extlen) 363 if (extlen)
360 extlen += sizeof(*iph_ext); 364 extlen += sizeof(*iph_ext);
361 365
366 if (x->props.flags & XFRM_STATE_ESN) {
367 sglists = 1;
368 seqhi_len = sizeof(*seqhi);
369 }
362 err = -ENOMEM; 370 err = -ENOMEM;
363 iph_base = ah_alloc_tmp(ahash, nfrags, IPV6HDR_BASELEN + extlen); 371 iph_base = ah_alloc_tmp(ahash, nfrags + sglists, IPV6HDR_BASELEN +
372 extlen + seqhi_len);
364 if (!iph_base) 373 if (!iph_base)
365 goto out; 374 goto out;
366 375
367 iph_ext = ah_tmp_ext(iph_base); 376 iph_ext = ah_tmp_ext(iph_base);
368 icv = ah_tmp_icv(ahash, iph_ext, extlen); 377 seqhi = (__be32 *)((char *)iph_ext + extlen);
378 icv = ah_tmp_icv(ahash, seqhi, seqhi_len);
369 req = ah_tmp_req(ahash, icv); 379 req = ah_tmp_req(ahash, icv);
370 sg = ah_req_sg(ahash, req); 380 sg = ah_req_sg(ahash, req);
381 seqhisg = sg + nfrags;
371 382
372 ah = ip_auth_hdr(skb); 383 ah = ip_auth_hdr(skb);
373 memset(ah->auth_data, 0, ahp->icv_trunc_len); 384 memset(ah->auth_data, 0, ahp->icv_trunc_len);
@@ -411,10 +422,15 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
411 ah->spi = x->id.spi; 422 ah->spi = x->id.spi;
412 ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low); 423 ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low);
413 424
414 sg_init_table(sg, nfrags); 425 sg_init_table(sg, nfrags + sglists);
415 skb_to_sgvec(skb, sg, 0, skb->len); 426 skb_to_sgvec_nomark(skb, sg, 0, skb->len);
416 427
417 ahash_request_set_crypt(req, sg, icv, skb->len); 428 if (x->props.flags & XFRM_STATE_ESN) {
429 /* Attach seqhi sg right after packet payload */
430 *seqhi = htonl(XFRM_SKB_CB(skb)->seq.output.hi);
431 sg_set_buf(seqhisg, seqhi, seqhi_len);
432 }
433 ahash_request_set_crypt(req, sg, icv, skb->len + seqhi_len);
418 ahash_request_set_callback(req, 0, ah6_output_done, skb); 434 ahash_request_set_callback(req, 0, ah6_output_done, skb);
419 435
420 AH_SKB_CB(skb)->tmp = iph_base; 436 AH_SKB_CB(skb)->tmp = iph_base;
@@ -514,6 +530,10 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
514 int nexthdr; 530 int nexthdr;
515 int nfrags; 531 int nfrags;
516 int err = -ENOMEM; 532 int err = -ENOMEM;
533 int seqhi_len = 0;
534 __be32 *seqhi;
535 int sglists = 0;
536 struct scatterlist *seqhisg;
517 537
518 if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr))) 538 if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr)))
519 goto out; 539 goto out;
@@ -550,14 +570,22 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
550 570
551 skb_push(skb, hdr_len); 571 skb_push(skb, hdr_len);
552 572
553 work_iph = ah_alloc_tmp(ahash, nfrags, hdr_len + ahp->icv_trunc_len); 573 if (x->props.flags & XFRM_STATE_ESN) {
574 sglists = 1;
575 seqhi_len = sizeof(*seqhi);
576 }
577
578 work_iph = ah_alloc_tmp(ahash, nfrags + sglists, hdr_len +
579 ahp->icv_trunc_len + seqhi_len);
554 if (!work_iph) 580 if (!work_iph)
555 goto out; 581 goto out;
556 582
557 auth_data = ah_tmp_auth(work_iph, hdr_len); 583 auth_data = ah_tmp_auth((u8 *)work_iph, hdr_len);
558 icv = ah_tmp_icv(ahash, auth_data, ahp->icv_trunc_len); 584 seqhi = (__be32 *)(auth_data + ahp->icv_trunc_len);
585 icv = ah_tmp_icv(ahash, seqhi, seqhi_len);
559 req = ah_tmp_req(ahash, icv); 586 req = ah_tmp_req(ahash, icv);
560 sg = ah_req_sg(ahash, req); 587 sg = ah_req_sg(ahash, req);
588 seqhisg = sg + nfrags;
561 589
562 memcpy(work_iph, ip6h, hdr_len); 590 memcpy(work_iph, ip6h, hdr_len);
563 memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); 591 memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
@@ -572,10 +600,16 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
572 ip6h->flow_lbl[2] = 0; 600 ip6h->flow_lbl[2] = 0;
573 ip6h->hop_limit = 0; 601 ip6h->hop_limit = 0;
574 602
575 sg_init_table(sg, nfrags); 603 sg_init_table(sg, nfrags + sglists);
576 skb_to_sgvec(skb, sg, 0, skb->len); 604 skb_to_sgvec_nomark(skb, sg, 0, skb->len);
605
606 if (x->props.flags & XFRM_STATE_ESN) {
607 /* Attach seqhi sg right after packet payload */
608 *seqhi = XFRM_SKB_CB(skb)->seq.input.hi;
609 sg_set_buf(seqhisg, seqhi, seqhi_len);
610 }
577 611
578 ahash_request_set_crypt(req, sg, icv, skb->len); 612 ahash_request_set_crypt(req, sg, icv, skb->len + seqhi_len);
579 ahash_request_set_callback(req, 0, ah6_input_done, skb); 613 ahash_request_set_callback(req, 0, ah6_input_done, skb);
580 614
581 AH_SKB_CB(skb)->tmp = work_iph; 615 AH_SKB_CB(skb)->tmp = work_iph;