aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorFan Du <fan.du@windriver.com>2014-01-17 20:54:24 -0500
committerSteffen Klassert <steffen.klassert@secunet.com>2014-02-12 01:02:10 -0500
commitd4d573d0334d07341beffdcf97e2b85d3955d8ae (patch)
tree9cd3e65edd08be02ab95c581bd626a95b826acdf /net/ipv4
parent25a91d8d91911f84a03a039339b29537e7f1970d (diff)
{IPv4,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/ipv4')
-rw-r--r--net/ipv4/ah4.c26
1 files changed, 20 insertions, 6 deletions
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index 717902669d2f..c6accacc3a2b 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -155,6 +155,10 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb)
155 struct iphdr *iph, *top_iph; 155 struct iphdr *iph, *top_iph;
156 struct ip_auth_hdr *ah; 156 struct ip_auth_hdr *ah;
157 struct ah_data *ahp; 157 struct ah_data *ahp;
158 int seqhi_len = 0;
159 __be32 *seqhi;
160 int sglists = 0;
161 struct scatterlist *seqhisg;
158 162
159 ahp = x->data; 163 ahp = x->data;
160 ahash = ahp->ahash; 164 ahash = ahp->ahash;
@@ -167,14 +171,19 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb)
167 ah = ip_auth_hdr(skb); 171 ah = ip_auth_hdr(skb);
168 ihl = ip_hdrlen(skb); 172 ihl = ip_hdrlen(skb);
169 173
174 if (x->props.flags & XFRM_STATE_ESN) {
175 sglists = 1;
176 seqhi_len = sizeof(*seqhi);
177 }
170 err = -ENOMEM; 178 err = -ENOMEM;
171 iph = ah_alloc_tmp(ahash, nfrags, ihl); 179 iph = ah_alloc_tmp(ahash, nfrags + sglists, ihl + seqhi_len);
172 if (!iph) 180 if (!iph)
173 goto out; 181 goto out;
174 182 seqhi = (__be32 *)((char *)iph + ihl);
175 icv = ah_tmp_icv(ahash, iph, ihl); 183 icv = ah_tmp_icv(ahash, seqhi, seqhi_len);
176 req = ah_tmp_req(ahash, icv); 184 req = ah_tmp_req(ahash, icv);
177 sg = ah_req_sg(ahash, req); 185 sg = ah_req_sg(ahash, req);
186 seqhisg = sg + nfrags;
178 187
179 memset(ah->auth_data, 0, ahp->icv_trunc_len); 188 memset(ah->auth_data, 0, ahp->icv_trunc_len);
180 189
@@ -210,10 +219,15 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb)
210 ah->spi = x->id.spi; 219 ah->spi = x->id.spi;
211 ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low); 220 ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low);
212 221
213 sg_init_table(sg, nfrags); 222 sg_init_table(sg, nfrags + sglists);
214 skb_to_sgvec(skb, sg, 0, skb->len); 223 skb_to_sgvec_nomark(skb, sg, 0, skb->len);
215 224
216 ahash_request_set_crypt(req, sg, icv, skb->len); 225 if (x->props.flags & XFRM_STATE_ESN) {
226 /* Attach seqhi sg right after packet payload */
227 *seqhi = htonl(XFRM_SKB_CB(skb)->seq.output.hi);
228 sg_set_buf(seqhisg, seqhi, seqhi_len);
229 }
230 ahash_request_set_crypt(req, sg, icv, skb->len + seqhi_len);
217 ahash_request_set_callback(req, 0, ah_output_done, skb); 231 ahash_request_set_callback(req, 0, ah_output_done, skb);
218 232
219 AH_SKB_CB(skb)->tmp = iph; 233 AH_SKB_CB(skb)->tmp = iph;