aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorFan Du <fan.du@windriver.com>2014-01-17 20:54:27 -0500
committerSteffen Klassert <steffen.klassert@secunet.com>2014-02-12 01:02:11 -0500
commit8d6da6f325572664107601a3c9782f8c23c1bfc5 (patch)
tree44f249e7182fd812ae4261083d6d61d50a201b4b /net/ipv6
parent26dd70c3fad36f4b1aa124080d5907db10ed287c (diff)
{IPv6,xfrm} Add ESN support for AH ingress part
This patch add esn support for AH input stage by attaching upper 32bits sequence number right after packet payload as specified by RFC 4302. Then the ICV value will guard upper 32bits sequence number as well when packet going in. Signed-off-by: Fan Du <fan.du@windriver.com> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/ah6.c30
1 files changed, 24 insertions, 6 deletions
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index 89298124c136..6c5f0949e0ab 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -530,6 +530,10 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
530 int nexthdr; 530 int nexthdr;
531 int nfrags; 531 int nfrags;
532 int err = -ENOMEM; 532 int err = -ENOMEM;
533 int seqhi_len = 0;
534 __be32 *seqhi;
535 int sglists = 0;
536 struct scatterlist *seqhisg;
533 537
534 if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr))) 538 if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr)))
535 goto out; 539 goto out;
@@ -566,14 +570,22 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
566 570
567 skb_push(skb, hdr_len); 571 skb_push(skb, hdr_len);
568 572
569 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);
570 if (!work_iph) 580 if (!work_iph)
571 goto out; 581 goto out;
572 582
573 auth_data = ah_tmp_auth(work_iph, hdr_len); 583 auth_data = ah_tmp_auth((u8 *)work_iph, hdr_len);
574 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);
575 req = ah_tmp_req(ahash, icv); 586 req = ah_tmp_req(ahash, icv);
576 sg = ah_req_sg(ahash, req); 587 sg = ah_req_sg(ahash, req);
588 seqhisg = sg + nfrags;
577 589
578 memcpy(work_iph, ip6h, hdr_len); 590 memcpy(work_iph, ip6h, hdr_len);
579 memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); 591 memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
@@ -588,10 +600,16 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
588 ip6h->flow_lbl[2] = 0; 600 ip6h->flow_lbl[2] = 0;
589 ip6h->hop_limit = 0; 601 ip6h->hop_limit = 0;
590 602
591 sg_init_table(sg, nfrags); 603 sg_init_table(sg, nfrags + sglists);
592 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 }
593 611
594 ahash_request_set_crypt(req, sg, icv, skb->len); 612 ahash_request_set_crypt(req, sg, icv, skb->len + seqhi_len);
595 ahash_request_set_callback(req, 0, ah6_input_done, skb); 613 ahash_request_set_callback(req, 0, ah6_input_done, skb);
596 614
597 AH_SKB_CB(skb)->tmp = work_iph; 615 AH_SKB_CB(skb)->tmp = work_iph;