Blame view

net/ipv6/esp6.c 15.7 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
  /*
   * Copyright (C)2002 USAGI/WIDE Project
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
3
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
7
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
8
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
12
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
13
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
16
17
18
19
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   *
   * Authors
   *
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
20
   *	Mitsuru KANDA @USAGI       : IPv6 Support
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
   * 	Kazunori MIYAZAWA @USAGI   :
   * 	Kunihiro Ishiguro <kunihiro@ipinfusion.com>
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
23
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
   * 	This file is derived from net/ipv4/esp.c
   */
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
26
27
  #include <crypto/aead.h>
  #include <crypto/authenc.h>
6b7326c84   Herbert Xu   [IPSEC] ESP: Use ...
28
  #include <linux/err.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
31
32
  #include <linux/module.h>
  #include <net/ip.h>
  #include <net/xfrm.h>
  #include <net/esp.h>
72998d8c8   Adrian Bunk   [INET] ESP: Must ...
33
  #include <linux/scatterlist.h>
a02a64223   Herbert Xu   [IPSEC]: Use ALIG...
34
  #include <linux/kernel.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
  #include <linux/pfkeyv2.h>
  #include <linux/random.h>
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
37
  #include <linux/slab.h>
b7c6538cd   Herbert Xu   [IPSEC]: Move sta...
38
  #include <linux/spinlock.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
  #include <net/icmp.h>
  #include <net/ipv6.h>
14c850212   Arnaldo Carvalho de Melo   [INET_SOCK]: Move...
41
  #include <net/protocol.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
  #include <linux/icmpv6.h>
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
43
44
45
46
47
48
  struct esp_skb_cb {
  	struct xfrm_skb_cb xfrm;
  	void *tmp;
  };
  
  #define ESP_SKB_CB(__skb) ((struct esp_skb_cb *)&((__skb)->cb[0]))
040253c93   Martin Willi   xfrm: Traffic Flo...
49
  static u32 esp6_get_mtu(struct xfrm_state *x, int mtu);
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
50
51
52
  /*
   * Allocate an AEAD request structure with extra space for SG and IV.
   *
d212a4c29   Steffen Klassert   esp6: Add support...
53
54
55
   * For alignment considerations the upper 32 bits of the sequence number are
   * placed at the front, if present. Followed by the IV, the request and finally
   * the SG list.
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
56
57
58
   *
   * TODO: Use spare space in skb for this where possible.
   */
d212a4c29   Steffen Klassert   esp6: Add support...
59
  static void *esp_alloc_tmp(struct crypto_aead *aead, int nfrags, int seqihlen)
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
60
61
  {
  	unsigned int len;
d212a4c29   Steffen Klassert   esp6: Add support...
62
63
64
  	len = seqihlen;
  
  	len += crypto_aead_ivsize(aead);
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
65
66
67
68
69
70
71
72
73
74
75
76
77
  	if (len) {
  		len += crypto_aead_alignmask(aead) &
  		       ~(crypto_tfm_ctx_alignment() - 1);
  		len = ALIGN(len, crypto_tfm_ctx_alignment());
  	}
  
  	len += sizeof(struct aead_givcrypt_request) + crypto_aead_reqsize(aead);
  	len = ALIGN(len, __alignof__(struct scatterlist));
  
  	len += sizeof(struct scatterlist) * nfrags;
  
  	return kmalloc(len, GFP_ATOMIC);
  }
