aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ah6.c
diff options
context:
space:
mode:
authorFan Du <fan.du@windriver.com>2014-01-17 20:54:26 -0500
committerSteffen Klassert <steffen.klassert@secunet.com>2014-02-12 01:02:11 -0500
commit26dd70c3fad36f4b1aa124080d5907db10ed287c (patch)
treec296a63cc7aee9f53f6a3dc33cfb7aa0f76c4c04 /net/ipv6/ah6.c
parentd8b2a8600b0ea002985d65bba4a94642a01bfe4c (diff)
{IPv6,xfrm} Add ESN support for AH egress part
This patch add esn support for AH output 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 out. Signed-off-by: Fan Du <fan.du@windriver.com> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Diffstat (limited to 'net/ipv6/ah6.c')
-rw-r--r--net/ipv6/ah6.c26
1 files changed, 21 insertions, 5 deletions
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index 81e496a2e008..89298124c136 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;