Blame view

net/ipv6/esp6.c 21.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
   * You should have received a copy of the GNU General Public License
a99421d9b   Jeff Kirsher   ipv4/ipv6: Fix FS...
15
   * along with this program; if not, see <http://www.gnu.org/licenses/>.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
18
   *
   * Authors
   *
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
19
   *	Mitsuru KANDA @USAGI       : IPv6 Support
67ba4152e   Ian Morris   ipv6: White-space...
20
21
   *	Kazunori MIYAZAWA @USAGI   :
   *	Kunihiro Ishiguro <kunihiro@ipinfusion.com>
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
22
   *
67ba4152e   Ian Morris   ipv6: White-space...
23
   *	This file is derived from net/ipv4/esp.c
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
   */
f32138319   Joe Perches   net: ipv6: Standa...
25
  #define pr_fmt(fmt) "IPv6: " fmt
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>
81aded246   David S. Miller   ipv6: Handle PMTU...
39
  #include <net/ip6_route.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
  #include <net/icmp.h>
  #include <net/ipv6.h>
14c850212   Arnaldo Carvalho de Melo   [INET_SOCK]: Move...
42
  #include <net/protocol.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
  #include <linux/icmpv6.h>
03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
44
  #include <linux/highmem.h>
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
45
46
47
48
49
50
  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...
51
  static u32 esp6_get_mtu(struct xfrm_state *x, int mtu);
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
52
53
54
  /*
   * Allocate an AEAD request structure with extra space for SG and IV.
   *
d212a4c29   Steffen Klassert   esp6: Add support...
55
56
57
   * 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...
58
59
60
   *
   * TODO: Use spare space in skb for this where possible.
   */
d212a4c29   Steffen Klassert   esp6: Add support...
61
  static void *esp_alloc_tmp(struct crypto_aead *aead, int nfrags, int seqihlen)
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
62
63
  {
  	unsigned int len;
d212a4c29   Steffen Klassert   esp6: Add support...
64
65
66
  	len = seqihlen;
  
  	len += crypto_aead_ivsize(aead);
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
67
68
69
70
71
  	if (len) {
  		len += crypto_aead_alignmask(aead) &
  		       ~(crypto_tfm_ctx_alignment() - 1);
  		len = ALIGN(len, crypto_tfm_ctx_alignment());
  	}
000ae7b26   Herbert Xu   esp6: Switch to n...
72
  	len += sizeof(struct aead_request) + crypto_aead_reqsize(aead);
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
73
74
75
76
77
78
  	len = ALIGN(len, __alignof__(struct scatterlist));
  
  	len += sizeof(struct scatterlist) * nfrags;
  
  	return kmalloc(len, GFP_ATOMIC);
  }
d212a4c29   Steffen Klassert   esp6: Add support...
79
80
81
82
83
84
  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...
85
86
  {
  	return crypto_aead_ivsize(aead) ?
d212a4c29   Steffen Klassert   esp6: Add support...
87
88
  	       PTR_ALIGN((u8 *)tmp + seqhilen,
  			 crypto_aead_alignmask(aead) + 1) : tmp + seqhilen;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
89
  }
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
  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));
  }
03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
107
108
  static void esp_ssg_unref(struct xfrm_state *x, void *tmp)
  {
03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
109
110
111
112
113
114
115
116
  	struct crypto_aead *aead = x->data;
  	int seqhilen = 0;
  	u8 *iv;
  	struct aead_request *req;
  	struct scatterlist *sg;
  
  	if (x->props.flags & XFRM_STATE_ESN)
  		seqhilen += sizeof(__be32);
03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
117
118
119
120
121
122
123
124
125
126
  	iv = esp_tmp_iv(aead, tmp, seqhilen);
  	req = esp_tmp_req(aead, iv);
  
  	/* Unref skb_frag_pages in the src scatterlist if necessary.
  	 * Skip the first sg which comes from skb->data.
  	 */
  	if (req->src != req->dst)
  		for (sg = sg_next(req->src); sg; sg = sg_next(sg))
  			put_page(sg_page(sg));
  }
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
127
128
129
  static void esp_output_done(struct crypto_async_request *base, int err)
  {
  	struct sk_buff *skb = base->data;
03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
130
131
132
  	void *tmp;
  	struct dst_entry *dst = skb_dst(skb);
  	struct xfrm_state *x = dst->xfrm;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
133

03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
134
135
136
  	tmp = ESP_SKB_CB(skb)->tmp;
  	esp_ssg_unref(x, tmp);
  	kfree(tmp);
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
137
138
  	xfrm_output_resume(skb, err);
  }
000ae7b26   Herbert Xu   esp6: Switch to n...
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
  /* Move ESP header back into place. */
  static void esp_restore_header(struct sk_buff *skb, unsigned int offset)
  {
  	struct ip_esp_hdr *esph = (void *)(skb->data + offset);
  	void *tmp = ESP_SKB_CB(skb)->tmp;
  	__be32 *seqhi = esp_tmp_seqhi(tmp);
  
  	esph->seq_no = esph->spi;
  	esph->spi = *seqhi;
  }
  
  static void esp_output_restore_header(struct sk_buff *skb)
  {
  	esp_restore_header(skb, skb_transport_offset(skb) - sizeof(__be32));
  }
