aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/ipv4/ah4.c27
1 files changed, 22 insertions, 5 deletions
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index c6accacc3a2b..54b965ddcb19 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -309,6 +309,10 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
309 struct ip_auth_hdr *ah; 309 struct ip_auth_hdr *ah;
310 struct ah_data *ahp; 310 struct ah_data *ahp;
311 int err = -ENOMEM; 311 int err = -ENOMEM;
312 int seqhi_len = 0;
313 __be32 *seqhi;
314 int sglists = 0;
315 struct scatterlist *seqhisg;
312 316
313 if (!pskb_may_pull(skb, sizeof(*ah))) 317 if (!pskb_may_pull(skb, sizeof(*ah)))
314 goto out; 318 goto out;
@@ -349,14 +353,22 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
349 iph = ip_hdr(skb); 353 iph = ip_hdr(skb);
350 ihl = ip_hdrlen(skb); 354 ihl = ip_hdrlen(skb);
351 355
352 work_iph = ah_alloc_tmp(ahash, nfrags, ihl + ahp->icv_trunc_len); 356 if (x->props.flags & XFRM_STATE_ESN) {
357 sglists = 1;
358 seqhi_len = sizeof(*seqhi);
359 }
360
361 work_iph = ah_alloc_tmp(ahash, nfrags + sglists, ihl +
362 ahp->icv_trunc_len + seqhi_len);
353 if (!work_iph) 363 if (!work_iph)
354 goto out; 364 goto out;
355 365
356 auth_data = ah_tmp_auth(work_iph, ihl); 366 seqhi = (__be32 *)((char *)work_iph + ihl);
367 auth_data = ah_tmp_auth(seqhi, seqhi_len);
357 icv = ah_tmp_icv(ahash, auth_data, ahp->icv_trunc_len); 368 icv = ah_tmp_icv(ahash, auth_data, ahp->icv_trunc_len);
358 req = ah_tmp_req(ahash, icv); 369 req = ah_tmp_req(ahash, icv);
359 sg = ah_req_sg(ahash, req); 370 sg = ah_req_sg(ahash, req);
371 seqhisg = sg + nfrags;
360 372
361 memcpy(work_iph, iph, ihl); 373 memcpy(work_iph, iph, ihl);
362 memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); 374 memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
@@ -375,10 +387,15 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
375 387
376 skb_push(skb, ihl); 388 skb_push(skb, ihl);
377 389
378 sg_init_table(sg, nfrags); 390 sg_init_table(sg, nfrags + sglists);
379 skb_to_sgvec(skb, sg, 0, skb->len); 391 skb_to_sgvec_nomark(skb, sg, 0, skb->len);
380 392
381 ahash_request_set_crypt(req, sg, icv, skb->len); 393 if (x->props.flags & XFRM_STATE_ESN) {
394 /* Attach seqhi sg right after packet payload */
395 *seqhi = XFRM_SKB_CB(skb)->seq.input.hi;
396 sg_set_buf(seqhisg, seqhi, seqhi_len);
397 }
398 ahash_request_set_crypt(req, sg, icv, skb->len + seqhi_len);
382 ahash_request_set_callback(req, 0, ah_input_done, skb); 399 ahash_request_set_callback(req, 0, ah_input_done, skb);
383 400
384 AH_SKB_CB(skb)->tmp = work_iph; 401 AH_SKB_CB(skb)->tmp = work_iph;