diff options
-rw-r--r-- | net/ipv4/ah4.c | 27 |
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; |