03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
154
  static struct ip_esp_hdr *esp_output_set_esn(struct sk_buff *skb,
383d0350f   Steffen Klassert   esp6: Reorganize ...
155
  					     struct xfrm_state *x,
03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
156
157
158
  					     struct ip_esp_hdr *esph,
  					     __be32 *seqhi)
  {
03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
159
160
161
162
163
  	/* For ESN we move the header forward by 4 bytes to
  	 * accomodate the high bits.  We will move it back after
  	 * encryption.
  	 */
  	if ((x->props.flags & XFRM_STATE_ESN)) {
7862b4058   Steffen Klassert   esp: Add gso hand...
164
  		struct xfrm_offload *xo = xfrm_offload(skb);
03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
165
166
  		esph = (void *)(skb_transport_header(skb) - sizeof(__be32));
  		*seqhi = esph->spi;
7862b4058   Steffen Klassert   esp: Add gso hand...
167
168
169
170
  		if (xo)
  			esph->seq_no = htonl(xo->seq.hi);
  		else
  			esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.hi);
03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
171
172
173
174
175
176
  	}
  
  	esph->spi = x->id.spi;
  
  	return esph;
  }
000ae7b26   Herbert Xu   esp6: Switch to n...
177
178
179
180
181
182
183
  static void esp_output_done_esn(struct crypto_async_request *base, int err)
  {
  	struct sk_buff *skb = base->data;
  
  	esp_output_restore_header(skb);
  	esp_output_done(base, err);
  }
eb758c886   Steffen Klassert   esp: Introduce a ...
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
  static void esp_output_fill_trailer(u8 *tail, int tfclen, int plen, __u8 proto)
  {
  	/* Fill padding... */
  	if (tfclen) {
  		memset(tail, 0, tfclen);
  		tail += tfclen;
  	}
  	do {
  		int i;
  		for (i = 0; i < plen - 2; i++)
  			tail[i] = i + 1;
  	} while (0);
  	tail[plen - 2] = plen - 2;
  	tail[plen - 1] = proto;
  }