d212a4c29   Steffen Klassert   esp6: Add support...
78
79
80
81
82
83
  static inline __be32 *esp_tmp_seqhi(void *tmp)
  {
  	return PTR_ALIGN((__be32 *)tmp, __alignof__(__be32));
  }
  
  static inline u8 *esp_tmp_iv(struct crypto_aead *aead, void *tmp, int seqhilen)
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
84
85
  {
  	return crypto_aead_ivsize(aead) ?
d212a4c29   Steffen Klassert   esp6: Add support...
86
87
  	       PTR_ALIGN((u8 *)tmp + seqhilen,
  			 crypto_aead_alignmask(aead) + 1) : tmp + seqhilen;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
  }
  
  static inline struct aead_givcrypt_request *esp_tmp_givreq(
  	struct crypto_aead *aead, u8 *iv)
  {
  	struct aead_givcrypt_request *req;
  
  	req = (void *)PTR_ALIGN(iv + crypto_aead_ivsize(aead),
  				crypto_tfm_ctx_alignment());
  	aead_givcrypt_set_tfm(req, aead);
  	return req;
  }
  
  static inline struct aead_request *esp_tmp_req(struct crypto_aead *aead, u8 *iv)
  {
  	struct aead_request *req;
  
  	req = (void *)PTR_ALIGN(iv + crypto_aead_ivsize(aead),
  				crypto_tfm_ctx_alignment());
  	aead_request_set_tfm(req, aead);
  	return req;
  }
  
  static inline struct scatterlist *esp_req_sg(struct crypto_aead *aead,
  					     struct aead_request *req)
  {
  	return (void *)ALIGN((unsigned long)(req + 1) +
  			     crypto_aead_reqsize(aead),
  			     __alignof__(struct scatterlist));
  }
  
  static inline struct scatterlist *esp_givreq_sg(
  	struct crypto_aead *aead, struct aead_givcrypt_request *req)
  {
  	return (void *)ALIGN((unsigned long)(req + 1) +
  			     crypto_aead_reqsize(aead),
  			     __alignof__(struct scatterlist));
  }
  
  static void esp_output_done(struct crypto_async_request *base, int err)
  {
  	struct sk_buff *skb = base->data;
  
  	kfree(ESP_SKB_CB(skb)->tmp);
  	xfrm_output_resume(skb, err);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
135
136
  static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
  {
  	int err;
87bdc48d3   Herbert Xu   [IPSEC]: Get rid ...
137
  	struct ip_esp_hdr *esph;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
138
139
140
141
  	struct crypto_aead *aead;
  	struct aead_givcrypt_request *req;
  	struct scatterlist *sg;
  	struct scatterlist *asg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
  	struct sk_buff *trailer;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
143
  	void *tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
146
  	int blksize;
  	int clen;
  	int alen;
040253c93   Martin Willi   xfrm: Traffic Flo...
147
148
  	int plen;
  	int tfclen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
  	int nfrags;
d212a4c29   Steffen Klassert   esp6: Add support...
150
151
152
  	int assoclen;
  	int sglists;
  	int seqhilen;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
153
  	u8 *iv;
27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
154
  	u8 *tail;
d212a4c29   Steffen Klassert   esp6: Add support...
155
  	__be32 *seqhi;
ea2ae17d6   Arnaldo Carvalho de Melo   [SK_BUFF]: Introd...
156
  	struct esp_data *esp = x->data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157

7b277b1a5   Herbert Xu   [IPSEC]: Set skb-...
158
  	/* skb is pure payload to encrypt */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
  	err = -ENOMEM;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
160
161
  	aead = esp->aead;
  	alen = crypto_aead_authsize(aead);
040253c93   Martin Willi   xfrm: Traffic Flo...
162
163
164
165
166
167
168
169
170
  	tfclen = 0;
  	if (x->tfcpad) {
  		struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb);
  		u32 padto;
  
  		padto = min(x->tfcpad, esp6_get_mtu(x, dst->child_mtu_cached));
  		if (skb->len < padto)
  			tfclen = padto - skb->len;
  	}
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
171
  	blksize = ALIGN(crypto_aead_blocksize(aead), 4);
040253c93   Martin Willi   xfrm: Traffic Flo...
172
  	clen = ALIGN(skb->len + 2 + tfclen, blksize);
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
173
174
  	if (esp->padlen)
  		clen = ALIGN(clen, esp->padlen);
040253c93   Martin Willi   xfrm: Traffic Flo...
175
  	plen = clen - skb->len - tfclen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176

040253c93   Martin Willi   xfrm: Traffic Flo...
177
178
  	err = skb_cow_data(skb, tfclen + plen + alen, &trailer);
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
  		goto error;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
180
  	nfrags = err;
d212a4c29   Steffen Klassert   esp6: Add support...
181
182
183
184
185
186
187
188
189
190
191
  	assoclen = sizeof(*esph);
  	sglists = 1;
  	seqhilen = 0;
  
  	if (x->props.flags & XFRM_STATE_ESN) {
  		sglists += 2;
  		seqhilen += sizeof(__be32);
  		assoclen += seqhilen;
  	}
  
  	tmp = esp_alloc_tmp(aead, nfrags + sglists, seqhilen);
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
192
193
  	if (!tmp)
  		goto error;
d212a4c29   Steffen Klassert   esp6: Add support...
194
195
  	seqhi = esp_tmp_seqhi(tmp);
  	iv = esp_tmp_iv(aead, tmp, seqhilen);
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
196
197
  	req = esp_tmp_givreq(aead, iv);
  	asg = esp_givreq_sg(aead, req);
d212a4c29   Steffen Klassert   esp6: Add support...
198
  	sg = asg + sglists;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
200
  
  	/* Fill padding... */
27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
201
  	tail = skb_tail_pointer(trailer);
040253c93   Martin Willi   xfrm: Traffic Flo...
202
203
204
205
  	if (tfclen) {
  		memset(tail, 0, tfclen);
  		tail += tfclen;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206
207
  	do {
  		int i;
040253c93   Martin Willi   xfrm: Traffic Flo...
208
  		for (i = 0; i < plen - 2; i++)
27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
209
  			tail[i] = i + 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
  	} while (0);
040253c93   Martin Willi   xfrm: Traffic Flo...
211
212
  	tail[plen - 2] = plen - 2;
  	tail[plen - 1] = *skb_mac_header(skb);
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
213
  	pskb_put(skb, trailer, clen - skb->len + alen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214

7b277b1a5   Herbert Xu   [IPSEC]: Set skb-...
215
  	skb_push(skb, -skb_network_offset(skb));
87bdc48d3   Herbert Xu   [IPSEC]: Get rid ...
216
  	esph = ip_esp_hdr(skb);
007f0211a   Herbert Xu   [IPSEC]: Store IP...
217
  	*skb_mac_header(skb) = IPPROTO_ESP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
219
  
  	esph->spi = x->id.spi;
1ce3644ad   Steffen Klassert   xfrm: Use separat...
220
  	esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221

38320c70d   Herbert Xu   [IPSEC]: Use cryp...
222
223
224
225
  	sg_init_table(sg, nfrags);
  	skb_to_sgvec(skb, sg,
  		     esph->enc_data + crypto_aead_ivsize(aead) - skb->data,
  		     clen + alen);
d212a4c29   Steffen Klassert   esp6: Add support...
226
227
228
229
230
231
232
233
234
  
  	if ((x->props.flags & XFRM_STATE_ESN)) {
  		sg_init_table(asg, 3);
  		sg_set_buf(asg, &esph->spi, sizeof(__be32));
  		*seqhi = htonl(XFRM_SKB_CB(skb)->seq.output.hi);
  		sg_set_buf(asg + 1, seqhi, seqhilen);
  		sg_set_buf(asg + 2, &esph->seq_no, sizeof(__be32));
  	} else
  		sg_init_one(asg, esph, sizeof(*esph));
b7c6538cd   Herbert Xu   [IPSEC]: Move sta...
235

38320c70d   Herbert Xu   [IPSEC]: Use cryp...
236
237
  	aead_givcrypt_set_callback(req, 0, esp_output_done, skb);
  	aead_givcrypt_set_crypt(req, sg, sg, clen, iv);
d212a4c29   Steffen Klassert   esp6: Add support...
238
  	aead_givcrypt_set_assoc(req, asg, assoclen);
b318e0e4e   Herbert Xu   [IPSEC]: Fix bogu...
239
  	aead_givcrypt_set_giv(req, esph->enc_data,
1ce3644ad   Steffen Klassert   xfrm: Use separat...
240
  			      XFRM_SKB_CB(skb)->seq.output.low);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241

38320c70d   Herbert Xu   [IPSEC]: Use cryp...
242
243
244
245
  	ESP_SKB_CB(skb)->tmp = tmp;
  	err = crypto_aead_givencrypt(req);
  	if (err == -EINPROGRESS)
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246

38320c70d   Herbert Xu   [IPSEC]: Use cryp...
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
  	if (err == -EBUSY)
  		err = NET_XMIT_DROP;
  
  	kfree(tmp);
  
  error:
  	return err;
  }
  
  static int esp_input_done2(struct sk_buff *skb, int err)
  {
  	struct xfrm_state *x = xfrm_input_state(skb);
  	struct esp_data *esp = x->data;
  	struct crypto_aead *aead = esp->aead;
  	int alen = crypto_aead_authsize(aead);
  	int hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead);
  	int elen = skb->len - hlen;
  	int hdr_len = skb_network_header_len(skb);
  	int padlen;
  	u8 nexthdr[2];
  
  	kfree(ESP_SKB_CB(skb)->tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269

6b7326c84   Herbert Xu   [IPSEC] ESP: Use ...
270
  	if (unlikely(err))
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
271
  		goto out;
6b7326c84   Herbert Xu   [IPSEC] ESP: Use ...
272

38320c70d   Herbert Xu   [IPSEC]: Use cryp...
273
274
  	if (skb_copy_bits(skb, skb->len - alen - 2, nexthdr, 2))
  		BUG();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275

38320c70d   Herbert Xu   [IPSEC]: Use cryp...
276
277
278
279
280
281
282
  	err = -EINVAL;
  	padlen = nexthdr[0];
  	if (padlen + 2 + alen >= elen) {
  		LIMIT_NETDEBUG(KERN_WARNING "ipsec esp packet is garbage "
  			       "padlen=%d, elen=%d
  ", padlen + 2, elen - alen);
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
  	}
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
284
  	/* ... check padding bits here. Silly. :-) */
b7c6538cd   Herbert Xu   [IPSEC]: Move sta...
285

38320c70d   Herbert Xu   [IPSEC]: Use cryp...
286
287
288
289
290
291
292
293
294
295
296
  	pskb_trim(skb, skb->len - alen - padlen - 2);
  	__skb_pull(skb, hlen);
  	skb_set_transport_header(skb, -hdr_len);
  
  	err = nexthdr[1];
  
  	/* RFC4303: Drop dummy packets without any error */
  	if (err == IPPROTO_NONE)
  		err = -EINVAL;
  
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
298
  	return err;
  }
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
299
300
301
302
303
304
  static void esp_input_done(struct crypto_async_request *base, int err)
  {
  	struct sk_buff *skb = base->data;
  
  	xfrm_input_resume(skb, esp_input_done2(skb, err));
  }
e695633e2   Herbert Xu   [IPSEC]: Kill unu...
305
  static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
  {
87bdc48d3   Herbert Xu   [IPSEC]: Get rid ...
307
  	struct ip_esp_hdr *esph;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
  	struct esp_data *esp = x->data;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
309
310
  	struct crypto_aead *aead = esp->aead;
  	struct aead_request *req;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
  	struct sk_buff *trailer;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
312
  	int elen = skb->len - sizeof(*esph) - crypto_aead_ivsize(aead);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
  	int nfrags;
d212a4c29   Steffen Klassert   esp6: Add support...
314
315
316
  	int assoclen;
  	int sglists;
  	int seqhilen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
  	int ret = 0;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
318
  	void *tmp;
d212a4c29   Steffen Klassert   esp6: Add support...
319
  	__be32 *seqhi;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
320
321
322
  	u8 *iv;
  	struct scatterlist *sg;
  	struct scatterlist *asg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323

920fc941a   Thomas Graf   [ESP]: Ensure IV ...
324
  	if (!pskb_may_pull(skb, sizeof(*esph) + crypto_aead_ivsize(aead))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
  		ret = -EINVAL;
31a4ab930   Herbert Xu   [IPSEC] proto: Mo...
326
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
  	}
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
328
  	if (elen <= 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
  		ret = -EINVAL;
31a4ab930   Herbert Xu   [IPSEC] proto: Mo...
330
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332

0ebea8ef3   Herbert Xu   [IPSEC]: Move sta...
333
334
335
336
  	if ((nfrags = skb_cow_data(skb, 0, &trailer)) < 0) {
  		ret = -EINVAL;
  		goto out;
  	}
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
337
  	ret = -ENOMEM;
d212a4c29   Steffen Klassert   esp6: Add support...
338
339
340
341
342
343
344
345
346
347
348
349
  
  	assoclen = sizeof(*esph);
  	sglists = 1;
  	seqhilen = 0;
  
  	if (x->props.flags & XFRM_STATE_ESN) {
  		sglists += 2;
  		seqhilen += sizeof(__be32);
  		assoclen += seqhilen;
  	}
  
  	tmp = esp_alloc_tmp(aead, nfrags + sglists, seqhilen);
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
350
351
  	if (!tmp)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352

38320c70d   Herbert Xu   [IPSEC]: Use cryp...
353
  	ESP_SKB_CB(skb)->tmp = tmp;
d212a4c29   Steffen Klassert   esp6: Add support...
354
355
  	seqhi = esp_tmp_seqhi(tmp);
  	iv = esp_tmp_iv(aead, tmp, seqhilen);
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
356
357
  	req = esp_tmp_req(aead, iv);
  	asg = esp_req_sg(aead, req);
c0a56e64a   Steffen Klassert   esp6: Fix scatter...
358
  	sg = asg + sglists;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359

38320c70d   Herbert Xu   [IPSEC]: Use cryp...
360
  	skb->ip_summed = CHECKSUM_NONE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361

87bdc48d3   Herbert Xu   [IPSEC]: Get rid ...
362
  	esph = (struct ip_esp_hdr *)skb->data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
364
  
  	/* Get ivec. This can be wrong, check against another impls. */
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
365
  	iv = esph->enc_data;
0ebea8ef3   Herbert Xu   [IPSEC]: Move sta...
366

38320c70d   Herbert Xu   [IPSEC]: Use cryp...
367
368
  	sg_init_table(sg, nfrags);
  	skb_to_sgvec(skb, sg, sizeof(*esph) + crypto_aead_ivsize(aead), elen);
d212a4c29   Steffen Klassert   esp6: Add support...
369
370
371
372
373
374
375
376
377
  
  	if ((x->props.flags & XFRM_STATE_ESN)) {
  		sg_init_table(asg, 3);
  		sg_set_buf(asg, &esph->spi, sizeof(__be32));
  		*seqhi = XFRM_SKB_CB(skb)->seq.input.hi;
  		sg_set_buf(asg + 1, seqhi, seqhilen);
  		sg_set_buf(asg + 2, &esph->seq_no, sizeof(__be32));
  	} else
  		sg_init_one(asg, esph, sizeof(*esph));
0ebea8ef3   Herbert Xu   [IPSEC]: Move sta...
378

38320c70d   Herbert Xu   [IPSEC]: Use cryp...
379
380
  	aead_request_set_callback(req, 0, esp_input_done, skb);
  	aead_request_set_crypt(req, sg, sg, elen, iv);
d212a4c29   Steffen Klassert   esp6: Add support...
381
  	aead_request_set_assoc(req, asg, assoclen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382

38320c70d   Herbert Xu   [IPSEC]: Use cryp...
383
384
385
  	ret = crypto_aead_decrypt(req);
  	if (ret == -EINPROGRESS)
  		goto out;
95a02cfd4   Thomas Graf   [IPv6] ESP: Disca...
386

38320c70d   Herbert Xu   [IPSEC]: Use cryp...
387
  	ret = esp_input_done2(skb, ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
389
  
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
391
  	return ret;
  }
c5c252389   Patrick McHardy   [XFRM]: Optimize ...
392
  static u32 esp6_get_mtu(struct xfrm_state *x, int mtu)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
394
  {
  	struct esp_data *esp = x->data;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
395
396
  	u32 blksize = ALIGN(crypto_aead_blocksize(esp->aead), 4);
  	u32 align = max_t(u32, blksize, esp->padlen);
c5c252389   Patrick McHardy   [XFRM]: Optimize ...
397
  	u32 rem;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398

38320c70d   Herbert Xu   [IPSEC]: Use cryp...
399
  	mtu -= x->props.header_len + crypto_aead_authsize(esp->aead);
c5c252389   Patrick McHardy   [XFRM]: Optimize ...
400
401
402
403
  	rem = mtu & (align - 1);
  	mtu &= ~(align - 1);
  
  	if (x->props.mode != XFRM_MODE_TUNNEL) {
d4875b049   Herbert Xu   [IPSEC] Fix block...
404
  		u32 padsize = ((blksize - 1) & 7) + 1;
c5c252389   Patrick McHardy   [XFRM]: Optimize ...
405
406
  		mtu -= blksize - padsize;
  		mtu += min_t(u32, blksize - padsize, rem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408

c5c252389   Patrick McHardy   [XFRM]: Optimize ...
409
  	return mtu - 2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410
411
412
  }
  
  static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
d5fdd6bab   Brian Haley   ipv6: Use correct...
413
  		     u8 type, u8 code, int offset, __be32 info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
  {
4fb236bac   Alexey Dobriyan   netns xfrm: AH/ES...
415
  	struct net *net = dev_net(skb->dev);
b71d1d426   Eric Dumazet   inet: constify ip...
416
  	const struct ipv6hdr *iph = (const struct ipv6hdr *)skb->data;
87bdc48d3   Herbert Xu   [IPSEC]: Get rid ...
417
  	struct ip_esp_hdr *esph = (struct ip_esp_hdr *)(skb->data + offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
  	struct xfrm_state *x;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
419
  	if (type != ICMPV6_DEST_UNREACH &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
421
  	    type != ICMPV6_PKT_TOOBIG)
  		return;
b71d1d426   Eric Dumazet   inet: constify ip...
422
423
  	x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
  			      esph->spi, IPPROTO_ESP, AF_INET6);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
425
  	if (!x)
  		return;
5b095d989   Harvey Harrison   net: replace %p6 ...
426
427
  	printk(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%pI6
  ",
0c6ce78ab   Harvey Harrison   net: replace uses...
428
  			ntohl(esph->spi), &iph->daddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
430
431
432
433
434
435
436
437
  	xfrm_state_put(x);
  }
  
  static void esp6_destroy(struct xfrm_state *x)
  {
  	struct esp_data *esp = x->data;
  
  	if (!esp)
  		return;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
438
  	crypto_free_aead(esp->aead);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
  	kfree(esp);
  }
1a6509d99   Herbert Xu   [IPSEC]: Add supp...
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
  static int esp_init_aead(struct xfrm_state *x)
  {
  	struct esp_data *esp = x->data;
  	struct crypto_aead *aead;
  	int err;
  
  	aead = crypto_alloc_aead(x->aead->alg_name, 0, 0);
  	err = PTR_ERR(aead);
  	if (IS_ERR(aead))
  		goto error;
  
  	esp->aead = aead;
  
  	err = crypto_aead_setkey(aead, x->aead->alg_key,
  				 (x->aead->alg_key_len + 7) / 8);
  	if (err)
  		goto error;
  
  	err = crypto_aead_setauthsize(aead, x->aead->alg_icv_len / 8);
  	if (err)
  		goto error;
  
  error:
  	return err;
  }
  
  static int esp_init_authenc(struct xfrm_state *x)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
  {
1a6509d99   Herbert Xu   [IPSEC]: Add supp...
469
  	struct esp_data *esp = x->data;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
470
471
472
473
474
475
  	struct crypto_aead *aead;
  	struct crypto_authenc_key_param *param;
  	struct rtattr *rta;
  	char *key;
  	char *p;
  	char authenc_name[CRYPTO_MAX_ALG_NAME];
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
476
477
  	unsigned int keylen;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
478

1a6509d99   Herbert Xu   [IPSEC]: Add supp...
479
  	err = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
  	if (x->ealg == NULL)
1a6509d99   Herbert Xu   [IPSEC]: Add supp...
481
  		goto error;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
482

1a6509d99   Herbert Xu   [IPSEC]: Add supp...
483
  	err = -ENAMETOOLONG;
d212a4c29   Steffen Klassert   esp6: Add support...
484
485
486
487
488
489
490
491
492
493
494
495
496
497
  
  	if ((x->props.flags & XFRM_STATE_ESN)) {
  		if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME,
  			     "authencesn(%s,%s)",
  			     x->aalg ? x->aalg->alg_name : "digest_null",
  			     x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME)
  			goto error;
  	} else {
  		if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME,
  			     "authenc(%s,%s)",
  			     x->aalg ? x->aalg->alg_name : "digest_null",
  			     x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME)
  			goto error;
  	}
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
  
  	aead = crypto_alloc_aead(authenc_name, 0, 0);
  	err = PTR_ERR(aead);
  	if (IS_ERR(aead))
  		goto error;
  
  	esp->aead = aead;
  
  	keylen = (x->aalg ? (x->aalg->alg_key_len + 7) / 8 : 0) +
  		 (x->ealg->alg_key_len + 7) / 8 + RTA_SPACE(sizeof(*param));
  	err = -ENOMEM;
  	key = kmalloc(keylen, GFP_KERNEL);
  	if (!key)
  		goto error;
  
  	p = key;
  	rta = (void *)p;
  	rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM;
  	rta->rta_len = RTA_LENGTH(sizeof(*param));
  	param = RTA_DATA(rta);
  	p += RTA_SPACE(sizeof(*param));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
520
  	if (x->aalg) {
  		struct xfrm_algo_desc *aalg_desc;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
521
522
  		memcpy(p, x->aalg->alg_key, (x->aalg->alg_key_len + 7) / 8);
  		p += (x->aalg->alg_key_len + 7) / 8;
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
523

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
525
  		aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
  		BUG_ON(!aalg_desc);
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
526

38320c70d   Herbert Xu   [IPSEC]: Use cryp...
527
  		err = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528
  		if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
529
  		    crypto_aead_authsize(aead)) {
07d4ee583   Herbert Xu   [IPSEC]: Use HMAC...
530
531
532
  			NETDEBUG(KERN_INFO "ESP: %s digestsize %u != %hu
  ",
  				 x->aalg->alg_name,
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
533
  				 crypto_aead_authsize(aead),
07d4ee583   Herbert Xu   [IPSEC]: Use HMAC...
534
  				 aalg_desc->uinfo.auth.icv_fullbits/8);
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
535
  			goto free_key;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
  		}
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
537

38320c70d   Herbert Xu   [IPSEC]: Use cryp...
538
  		err = crypto_aead_setauthsize(
8f8a088c2   Martin Willi   xfrm: Use the use...
539
  			aead, x->aalg->alg_trunc_len / 8);
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
540
541
  		if (err)
  			goto free_key;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
  	}
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
543

38320c70d   Herbert Xu   [IPSEC]: Use cryp...
544
545
546
547
548
549
550
  	param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8);
  	memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8);
  
  	err = crypto_aead_setkey(aead, key, keylen);
  
  free_key:
  	kfree(key);
1a6509d99   Herbert Xu   [IPSEC]: Add supp...
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
  error:
  	return err;
  }
  
  static int esp6_init_state(struct xfrm_state *x)
  {
  	struct esp_data *esp;
  	struct crypto_aead *aead;
  	u32 align;
  	int err;
  
  	if (x->encap)
  		return -EINVAL;
  
  	esp = kzalloc(sizeof(*esp), GFP_KERNEL);
  	if (esp == NULL)
  		return -ENOMEM;
  
  	x->data = esp;
  
  	if (x->aead)
  		err = esp_init_aead(x);
  	else
  		err = esp_init_authenc(x);
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
575
  	if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576
  		goto error;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
577

1a6509d99   Herbert Xu   [IPSEC]: Add supp...
578
579
580
  	aead = esp->aead;
  
  	esp->padlen = 0;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
581
582
  	x->props.header_len = sizeof(struct ip_esp_hdr) +
  			      crypto_aead_ivsize(aead);
ca68145f1   Herbert Xu   [IPSEC]: Disallow...
583
584
  	switch (x->props.mode) {
  	case XFRM_MODE_BEET:
abf5cdb89   Joakim Koskela   ipsec: Interfamil...
585
586
587
588
  		if (x->sel.family != AF_INET6)
  			x->props.header_len += IPV4_BEET_PHMAXLEN +
  				               (sizeof(struct ipv6hdr) - sizeof(struct iphdr));
  		break;
ca68145f1   Herbert Xu   [IPSEC]: Disallow...
589
590
591
  	case XFRM_MODE_TRANSPORT:
  		break;
  	case XFRM_MODE_TUNNEL:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
  		x->props.header_len += sizeof(struct ipv6hdr);
ea2c47b42   Masahide NAKAMURA   [IPSEC] IPV6: Fix...
593
  		break;
ca68145f1   Herbert Xu   [IPSEC]: Disallow...
594
595
596
  	default:
  		goto error;
  	}
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
597
598
599
600
601
  
  	align = ALIGN(crypto_aead_blocksize(aead), 4);
  	if (esp->padlen)
  		align = max_t(u32, align, esp->padlen);
  	x->props.trailer_len = align + 1 + crypto_aead_authsize(esp->aead);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
603
  
  error:
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
604
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
605
  }
533cb5b0a   Eric Dumazet   [XFRM]: constify ...
606
  static const struct xfrm_type esp6_type =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
607
608
609
610
  {
  	.description	= "ESP6",
  	.owner	     	= THIS_MODULE,
  	.proto	     	= IPPROTO_ESP,
436a0a402   Herbert Xu   [IPSEC]: Move out...
611
  	.flags		= XFRM_TYPE_REPLAY_PROT,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
612
613
  	.init_state	= esp6_init_state,
  	.destructor	= esp6_destroy,
c5c252389   Patrick McHardy   [XFRM]: Optimize ...
614
  	.get_mtu	= esp6_get_mtu,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
615
  	.input		= esp6_input,
aee5adb43   Masahide NAKAMURA   [XFRM] STATE: Add...
616
617
  	.output		= esp6_output,
  	.hdr_offset	= xfrm6_find_1stfragopt,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
618
  };
41135cc83   Alexey Dobriyan   net: constify str...
619
  static const struct inet6_protocol esp6_protocol = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
  	.handler 	=	xfrm6_rcv,
  	.err_handler	=	esp6_err,
  	.flags		=	INET6_PROTO_NOPOLICY,
  };
  
  static int __init esp6_init(void)
  {
  	if (xfrm_register_type(&esp6_type, AF_INET6) < 0) {
  		printk(KERN_INFO "ipv6 esp init: can't add xfrm type
  ");
  		return -EAGAIN;
  	}
  	if (inet6_add_protocol(&esp6_protocol, IPPROTO_ESP) < 0) {
  		printk(KERN_INFO "ipv6 esp init: can't add protocol
  ");
  		xfrm_unregister_type(&esp6_type, AF_INET6);
  		return -EAGAIN;
  	}
  
  	return 0;
  }
  
  static void __exit esp6_fini(void)
  {
  	if (inet6_del_protocol(&esp6_protocol, IPPROTO_ESP) < 0)
  		printk(KERN_INFO "ipv6 esp close: can't remove protocol
  ");
  	if (xfrm_unregister_type(&esp6_type, AF_INET6) < 0)
  		printk(KERN_INFO "ipv6 esp close: can't remove xfrm type
  ");
  }
  
  module_init(esp6_init);
  module_exit(esp6_fini);
  
  MODULE_LICENSE("GPL");
d3d6dd3ad   Masahide NAKAMURA   [XFRM]: Add modul...
656
  MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_ESP);