383d0350f   Steffen Klassert   esp6: Reorganize ...
199
  int esp6_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *esp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
  {
27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
201
  	u8 *tail;
03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
202
  	u8 *vaddr;
383d0350f   Steffen Klassert   esp6: Reorganize ...
203
204
  	int nfrags;
  	struct page *page;
383d0350f   Steffen Klassert   esp6: Reorganize ...
205
206
  	struct sk_buff *trailer;
  	int tailen = esp->tailen;
d212a4c29   Steffen Klassert   esp6: Add support...
207

03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
208
  	if (!skb_cloned(skb)) {
54ffd7907   Steffen Klassert   esp: Fix skb tail...
209
  		if (tailen <= skb_tailroom(skb)) {
03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
210
211
212
213
214
215
216
217
218
219
  			nfrags = 1;
  			trailer = skb;
  			tail = skb_tail_pointer(trailer);
  
  			goto skip_cow;
  		} else if ((skb_shinfo(skb)->nr_frags < MAX_SKB_FRAGS)
  			   && !skb_has_frag_list(skb)) {
  			int allocsize;
  			struct sock *sk = skb->sk;
  			struct page_frag *pfrag = &x->xfrag;
383d0350f   Steffen Klassert   esp6: Reorganize ...
220
  			esp->inplace = false;
03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
  			allocsize = ALIGN(tailen, L1_CACHE_BYTES);
  
  			spin_lock_bh(&x->lock);
  
  			if (unlikely(!skb_page_frag_refill(allocsize, pfrag, GFP_ATOMIC))) {
  				spin_unlock_bh(&x->lock);
  				goto cow;
  			}
  
  			page = pfrag->page;
  			get_page(page);
  
  			vaddr = kmap_atomic(page);
  
  			tail = vaddr + pfrag->offset;
383d0350f   Steffen Klassert   esp6: Reorganize ...
236
  			esp_output_fill_trailer(tail, esp->tfclen, esp->plen, esp->proto);
03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
237
238
239
240
241
242
243
244
245
246
  
  			kunmap_atomic(vaddr);
  
  			nfrags = skb_shinfo(skb)->nr_frags;
  
  			__skb_fill_page_desc(skb, nfrags, page, pfrag->offset,
  					     tailen);
  			skb_shinfo(skb)->nr_frags = ++nfrags;
  
  			pfrag->offset = pfrag->offset + allocsize;
36ff0dd39   Steffen Klassert   esp: Fix locking ...
247
248
  
  			spin_unlock_bh(&x->lock);
03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
249
250
251
252
253
254
  			nfrags++;
  
  			skb->len += tailen;
  			skb->data_len += tailen;
  			skb->truesize += tailen;
  			if (sk)
14afee4b6   Reshetova, Elena   net: convert sock...
255
  				refcount_add(tailen, &sk->sk_wmem_alloc);
03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
256

383d0350f   Steffen Klassert   esp6: Reorganize ...
257
  			goto out;
03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
258
  		}
48f125ce1   Julia Lawall   net: ipv6: fix er...
259
  	}
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
260

03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
261
  cow:
383d0350f   Steffen Klassert   esp6: Reorganize ...
262
263
264
  	nfrags = skb_cow_data(skb, tailen, &trailer);
  	if (nfrags < 0)
  		goto out;
27a884dc3   Arnaldo Carvalho de Melo   [SK_BUFF]: Conver...
265
  	tail = skb_tail_pointer(trailer);
03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
266
267
  
  skip_cow:
383d0350f   Steffen Klassert   esp6: Reorganize ...
268
269
  	esp_output_fill_trailer(tail, esp->tfclen, esp->plen, esp->proto);
  	pskb_put(skb, trailer, tailen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270

383d0350f   Steffen Klassert   esp6: Reorganize ...
271
272
273
274
  out:
  	return nfrags;
  }
  EXPORT_SYMBOL_GPL(esp6_output_head);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275

383d0350f   Steffen Klassert   esp6: Reorganize ...
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
  int esp6_output_tail(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *esp)
  {
  	u8 *iv;
  	int alen;
  	void *tmp;
  	int ivlen;
  	int assoclen;
  	int seqhilen;
  	__be32 *seqhi;
  	struct page *page;
  	struct ip_esp_hdr *esph;
  	struct aead_request *req;
  	struct crypto_aead *aead;
  	struct scatterlist *sg, *dsg;
  	int err = -ENOMEM;
  
  	assoclen = sizeof(struct ip_esp_hdr);
  	seqhilen = 0;
  
  	if (x->props.flags & XFRM_STATE_ESN) {
  		seqhilen += sizeof(__be32);
  		assoclen += sizeof(__be32);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299

383d0350f   Steffen Klassert   esp6: Reorganize ...
300
301
302
303
304
  	aead = x->data;
  	alen = crypto_aead_authsize(aead);
  	ivlen = crypto_aead_ivsize(aead);
  
  	tmp = esp_alloc_tmp(aead, esp->nfrags + 2, seqhilen);
e892d2d40   Steffen Klassert   esp: Fix misplace...
305
  	if (!tmp)
03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
306
  		goto error;
000ae7b26   Herbert Xu   esp6: Switch to n...
307

03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
308
309
310
311
  	seqhi = esp_tmp_seqhi(tmp);
  	iv = esp_tmp_iv(aead, tmp, seqhilen);
  	req = esp_tmp_req(aead, iv);
  	sg = esp_req_sg(aead, req);
03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
312

383d0350f   Steffen Klassert   esp6: Reorganize ...
313
314
315
316
317
318
  	if (esp->inplace)
  		dsg = sg;
  	else
  		dsg = &sg[esp->nfrags];
  
  	esph = esp_output_set_esn(skb, x, ip_esp_hdr(skb), seqhi);
000ae7b26   Herbert Xu   esp6: Switch to n...
319

383d0350f   Steffen Klassert   esp6: Reorganize ...
320
  	sg_init_table(sg, esp->nfrags);
3f2977072   Jason A. Donenfeld   ipsec: check retu...
321
322
323
324
  	err = skb_to_sgvec(skb, sg,
  		           (unsigned char *)esph - skb->data,
  		           assoclen + ivlen + esp->clen + alen);
  	if (unlikely(err < 0))
e61949232   Steffen Klassert   esp: Fix memleaks...
325
  		goto error_free;
383d0350f   Steffen Klassert   esp6: Reorganize ...
326
327
328
329
330
331
332
333
334
335
  
  	if (!esp->inplace) {
  		int allocsize;
  		struct page_frag *pfrag = &x->xfrag;
  
  		allocsize = ALIGN(skb->data_len, L1_CACHE_BYTES);
  
  		spin_lock_bh(&x->lock);
  		if (unlikely(!skb_page_frag_refill(allocsize, pfrag, GFP_ATOMIC))) {
  			spin_unlock_bh(&x->lock);
e61949232   Steffen Klassert   esp: Fix memleaks...
336
  			goto error_free;
383d0350f   Steffen Klassert   esp6: Reorganize ...
337
338
339
340
341
342
343
344
345
346
347
348
  		}
  
  		skb_shinfo(skb)->nr_frags = 1;
  
  		page = pfrag->page;
  		get_page(page);
  		/* replace page frags in skb with new page */
  		__skb_fill_page_desc(skb, 0, page, pfrag->offset, skb->data_len);
  		pfrag->offset = pfrag->offset + allocsize;
  		spin_unlock_bh(&x->lock);
  
  		sg_init_table(dsg, skb_shinfo(skb)->nr_frags + 1);
3f2977072   Jason A. Donenfeld   ipsec: check retu...
349
350
351
352
  		err = skb_to_sgvec(skb, dsg,
  			           (unsigned char *)esph - skb->data,
  			           assoclen + ivlen + esp->clen + alen);
  		if (unlikely(err < 0))
e61949232   Steffen Klassert   esp: Fix memleaks...
353
  			goto error_free;
383d0350f   Steffen Klassert   esp6: Reorganize ...
354
  	}
d212a4c29   Steffen Klassert   esp6: Add support...
355

03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
356
357
358
359
  	if ((x->props.flags & XFRM_STATE_ESN))
  		aead_request_set_callback(req, 0, esp_output_done_esn, skb);
  	else
  		aead_request_set_callback(req, 0, esp_output_done, skb);
383d0350f   Steffen Klassert   esp6: Reorganize ...
360
  	aead_request_set_crypt(req, sg, dsg, ivlen + esp->clen, iv);
000ae7b26   Herbert Xu   esp6: Switch to n...
361
  	aead_request_set_ad(req, assoclen);
000ae7b26   Herbert Xu   esp6: Switch to n...
362
  	memset(iv, 0, ivlen);
383d0350f   Steffen Klassert   esp6: Reorganize ...
363
  	memcpy(iv + ivlen - min(ivlen, 8), (u8 *)&esp->seqno + 8 - min(ivlen, 8),
000ae7b26   Herbert Xu   esp6: Switch to n...
364
  	       min(ivlen, 8));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365

38320c70d   Herbert Xu   [IPSEC]: Use cryp...
366
  	ESP_SKB_CB(skb)->tmp = tmp;
000ae7b26   Herbert Xu   esp6: Switch to n...
367
368
369
370
  	err = crypto_aead_encrypt(req);
  
  	switch (err) {
  	case -EINPROGRESS:
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
371
  		goto error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372

000ae7b26   Herbert Xu   esp6: Switch to n...
373
  	case -EBUSY:
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
374
  		err = NET_XMIT_DROP;
000ae7b26   Herbert Xu   esp6: Switch to n...
375
376
377
378
379
380
  		break;
  
  	case 0:
  		if ((x->props.flags & XFRM_STATE_ESN))
  			esp_output_restore_header(skb);
  	}
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
381

03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
382
383
  	if (sg != dsg)
  		esp_ssg_unref(x, tmp);
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
384

e61949232   Steffen Klassert   esp: Fix memleaks...
385
386
  error_free:
  	kfree(tmp);
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
387
388
389
  error:
  	return err;
  }
383d0350f   Steffen Klassert   esp6: Reorganize ...
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
  EXPORT_SYMBOL_GPL(esp6_output_tail);
  
  static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
  {
  	int alen;
  	int blksize;
  	struct ip_esp_hdr *esph;
  	struct crypto_aead *aead;
  	struct esp_info esp;
  
  	esp.inplace = true;
  
  	esp.proto = *skb_mac_header(skb);
  	*skb_mac_header(skb) = IPPROTO_ESP;
  
  	/* skb is pure payload to encrypt */
  
  	aead = x->data;
  	alen = crypto_aead_authsize(aead);
  
  	esp.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)
  			esp.tfclen = padto - skb->len;
  	}
  	blksize = ALIGN(crypto_aead_blocksize(aead), 4);
  	esp.clen = ALIGN(skb->len + 2 + esp.tfclen, blksize);
  	esp.plen = esp.clen - skb->len - esp.tfclen;
  	esp.tailen = esp.tfclen + esp.plen + alen;
  
  	esp.nfrags = esp6_output_head(x, skb, &esp);
  	if (esp.nfrags < 0)
  		return esp.nfrags;
  
  	esph = ip_esp_hdr(skb);
  	esph->spi = x->id.spi;
  
  	esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low);
  	esp.seqno = cpu_to_be64(XFRM_SKB_CB(skb)->seq.output.low +
  			    ((u64)XFRM_SKB_CB(skb)->seq.output.hi << 32));
  
  	skb_push(skb, -skb_network_offset(skb));
  
  	return esp6_output_tail(x, skb, &esp);
  }
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
439

47ebcc0bb   Yossi Kuperman   xfrm: Add support...
440
  static inline int esp_remove_trailer(struct sk_buff *skb)
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
441
442
  {
  	struct xfrm_state *x = xfrm_input_state(skb);
d77e38e61   Steffen Klassert   xfrm: Add an IPse...
443
  	struct xfrm_offload *xo = xfrm_offload(skb);
1c5ad13f7   Mathias Krause   net: esp{4,6}: ge...
444
  	struct crypto_aead *aead = x->data;
47ebcc0bb   Yossi Kuperman   xfrm: Add support...
445
  	int alen, hlen, elen;
e51a64727   Ilan Tayari   esp6: Support RX ...
446
447
  	int padlen, trimlen;
  	__wsum csumdiff;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
448
  	u8 nexthdr[2];
47ebcc0bb   Yossi Kuperman   xfrm: Add support...
449
  	int ret;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
450

47ebcc0bb   Yossi Kuperman   xfrm: Add support...
451
452
453
  	alen = crypto_aead_authsize(aead);
  	hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead);
  	elen = skb->len - hlen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454

47ebcc0bb   Yossi Kuperman   xfrm: Add support...
455
456
  	if (xo && (xo->flags & XFRM_ESP_NO_TRAILER)) {
  		ret = xo->proto;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
457
  		goto out;
47ebcc0bb   Yossi Kuperman   xfrm: Add support...
458
  	}
6b7326c84   Herbert Xu   [IPSEC] ESP: Use ...
459

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

47ebcc0bb   Yossi Kuperman   xfrm: Add support...
463
  	ret = -EINVAL;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
464
465
  	padlen = nexthdr[0];
  	if (padlen + 2 + alen >= elen) {
ba7a46f16   Joe Perches   net: Convert LIMI...
466
467
468
  		net_dbg_ratelimited("ipsec esp packet is garbage padlen=%d, elen=%d
  ",
  				    padlen + 2, elen - alen);
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
469
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
  	}
e51a64727   Ilan Tayari   esp6: Support RX ...
471
472
473
474
475
476
477
  	trimlen = alen + padlen + 2;
  	if (skb->ip_summed == CHECKSUM_COMPLETE) {
  		csumdiff = skb_checksum(skb, skb->len - trimlen, trimlen, 0);
  		skb->csum = csum_block_sub(skb->csum, csumdiff,
  					   skb->len - trimlen);
  	}
  	pskb_trim(skb, skb->len - trimlen);
47ebcc0bb   Yossi Kuperman   xfrm: Add support...
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
  	ret = nexthdr[1];
  
  out:
  	return ret;
  }
  
  int esp6_input_done2(struct sk_buff *skb, int err)
  {
  	struct xfrm_state *x = xfrm_input_state(skb);
  	struct xfrm_offload *xo = xfrm_offload(skb);
  	struct crypto_aead *aead = x->data;
  	int hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead);
  	int hdr_len = skb_network_header_len(skb);
  
  	if (!xo || (xo && !(xo->flags & CRYPTO_DONE)))
  		kfree(ESP_SKB_CB(skb)->tmp);
  
  	if (unlikely(err))
  		goto out;
  
  	err = esp_remove_trailer(skb);
  	if (unlikely(err < 0))
  		goto out;
  
  	skb_postpull_rcsum(skb, skb_network_header(skb),
  			   skb_network_header_len(skb));
e51a64727   Ilan Tayari   esp6: Support RX ...
504
  	skb_pull_rcsum(skb, hlen);
a9403f8ae   Li RongQing   ah6/esp6: set tra...
505
506
507
508
  	if (x->props.mode == XFRM_MODE_TUNNEL)
  		skb_reset_transport_header(skb);
  	else
  		skb_set_transport_header(skb, -hdr_len);
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
509

38320c70d   Herbert Xu   [IPSEC]: Use cryp...
510
511
512
513
514
  	/* RFC4303: Drop dummy packets without any error */
  	if (err == IPPROTO_NONE)
  		err = -EINVAL;
  
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
516
  	return err;
  }
383d0350f   Steffen Klassert   esp6: Reorganize ...
517
  EXPORT_SYMBOL_GPL(esp6_input_done2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
518

38320c70d   Herbert Xu   [IPSEC]: Use cryp...
519
520
521
  static void esp_input_done(struct crypto_async_request *base, int err)
  {
  	struct sk_buff *skb = base->data;
f1fbed0e8   Steffen Klassert   esp6: Remame esp_...
522
  	xfrm_input_resume(skb, esp6_input_done2(skb, err));
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
523
  }
000ae7b26   Herbert Xu   esp6: Switch to n...
524
525
526
527
528
  static void esp_input_restore_header(struct sk_buff *skb)
  {
  	esp_restore_header(skb, 0);
  	__skb_pull(skb, 4);
  }
03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
529
530
531
532
533
534
535
536
537
538
  static void esp_input_set_header(struct sk_buff *skb, __be32 *seqhi)
  {
  	struct xfrm_state *x = xfrm_input_state(skb);
  	struct ip_esp_hdr *esph = (struct ip_esp_hdr *)skb->data;
  
  	/* For ESN we move the header forward by 4 bytes to
  	 * accomodate the high bits.  We will move it back after
  	 * decryption.
  	 */
  	if ((x->props.flags & XFRM_STATE_ESN)) {
d58ff3512   Johannes Berg   networking: make ...
539
  		esph = skb_push(skb, 4);
03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
540
541
542
543
544
  		*seqhi = esph->spi;
  		esph->spi = esph->seq_no;
  		esph->seq_no = XFRM_SKB_CB(skb)->seq.input.hi;
  	}
  }
000ae7b26   Herbert Xu   esp6: Switch to n...
545
546
547
548
549
550
551
  static void esp_input_done_esn(struct crypto_async_request *base, int err)
  {
  	struct sk_buff *skb = base->data;
  
  	esp_input_restore_header(skb);
  	esp_input_done(base, err);
  }
e695633e2   Herbert Xu   [IPSEC]: Kill unu...
552
  static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
  {
87bdc48d3   Herbert Xu   [IPSEC]: Get rid ...
554
  	struct ip_esp_hdr *esph;
1c5ad13f7   Mathias Krause   net: esp{4,6}: ge...
555
  	struct crypto_aead *aead = x->data;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
556
  	struct aead_request *req;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
  	struct sk_buff *trailer;
000ae7b26   Herbert Xu   esp6: Switch to n...
558
559
  	int ivlen = crypto_aead_ivsize(aead);
  	int elen = skb->len - sizeof(*esph) - ivlen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560
  	int nfrags;
d212a4c29   Steffen Klassert   esp6: Add support...
561
  	int assoclen;
d212a4c29   Steffen Klassert   esp6: Add support...
562
  	int seqhilen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
  	int ret = 0;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
564
  	void *tmp;
d212a4c29   Steffen Klassert   esp6: Add support...
565
  	__be32 *seqhi;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
566
567
  	u8 *iv;
  	struct scatterlist *sg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568

000ae7b26   Herbert Xu   esp6: Switch to n...
569
  	if (!pskb_may_pull(skb, sizeof(*esph) + ivlen)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
  		ret = -EINVAL;
31a4ab930   Herbert Xu   [IPSEC] proto: Mo...
571
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
  	}
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
573
  	if (elen <= 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
  		ret = -EINVAL;
31a4ab930   Herbert Xu   [IPSEC] proto: Mo...
575
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577

d212a4c29   Steffen Klassert   esp6: Add support...
578
  	assoclen = sizeof(*esph);
d212a4c29   Steffen Klassert   esp6: Add support...
579
580
581
  	seqhilen = 0;
  
  	if (x->props.flags & XFRM_STATE_ESN) {
d212a4c29   Steffen Klassert   esp6: Add support...
582
583
584
  		seqhilen += sizeof(__be32);
  		assoclen += seqhilen;
  	}
03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
  	if (!skb_cloned(skb)) {
  		if (!skb_is_nonlinear(skb)) {
  			nfrags = 1;
  
  			goto skip_cow;
  		} else if (!skb_has_frag_list(skb)) {
  			nfrags = skb_shinfo(skb)->nr_frags;
  			nfrags++;
  
  			goto skip_cow;
  		}
  	}
  
  	nfrags = skb_cow_data(skb, 0, &trailer);
  	if (nfrags < 0) {
  		ret = -EINVAL;
  		goto out;
  	}
  
  skip_cow:
  	ret = -ENOMEM;
000ae7b26   Herbert Xu   esp6: Switch to n...
606
  	tmp = esp_alloc_tmp(aead, nfrags, seqhilen);
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
607
608
  	if (!tmp)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609

38320c70d   Herbert Xu   [IPSEC]: Use cryp...
610
  	ESP_SKB_CB(skb)->tmp = tmp;
d212a4c29   Steffen Klassert   esp6: Add support...
611
612
  	seqhi = esp_tmp_seqhi(tmp);
  	iv = esp_tmp_iv(aead, tmp, seqhilen);
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
613
  	req = esp_tmp_req(aead, iv);
000ae7b26   Herbert Xu   esp6: Switch to n...
614
  	sg = esp_req_sg(aead, req);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
615

03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
616
  	esp_input_set_header(skb, seqhi);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617

03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
618
  	sg_init_table(sg, nfrags);
3f2977072   Jason A. Donenfeld   ipsec: check retu...
619
  	ret = skb_to_sgvec(skb, sg, 0, skb->len);
b6f147a2d   Zhen Lei   esp6: fix memleak...
620
621
  	if (unlikely(ret < 0)) {
  		kfree(tmp);
3f2977072   Jason A. Donenfeld   ipsec: check retu...
622
  		goto out;
b6f147a2d   Zhen Lei   esp6: fix memleak...
623
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624

03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
625
  	skb->ip_summed = CHECKSUM_NONE;
d212a4c29   Steffen Klassert   esp6: Add support...
626

03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
627
  	if ((x->props.flags & XFRM_STATE_ESN))
000ae7b26   Herbert Xu   esp6: Switch to n...
628
  		aead_request_set_callback(req, 0, esp_input_done_esn, skb);
03e2a30f6   Steffen Klassert   esp6: Avoid skb_c...
629
630
  	else
  		aead_request_set_callback(req, 0, esp_input_done, skb);
000ae7b26   Herbert Xu   esp6: Switch to n...
631
632
633
  
  	aead_request_set_crypt(req, sg, sg, elen + ivlen, iv);
  	aead_request_set_ad(req, assoclen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
634

38320c70d   Herbert Xu   [IPSEC]: Use cryp...
635
636
637
  	ret = crypto_aead_decrypt(req);
  	if (ret == -EINPROGRESS)
  		goto out;
95a02cfd4   Thomas Graf   [IPv6] ESP: Disca...
638

000ae7b26   Herbert Xu   esp6: Switch to n...
639
640
  	if ((x->props.flags & XFRM_STATE_ESN))
  		esp_input_restore_header(skb);
f1fbed0e8   Steffen Klassert   esp6: Remame esp_...
641
  	ret = esp6_input_done2(skb, ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
642
643
  
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
645
  	return ret;
  }
c5c252389   Patrick McHardy   [XFRM]: Optimize ...
646
  static u32 esp6_get_mtu(struct xfrm_state *x, int mtu)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
  {
1c5ad13f7   Mathias Krause   net: esp{4,6}: ge...
648
649
  	struct crypto_aead *aead = x->data;
  	u32 blksize = ALIGN(crypto_aead_blocksize(aead), 4);
91657eafb   Benjamin Poirier   xfrm: take net hd...
650
  	unsigned int net_adj;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651

91657eafb   Benjamin Poirier   xfrm: take net hd...
652
653
654
655
  	if (x->props.mode != XFRM_MODE_TUNNEL)
  		net_adj = sizeof(struct ipv6hdr);
  	else
  		net_adj = 0;
c5c252389   Patrick McHardy   [XFRM]: Optimize ...
656

1c5ad13f7   Mathias Krause   net: esp{4,6}: ge...
657
  	return ((mtu - x->props.header_len - crypto_aead_authsize(aead) -
123b0d1ba   Mathias Krause   net: esp{4,6}: re...
658
  		 net_adj) & ~(blksize - 1)) + net_adj - 2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
  }
d5860c5cc   Steffen Klassert   esp6: Use the IPs...
660
661
  static int esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
  		    u8 type, u8 code, int offset, __be32 info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
  {
4fb236bac   Alexey Dobriyan   netns xfrm: AH/ES...
663
  	struct net *net = dev_net(skb->dev);
b71d1d426   Eric Dumazet   inet: constify ip...
664
  	const struct ipv6hdr *iph = (const struct ipv6hdr *)skb->data;
87bdc48d3   Herbert Xu   [IPSEC]: Get rid ...
665
  	struct ip_esp_hdr *esph = (struct ip_esp_hdr *)(skb->data + offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
666
  	struct xfrm_state *x;
b3b2b9e19   Steffen Klassert   ipsec: Don't upda...
667
  	if (type != ICMPV6_PKT_TOOBIG &&
ec18d9a26   David S. Miller   ipv6: Add redirec...
668
  	    type != NDISC_REDIRECT)
d5860c5cc   Steffen Klassert   esp6: Use the IPs...
669
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670

b71d1d426   Eric Dumazet   inet: constify ip...
671
672
  	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
673
  	if (!x)
d5860c5cc   Steffen Klassert   esp6: Use the IPs...
674
  		return 0;
ec18d9a26   David S. Miller   ipv6: Add redirec...
675
676
  
  	if (type == NDISC_REDIRECT)
e2d118a1c   Lorenzo Colitti   net: inet: Suppor...
677
678
  		ip6_redirect(skb, net, skb->dev->ifindex, 0,
  			     sock_net_uid(net, NULL));
ec18d9a26   David S. Miller   ipv6: Add redirec...
679
  	else
e2d118a1c   Lorenzo Colitti   net: inet: Suppor...
680
  		ip6_update_pmtu(skb, net, info, 0, 0, sock_net_uid(net, NULL));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
  	xfrm_state_put(x);
d5860c5cc   Steffen Klassert   esp6: Use the IPs...
682
683
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
684
685
686
687
  }
  
  static void esp6_destroy(struct xfrm_state *x)
  {
1c5ad13f7   Mathias Krause   net: esp{4,6}: ge...
688
  	struct crypto_aead *aead = x->data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
689

1c5ad13f7   Mathias Krause   net: esp{4,6}: ge...
690
  	if (!aead)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
691
  		return;
1c5ad13f7   Mathias Krause   net: esp{4,6}: ge...
692
  	crypto_free_aead(aead);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693
  }
1a6509d99   Herbert Xu   [IPSEC]: Add supp...
694
695
  static int esp_init_aead(struct xfrm_state *x)
  {
000ae7b26   Herbert Xu   esp6: Switch to n...
696
  	char aead_name[CRYPTO_MAX_ALG_NAME];
1a6509d99   Herbert Xu   [IPSEC]: Add supp...
697
698
  	struct crypto_aead *aead;
  	int err;
b3859c8eb   Steffen Klassert   esp: Use a synchr...
699
  	u32 mask = 0;
1a6509d99   Herbert Xu   [IPSEC]: Add supp...
700

000ae7b26   Herbert Xu   esp6: Switch to n...
701
702
703
704
  	err = -ENAMETOOLONG;
  	if (snprintf(aead_name, CRYPTO_MAX_ALG_NAME, "%s(%s)",
  		     x->geniv, x->aead->alg_name) >= CRYPTO_MAX_ALG_NAME)
  		goto error;
b3859c8eb   Steffen Klassert   esp: Use a synchr...
705
706
707
708
  	if (x->xso.offload_handle)
  		mask |= CRYPTO_ALG_ASYNC;
  
  	aead = crypto_alloc_aead(aead_name, 0, mask);
1a6509d99   Herbert Xu   [IPSEC]: Add supp...
709
710
711
  	err = PTR_ERR(aead);
  	if (IS_ERR(aead))
  		goto error;
1c5ad13f7   Mathias Krause   net: esp{4,6}: ge...
712
  	x->data = aead;
1a6509d99   Herbert Xu   [IPSEC]: Add supp...
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
  
  	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
728
  {
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
729
730
731
732
733
734
  	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...
735
736
  	unsigned int keylen;
  	int err;
b3859c8eb   Steffen Klassert   esp: Use a synchr...
737
  	u32 mask = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
738

1a6509d99   Herbert Xu   [IPSEC]: Add supp...
739
  	err = -EINVAL;
63159f29b   Ian Morris   ipv6: coding styl...
740
  	if (!x->ealg)
1a6509d99   Herbert Xu   [IPSEC]: Add supp...
741
  		goto error;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
742

1a6509d99   Herbert Xu   [IPSEC]: Add supp...
743
  	err = -ENAMETOOLONG;
d212a4c29   Steffen Klassert   esp6: Add support...
744
745
746
  
  	if ((x->props.flags & XFRM_STATE_ESN)) {
  		if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME,
000ae7b26   Herbert Xu   esp6: Switch to n...
747
748
  			     "%s%sauthencesn(%s,%s)%s",
  			     x->geniv ?: "", x->geniv ? "(" : "",
d212a4c29   Steffen Klassert   esp6: Add support...
749
  			     x->aalg ? x->aalg->alg_name : "digest_null",
000ae7b26   Herbert Xu   esp6: Switch to n...
750
751
  			     x->ealg->alg_name,
  			     x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME)
d212a4c29   Steffen Klassert   esp6: Add support...
752
753
754
  			goto error;
  	} else {
  		if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME,
000ae7b26   Herbert Xu   esp6: Switch to n...
755
756
  			     "%s%sauthenc(%s,%s)%s",
  			     x->geniv ?: "", x->geniv ? "(" : "",
d212a4c29   Steffen Klassert   esp6: Add support...
757
  			     x->aalg ? x->aalg->alg_name : "digest_null",
000ae7b26   Herbert Xu   esp6: Switch to n...
758
759
  			     x->ealg->alg_name,
  			     x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME)
d212a4c29   Steffen Klassert   esp6: Add support...
760
761
  			goto error;
  	}
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
762

b3859c8eb   Steffen Klassert   esp: Use a synchr...
763
764
765
766
  	if (x->xso.offload_handle)
  		mask |= CRYPTO_ALG_ASYNC;
  
  	aead = crypto_alloc_aead(authenc_name, 0, mask);
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
767
768
769
  	err = PTR_ERR(aead);
  	if (IS_ERR(aead))
  		goto error;
1c5ad13f7   Mathias Krause   net: esp{4,6}: ge...
770
  	x->data = aead;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
771
772
773
774
775
776
777
778
779
780
781
782
783
784
  
  	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
785
786
  	if (x->aalg) {
  		struct xfrm_algo_desc *aalg_desc;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
787
788
  		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...
789

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

38320c70d   Herbert Xu   [IPSEC]: Use cryp...
793
  		err = -EINVAL;
450834977   Joe Perches   net: esp: Convert...
794
  		if (aalg_desc->uinfo.auth.icv_fullbits / 8 !=
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
795
  		    crypto_aead_authsize(aead)) {
450834977   Joe Perches   net: esp: Convert...
796
797
798
799
800
  			pr_info("ESP: %s digestsize %u != %hu
  ",
  				x->aalg->alg_name,
  				crypto_aead_authsize(aead),
  				aalg_desc->uinfo.auth.icv_fullbits / 8);
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
801
  			goto free_key;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
  		}
1ab1457c4   YOSHIFUJI Hideaki   [NET] IPV6: Fix w...
803

38320c70d   Herbert Xu   [IPSEC]: Use cryp...
804
  		err = crypto_aead_setauthsize(
8f8a088c2   Martin Willi   xfrm: Use the use...
805
  			aead, x->aalg->alg_trunc_len / 8);
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
806
807
  		if (err)
  			goto free_key;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
808
  	}
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
809

38320c70d   Herbert Xu   [IPSEC]: Use cryp...
810
811
812
813
814
815
816
  	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...
817
818
819
820
821
822
  error:
  	return err;
  }
  
  static int esp6_init_state(struct xfrm_state *x)
  {
1a6509d99   Herbert Xu   [IPSEC]: Add supp...
823
824
825
826
827
828
  	struct crypto_aead *aead;
  	u32 align;
  	int err;
  
  	if (x->encap)
  		return -EINVAL;
1c5ad13f7   Mathias Krause   net: esp{4,6}: ge...
829
  	x->data = NULL;
1a6509d99   Herbert Xu   [IPSEC]: Add supp...
830
831
832
833
834
  
  	if (x->aead)
  		err = esp_init_aead(x);
  	else
  		err = esp_init_authenc(x);
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
835
  	if (err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
836
  		goto error;
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
837

1c5ad13f7   Mathias Krause   net: esp{4,6}: ge...
838
  	aead = x->data;
1a6509d99   Herbert Xu   [IPSEC]: Add supp...
839

38320c70d   Herbert Xu   [IPSEC]: Use cryp...
840
841
  	x->props.header_len = sizeof(struct ip_esp_hdr) +
  			      crypto_aead_ivsize(aead);
ca68145f1   Herbert Xu   [IPSEC]: Disallow...
842
843
  	switch (x->props.mode) {
  	case XFRM_MODE_BEET:
abf5cdb89   Joakim Koskela   ipsec: Interfamil...
844
845
  		if (x->sel.family != AF_INET6)
  			x->props.header_len += IPV4_BEET_PHMAXLEN +
67ba4152e   Ian Morris   ipv6: White-space...
846
  					       (sizeof(struct ipv6hdr) - sizeof(struct iphdr));
abf5cdb89   Joakim Koskela   ipsec: Interfamil...
847
  		break;
ca68145f1   Herbert Xu   [IPSEC]: Disallow...
848
849
850
  	case XFRM_MODE_TRANSPORT:
  		break;
  	case XFRM_MODE_TUNNEL:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
851
  		x->props.header_len += sizeof(struct ipv6hdr);
ea2c47b42   Masahide NAKAMURA   [IPSEC] IPV6: Fix...
852
  		break;
ca68145f1   Herbert Xu   [IPSEC]: Disallow...
853
854
855
  	default:
  		goto error;
  	}
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
856
857
  
  	align = ALIGN(crypto_aead_blocksize(aead), 4);
1c5ad13f7   Mathias Krause   net: esp{4,6}: ge...
858
  	x->props.trailer_len = align + 1 + crypto_aead_authsize(aead);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859
860
  
  error:
38320c70d   Herbert Xu   [IPSEC]: Use cryp...
861
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
862
  }
d5860c5cc   Steffen Klassert   esp6: Use the IPs...
863
864
865
866
  static int esp6_rcv_cb(struct sk_buff *skb, int err)
  {
  	return 0;
  }
cc24becae   Ian Morris   ipv6: White-space...
867
  static const struct xfrm_type esp6_type = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
868
  	.description	= "ESP6",
cc24becae   Ian Morris   ipv6: White-space...
869
870
  	.owner		= THIS_MODULE,
  	.proto		= IPPROTO_ESP,
436a0a402   Herbert Xu   [IPSEC]: Move out...
871
  	.flags		= XFRM_TYPE_REPLAY_PROT,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
872
873
  	.init_state	= esp6_init_state,
  	.destructor	= esp6_destroy,
c5c252389   Patrick McHardy   [XFRM]: Optimize ...
874
  	.get_mtu	= esp6_get_mtu,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
875
  	.input		= esp6_input,
aee5adb43   Masahide NAKAMURA   [XFRM] STATE: Add...
876
877
  	.output		= esp6_output,
  	.hdr_offset	= xfrm6_find_1stfragopt,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
878
  };
d5860c5cc   Steffen Klassert   esp6: Use the IPs...
879
880
881
  static struct xfrm6_protocol esp6_protocol = {
  	.handler	=	xfrm6_rcv,
  	.cb_handler	=	esp6_rcv_cb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
882
  	.err_handler	=	esp6_err,
d5860c5cc   Steffen Klassert   esp6: Use the IPs...
883
  	.priority	=	0,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
884
885
886
887
888
  };
  
  static int __init esp6_init(void)
  {
  	if (xfrm_register_type(&esp6_type, AF_INET6) < 0) {
f32138319   Joe Perches   net: ipv6: Standa...
889
890
  		pr_info("%s: can't add xfrm type
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
891
892
  		return -EAGAIN;
  	}
d5860c5cc   Steffen Klassert   esp6: Use the IPs...
893
  	if (xfrm6_protocol_register(&esp6_protocol, IPPROTO_ESP) < 0) {
f32138319   Joe Perches   net: ipv6: Standa...
894
895
  		pr_info("%s: can't add protocol
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
896
897
898
899
900
901
902
903
904
  		xfrm_unregister_type(&esp6_type, AF_INET6);
  		return -EAGAIN;
  	}
  
  	return 0;
  }
  
  static void __exit esp6_fini(void)
  {
d5860c5cc   Steffen Klassert   esp6: Use the IPs...
905
  	if (xfrm6_protocol_deregister(&esp6_protocol, IPPROTO_ESP) < 0)
f32138319   Joe Perches   net: ipv6: Standa...
906
907
  		pr_info("%s: can't remove protocol
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
908
  	if (xfrm_unregister_type(&esp6_type, AF_INET6) < 0)
f32138319   Joe Perches   net: ipv6: Standa...
909
910
  		pr_info("%s: can't remove xfrm type
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
911
912
913
914
915
916
  }
  
  module_init(esp6_init);
  module_exit(esp6_fini);
  
  MODULE_LICENSE("GPL");
d3d6dd3ad   Masahide NAKAMURA   [XFRM]: Add modul...
917
  MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_ESP);