xref: /linux/net/ipv4/esp4.c (revision a6d95c5a628a09be129f25d5663a7e9db8261f51)
109c434b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2afd46503SJoe Perches #define pr_fmt(fmt) "IPsec: " fmt
3afd46503SJoe Perches 
438320c70SHerbert Xu #include <crypto/aead.h>
538320c70SHerbert Xu #include <crypto/authenc.h>
66b7326c8SHerbert Xu #include <linux/err.h>
71da177e4SLinus Torvalds #include <linux/module.h>
81da177e4SLinus Torvalds #include <net/ip.h>
91da177e4SLinus Torvalds #include <net/xfrm.h>
101da177e4SLinus Torvalds #include <net/esp.h>
1172998d8cSAdrian Bunk #include <linux/scatterlist.h>
12a02a6422SHerbert Xu #include <linux/kernel.h>
131da177e4SLinus Torvalds #include <linux/pfkeyv2.h>
1438320c70SHerbert Xu #include <linux/rtnetlink.h>
1538320c70SHerbert Xu #include <linux/slab.h>
16b7c6538cSHerbert Xu #include <linux/spinlock.h>
172017a72cSThomas Graf #include <linux/in6.h>
181da177e4SLinus Torvalds #include <net/icmp.h>
1914c85021SArnaldo Carvalho de Melo #include <net/protocol.h>
201da177e4SLinus Torvalds #include <net/udp.h>
21e27cca96SSabrina Dubroca #include <net/tcp.h>
22e27cca96SSabrina Dubroca #include <net/espintcp.h>
231da177e4SLinus Torvalds 
24cac2661cSSteffen Klassert #include <linux/highmem.h>
25cac2661cSSteffen Klassert 
2638320c70SHerbert Xu struct esp_skb_cb {
2738320c70SHerbert Xu 	struct xfrm_skb_cb xfrm;
2838320c70SHerbert Xu 	void *tmp;
2938320c70SHerbert Xu };
3038320c70SHerbert Xu 
31962fcef3SHerbert Xu struct esp_output_extra {
32962fcef3SHerbert Xu 	__be32 seqhi;
33962fcef3SHerbert Xu 	u32 esphoff;
34962fcef3SHerbert Xu };
35962fcef3SHerbert Xu 
3638320c70SHerbert Xu #define ESP_SKB_CB(__skb) ((struct esp_skb_cb *)&((__skb)->cb[0]))
3738320c70SHerbert Xu 
3838320c70SHerbert Xu /*
3938320c70SHerbert Xu  * Allocate an AEAD request structure with extra space for SG and IV.
4038320c70SHerbert Xu  *
4138320c70SHerbert Xu  * For alignment considerations the IV is placed at the front, followed
4238320c70SHerbert Xu  * by the request and finally the SG list.
4338320c70SHerbert Xu  *
4438320c70SHerbert Xu  * TODO: Use spare space in skb for this where possible.
4538320c70SHerbert Xu  */
46962fcef3SHerbert Xu static void *esp_alloc_tmp(struct crypto_aead *aead, int nfrags, int extralen)
4738320c70SHerbert Xu {
4838320c70SHerbert Xu 	unsigned int len;
4938320c70SHerbert Xu 
50962fcef3SHerbert Xu 	len = extralen;
510dc49e9bSSteffen Klassert 
520dc49e9bSSteffen Klassert 	len += crypto_aead_ivsize(aead);
530dc49e9bSSteffen Klassert 
5438320c70SHerbert Xu 	if (len) {
5538320c70SHerbert Xu 		len += crypto_aead_alignmask(aead) &
5638320c70SHerbert Xu 		       ~(crypto_tfm_ctx_alignment() - 1);
5738320c70SHerbert Xu 		len = ALIGN(len, crypto_tfm_ctx_alignment());
5838320c70SHerbert Xu 	}
5938320c70SHerbert Xu 
607021b2e1SHerbert Xu 	len += sizeof(struct aead_request) + crypto_aead_reqsize(aead);
6138320c70SHerbert Xu 	len = ALIGN(len, __alignof__(struct scatterlist));
6238320c70SHerbert Xu 
6338320c70SHerbert Xu 	len += sizeof(struct scatterlist) * nfrags;
6438320c70SHerbert Xu 
6538320c70SHerbert Xu 	return kmalloc(len, GFP_ATOMIC);
6638320c70SHerbert Xu }
6738320c70SHerbert Xu 
68962fcef3SHerbert Xu static inline void *esp_tmp_extra(void *tmp)
690dc49e9bSSteffen Klassert {
70962fcef3SHerbert Xu 	return PTR_ALIGN(tmp, __alignof__(struct esp_output_extra));
710dc49e9bSSteffen Klassert }
72962fcef3SHerbert Xu 
73962fcef3SHerbert Xu static inline u8 *esp_tmp_iv(struct crypto_aead *aead, void *tmp, int extralen)
7438320c70SHerbert Xu {
7538320c70SHerbert Xu 	return crypto_aead_ivsize(aead) ?
76962fcef3SHerbert Xu 	       PTR_ALIGN((u8 *)tmp + extralen,
77962fcef3SHerbert Xu 			 crypto_aead_alignmask(aead) + 1) : tmp + extralen;
7838320c70SHerbert Xu }
7938320c70SHerbert Xu 
8038320c70SHerbert Xu static inline struct aead_request *esp_tmp_req(struct crypto_aead *aead, u8 *iv)
8138320c70SHerbert Xu {
8238320c70SHerbert Xu 	struct aead_request *req;
8338320c70SHerbert Xu 
8438320c70SHerbert Xu 	req = (void *)PTR_ALIGN(iv + crypto_aead_ivsize(aead),
8538320c70SHerbert Xu 				crypto_tfm_ctx_alignment());
8638320c70SHerbert Xu 	aead_request_set_tfm(req, aead);
8738320c70SHerbert Xu 	return req;
8838320c70SHerbert Xu }
8938320c70SHerbert Xu 
9038320c70SHerbert Xu static inline struct scatterlist *esp_req_sg(struct crypto_aead *aead,
9138320c70SHerbert Xu 					     struct aead_request *req)
9238320c70SHerbert Xu {
9338320c70SHerbert Xu 	return (void *)ALIGN((unsigned long)(req + 1) +
9438320c70SHerbert Xu 			     crypto_aead_reqsize(aead),
9538320c70SHerbert Xu 			     __alignof__(struct scatterlist));
9638320c70SHerbert Xu }
9738320c70SHerbert Xu 
98cac2661cSSteffen Klassert static void esp_ssg_unref(struct xfrm_state *x, void *tmp)
99cac2661cSSteffen Klassert {
100cac2661cSSteffen Klassert 	struct crypto_aead *aead = x->data;
101cac2661cSSteffen Klassert 	int extralen = 0;
102cac2661cSSteffen Klassert 	u8 *iv;
103cac2661cSSteffen Klassert 	struct aead_request *req;
104cac2661cSSteffen Klassert 	struct scatterlist *sg;
105cac2661cSSteffen Klassert 
106cac2661cSSteffen Klassert 	if (x->props.flags & XFRM_STATE_ESN)
107f8fdadefSCorey Minyard 		extralen += sizeof(struct esp_output_extra);
108cac2661cSSteffen Klassert 
109cac2661cSSteffen Klassert 	iv = esp_tmp_iv(aead, tmp, extralen);
110cac2661cSSteffen Klassert 	req = esp_tmp_req(aead, iv);
111cac2661cSSteffen Klassert 
112cac2661cSSteffen Klassert 	/* Unref skb_frag_pages in the src scatterlist if necessary.
113cac2661cSSteffen Klassert 	 * Skip the first sg which comes from skb->data.
114cac2661cSSteffen Klassert 	 */
115cac2661cSSteffen Klassert 	if (req->src != req->dst)
116cac2661cSSteffen Klassert 		for (sg = sg_next(req->src); sg; sg = sg_next(sg))
117cac2661cSSteffen Klassert 			put_page(sg_page(sg));
118cac2661cSSteffen Klassert }
119cac2661cSSteffen Klassert 
120e27cca96SSabrina Dubroca #ifdef CONFIG_INET_ESPINTCP
121e27cca96SSabrina Dubroca struct esp_tcp_sk {
122e27cca96SSabrina Dubroca 	struct sock *sk;
123e27cca96SSabrina Dubroca 	struct rcu_head rcu;
124e27cca96SSabrina Dubroca };
125e27cca96SSabrina Dubroca 
126e27cca96SSabrina Dubroca static void esp_free_tcp_sk(struct rcu_head *head)
127e27cca96SSabrina Dubroca {
128e27cca96SSabrina Dubroca 	struct esp_tcp_sk *esk = container_of(head, struct esp_tcp_sk, rcu);
129e27cca96SSabrina Dubroca 
130e27cca96SSabrina Dubroca 	sock_put(esk->sk);
131e27cca96SSabrina Dubroca 	kfree(esk);
132e27cca96SSabrina Dubroca }
133e27cca96SSabrina Dubroca 
134e27cca96SSabrina Dubroca static struct sock *esp_find_tcp_sk(struct xfrm_state *x)
135e27cca96SSabrina Dubroca {
136e27cca96SSabrina Dubroca 	struct xfrm_encap_tmpl *encap = x->encap;
137e27cca96SSabrina Dubroca 	struct esp_tcp_sk *esk;
138e27cca96SSabrina Dubroca 	__be16 sport, dport;
139e27cca96SSabrina Dubroca 	struct sock *nsk;
140e27cca96SSabrina Dubroca 	struct sock *sk;
141e27cca96SSabrina Dubroca 
142e27cca96SSabrina Dubroca 	sk = rcu_dereference(x->encap_sk);
143e27cca96SSabrina Dubroca 	if (sk && sk->sk_state == TCP_ESTABLISHED)
144e27cca96SSabrina Dubroca 		return sk;
145e27cca96SSabrina Dubroca 
146e27cca96SSabrina Dubroca 	spin_lock_bh(&x->lock);
147e27cca96SSabrina Dubroca 	sport = encap->encap_sport;
148e27cca96SSabrina Dubroca 	dport = encap->encap_dport;
149e27cca96SSabrina Dubroca 	nsk = rcu_dereference_protected(x->encap_sk,
150e27cca96SSabrina Dubroca 					lockdep_is_held(&x->lock));
151e27cca96SSabrina Dubroca 	if (sk && sk == nsk) {
152e27cca96SSabrina Dubroca 		esk = kmalloc(sizeof(*esk), GFP_ATOMIC);
153e27cca96SSabrina Dubroca 		if (!esk) {
154e27cca96SSabrina Dubroca 			spin_unlock_bh(&x->lock);
155e27cca96SSabrina Dubroca 			return ERR_PTR(-ENOMEM);
156e27cca96SSabrina Dubroca 		}
157e27cca96SSabrina Dubroca 		RCU_INIT_POINTER(x->encap_sk, NULL);
158e27cca96SSabrina Dubroca 		esk->sk = sk;
159e27cca96SSabrina Dubroca 		call_rcu(&esk->rcu, esp_free_tcp_sk);
160e27cca96SSabrina Dubroca 	}
161e27cca96SSabrina Dubroca 	spin_unlock_bh(&x->lock);
162e27cca96SSabrina Dubroca 
163e27cca96SSabrina Dubroca 	sk = inet_lookup_established(xs_net(x), &tcp_hashinfo, x->id.daddr.a4,
164e27cca96SSabrina Dubroca 				     dport, x->props.saddr.a4, sport, 0);
165e27cca96SSabrina Dubroca 	if (!sk)
166e27cca96SSabrina Dubroca 		return ERR_PTR(-ENOENT);
167e27cca96SSabrina Dubroca 
168e27cca96SSabrina Dubroca 	if (!tcp_is_ulp_esp(sk)) {
169e27cca96SSabrina Dubroca 		sock_put(sk);
170e27cca96SSabrina Dubroca 		return ERR_PTR(-EINVAL);
171e27cca96SSabrina Dubroca 	}
172e27cca96SSabrina Dubroca 
173e27cca96SSabrina Dubroca 	spin_lock_bh(&x->lock);
174e27cca96SSabrina Dubroca 	nsk = rcu_dereference_protected(x->encap_sk,
175e27cca96SSabrina Dubroca 					lockdep_is_held(&x->lock));
176e27cca96SSabrina Dubroca 	if (encap->encap_sport != sport ||
177e27cca96SSabrina Dubroca 	    encap->encap_dport != dport) {
178e27cca96SSabrina Dubroca 		sock_put(sk);
179e27cca96SSabrina Dubroca 		sk = nsk ?: ERR_PTR(-EREMCHG);
180e27cca96SSabrina Dubroca 	} else if (sk == nsk) {
181e27cca96SSabrina Dubroca 		sock_put(sk);
182e27cca96SSabrina Dubroca 	} else {
183e27cca96SSabrina Dubroca 		rcu_assign_pointer(x->encap_sk, sk);
184e27cca96SSabrina Dubroca 	}
185e27cca96SSabrina Dubroca 	spin_unlock_bh(&x->lock);
186e27cca96SSabrina Dubroca 
187e27cca96SSabrina Dubroca 	return sk;
188e27cca96SSabrina Dubroca }
189e27cca96SSabrina Dubroca 
190e27cca96SSabrina Dubroca static int esp_output_tcp_finish(struct xfrm_state *x, struct sk_buff *skb)
191e27cca96SSabrina Dubroca {
192e27cca96SSabrina Dubroca 	struct sock *sk;
193e27cca96SSabrina Dubroca 	int err;
194e27cca96SSabrina Dubroca 
195e27cca96SSabrina Dubroca 	rcu_read_lock();
196e27cca96SSabrina Dubroca 
197e27cca96SSabrina Dubroca 	sk = esp_find_tcp_sk(x);
198e27cca96SSabrina Dubroca 	err = PTR_ERR_OR_ZERO(sk);
199e27cca96SSabrina Dubroca 	if (err)
200e27cca96SSabrina Dubroca 		goto out;
201e27cca96SSabrina Dubroca 
202e27cca96SSabrina Dubroca 	bh_lock_sock(sk);
203e27cca96SSabrina Dubroca 	if (sock_owned_by_user(sk))
204e27cca96SSabrina Dubroca 		err = espintcp_queue_out(sk, skb);
205e27cca96SSabrina Dubroca 	else
206e27cca96SSabrina Dubroca 		err = espintcp_push_skb(sk, skb);
207e27cca96SSabrina Dubroca 	bh_unlock_sock(sk);
208e27cca96SSabrina Dubroca 
209e27cca96SSabrina Dubroca out:
210e27cca96SSabrina Dubroca 	rcu_read_unlock();
211e27cca96SSabrina Dubroca 	return err;
212e27cca96SSabrina Dubroca }
213e27cca96SSabrina Dubroca 
214e27cca96SSabrina Dubroca static int esp_output_tcp_encap_cb(struct net *net, struct sock *sk,
215e27cca96SSabrina Dubroca 				   struct sk_buff *skb)
216e27cca96SSabrina Dubroca {
217e27cca96SSabrina Dubroca 	struct dst_entry *dst = skb_dst(skb);
218e27cca96SSabrina Dubroca 	struct xfrm_state *x = dst->xfrm;
219e27cca96SSabrina Dubroca 
220e27cca96SSabrina Dubroca 	return esp_output_tcp_finish(x, skb);
221e27cca96SSabrina Dubroca }
222e27cca96SSabrina Dubroca 
223e27cca96SSabrina Dubroca static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)
224e27cca96SSabrina Dubroca {
225e27cca96SSabrina Dubroca 	int err;
226e27cca96SSabrina Dubroca 
227e27cca96SSabrina Dubroca 	local_bh_disable();
228e27cca96SSabrina Dubroca 	err = xfrm_trans_queue_net(xs_net(x), skb, esp_output_tcp_encap_cb);
229e27cca96SSabrina Dubroca 	local_bh_enable();
230e27cca96SSabrina Dubroca 
231e27cca96SSabrina Dubroca 	/* EINPROGRESS just happens to do the right thing.  It
232e27cca96SSabrina Dubroca 	 * actually means that the skb has been consumed and
233e27cca96SSabrina Dubroca 	 * isn't coming back.
234e27cca96SSabrina Dubroca 	 */
235e27cca96SSabrina Dubroca 	return err ?: -EINPROGRESS;
236e27cca96SSabrina Dubroca }
237e27cca96SSabrina Dubroca #else
238e27cca96SSabrina Dubroca static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)
239e27cca96SSabrina Dubroca {
240e27cca96SSabrina Dubroca 	kfree_skb(skb);
241e27cca96SSabrina Dubroca 
242e27cca96SSabrina Dubroca 	return -EOPNOTSUPP;
243e27cca96SSabrina Dubroca }
244e27cca96SSabrina Dubroca #endif
245e27cca96SSabrina Dubroca 
24638320c70SHerbert Xu static void esp_output_done(struct crypto_async_request *base, int err)
24738320c70SHerbert Xu {
24838320c70SHerbert Xu 	struct sk_buff *skb = base->data;
249f53c7239SSteffen Klassert 	struct xfrm_offload *xo = xfrm_offload(skb);
250cac2661cSSteffen Klassert 	void *tmp;
251f53c7239SSteffen Klassert 	struct xfrm_state *x;
252f53c7239SSteffen Klassert 
2532294be0fSFlorian Westphal 	if (xo && (xo->flags & XFRM_DEV_RESUME)) {
2542294be0fSFlorian Westphal 		struct sec_path *sp = skb_sec_path(skb);
2552294be0fSFlorian Westphal 
2562294be0fSFlorian Westphal 		x = sp->xvec[sp->len - 1];
2572294be0fSFlorian Westphal 	} else {
258f53c7239SSteffen Klassert 		x = skb_dst(skb)->xfrm;
2592294be0fSFlorian Westphal 	}
26038320c70SHerbert Xu 
261cac2661cSSteffen Klassert 	tmp = ESP_SKB_CB(skb)->tmp;
262cac2661cSSteffen Klassert 	esp_ssg_unref(x, tmp);
263cac2661cSSteffen Klassert 	kfree(tmp);
264f53c7239SSteffen Klassert 
265f53c7239SSteffen Klassert 	if (xo && (xo->flags & XFRM_DEV_RESUME)) {
266f53c7239SSteffen Klassert 		if (err) {
267f53c7239SSteffen Klassert 			XFRM_INC_STATS(xs_net(x), LINUX_MIB_XFRMOUTSTATEPROTOERROR);
268f53c7239SSteffen Klassert 			kfree_skb(skb);
269f53c7239SSteffen Klassert 			return;
270f53c7239SSteffen Klassert 		}
271f53c7239SSteffen Klassert 
272f53c7239SSteffen Klassert 		skb_push(skb, skb->data - skb_mac_header(skb));
273f53c7239SSteffen Klassert 		secpath_reset(skb);
274f53c7239SSteffen Klassert 		xfrm_dev_resume(skb);
275f53c7239SSteffen Klassert 	} else {
276e27cca96SSabrina Dubroca 		if (!err &&
277e27cca96SSabrina Dubroca 		    x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP)
278e27cca96SSabrina Dubroca 			esp_output_tail_tcp(x, skb);
279e27cca96SSabrina Dubroca 		else
2809ab1265dSEvan Nimmo 			xfrm_output_resume(skb->sk, skb, err);
28138320c70SHerbert Xu 	}
282f53c7239SSteffen Klassert }
28338320c70SHerbert Xu 
2847021b2e1SHerbert Xu /* Move ESP header back into place. */
2857021b2e1SHerbert Xu static void esp_restore_header(struct sk_buff *skb, unsigned int offset)
2867021b2e1SHerbert Xu {
2877021b2e1SHerbert Xu 	struct ip_esp_hdr *esph = (void *)(skb->data + offset);
2887021b2e1SHerbert Xu 	void *tmp = ESP_SKB_CB(skb)->tmp;
289962fcef3SHerbert Xu 	__be32 *seqhi = esp_tmp_extra(tmp);
2907021b2e1SHerbert Xu 
2917021b2e1SHerbert Xu 	esph->seq_no = esph->spi;
2927021b2e1SHerbert Xu 	esph->spi = *seqhi;
2937021b2e1SHerbert Xu }
2947021b2e1SHerbert Xu 
2957021b2e1SHerbert Xu static void esp_output_restore_header(struct sk_buff *skb)
2967021b2e1SHerbert Xu {
297962fcef3SHerbert Xu 	void *tmp = ESP_SKB_CB(skb)->tmp;
298962fcef3SHerbert Xu 	struct esp_output_extra *extra = esp_tmp_extra(tmp);
299962fcef3SHerbert Xu 
300962fcef3SHerbert Xu 	esp_restore_header(skb, skb_transport_offset(skb) + extra->esphoff -
301962fcef3SHerbert Xu 				sizeof(__be32));
3027021b2e1SHerbert Xu }
3037021b2e1SHerbert Xu 
304cac2661cSSteffen Klassert static struct ip_esp_hdr *esp_output_set_extra(struct sk_buff *skb,
305fca11ebdSSteffen Klassert 					       struct xfrm_state *x,
306cac2661cSSteffen Klassert 					       struct ip_esp_hdr *esph,
307cac2661cSSteffen Klassert 					       struct esp_output_extra *extra)
308cac2661cSSteffen Klassert {
309cac2661cSSteffen Klassert 	/* For ESN we move the header forward by 4 bytes to
310cbd801b3SLu Wei 	 * accommodate the high bits.  We will move it back after
311cac2661cSSteffen Klassert 	 * encryption.
312cac2661cSSteffen Klassert 	 */
313cac2661cSSteffen Klassert 	if ((x->props.flags & XFRM_STATE_ESN)) {
3147862b405SSteffen Klassert 		__u32 seqhi;
3157862b405SSteffen Klassert 		struct xfrm_offload *xo = xfrm_offload(skb);
3167862b405SSteffen Klassert 
3177862b405SSteffen Klassert 		if (xo)
3187862b405SSteffen Klassert 			seqhi = xo->seq.hi;
3197862b405SSteffen Klassert 		else
3207862b405SSteffen Klassert 			seqhi = XFRM_SKB_CB(skb)->seq.output.hi;
3217862b405SSteffen Klassert 
322cac2661cSSteffen Klassert 		extra->esphoff = (unsigned char *)esph -
323cac2661cSSteffen Klassert 				 skb_transport_header(skb);
324cac2661cSSteffen Klassert 		esph = (struct ip_esp_hdr *)((unsigned char *)esph - 4);
325cac2661cSSteffen Klassert 		extra->seqhi = esph->spi;
3267862b405SSteffen Klassert 		esph->seq_no = htonl(seqhi);
327cac2661cSSteffen Klassert 	}
328cac2661cSSteffen Klassert 
329cac2661cSSteffen Klassert 	esph->spi = x->id.spi;
330cac2661cSSteffen Klassert 
331cac2661cSSteffen Klassert 	return esph;
332cac2661cSSteffen Klassert }
333cac2661cSSteffen Klassert 
3347021b2e1SHerbert Xu static void esp_output_done_esn(struct crypto_async_request *base, int err)
3357021b2e1SHerbert Xu {
3367021b2e1SHerbert Xu 	struct sk_buff *skb = base->data;
3377021b2e1SHerbert Xu 
3387021b2e1SHerbert Xu 	esp_output_restore_header(skb);
3397021b2e1SHerbert Xu 	esp_output_done(base, err);
3407021b2e1SHerbert Xu }
3417021b2e1SHerbert Xu 
342eecd227aSSabrina Dubroca static struct ip_esp_hdr *esp_output_udp_encap(struct sk_buff *skb,
343eecd227aSSabrina Dubroca 					       int encap_type,
344eecd227aSSabrina Dubroca 					       struct esp_info *esp,
345eecd227aSSabrina Dubroca 					       __be16 sport,
346eecd227aSSabrina Dubroca 					       __be16 dport)
3471da177e4SLinus Torvalds {
3481da177e4SLinus Torvalds 	struct udphdr *uh;
349d5a0a1e3SAl Viro 	__be32 *udpdata32;
3508dfb4ebaSSabrina Dubroca 	unsigned int len;
35138320c70SHerbert Xu 
352eecd227aSSabrina Dubroca 	len = skb->len + esp->tailen - skb_transport_offset(skb);
353e27cca96SSabrina Dubroca 	if (len + sizeof(struct iphdr) > IP_MAX_MTU)
354eecd227aSSabrina Dubroca 		return ERR_PTR(-EMSGSIZE);
355eecd227aSSabrina Dubroca 
356eecd227aSSabrina Dubroca 	uh = (struct udphdr *)esp->esph;
357eecd227aSSabrina Dubroca 	uh->source = sport;
358eecd227aSSabrina Dubroca 	uh->dest = dport;
359eecd227aSSabrina Dubroca 	uh->len = htons(len);
360eecd227aSSabrina Dubroca 	uh->check = 0;
361eecd227aSSabrina Dubroca 
362eecd227aSSabrina Dubroca 	*skb_mac_header(skb) = IPPROTO_UDP;
363eecd227aSSabrina Dubroca 
364eecd227aSSabrina Dubroca 	if (encap_type == UDP_ENCAP_ESPINUDP_NON_IKE) {
365eecd227aSSabrina Dubroca 		udpdata32 = (__be32 *)(uh + 1);
366eecd227aSSabrina Dubroca 		udpdata32[0] = udpdata32[1] = 0;
367eecd227aSSabrina Dubroca 		return (struct ip_esp_hdr *)(udpdata32 + 2);
368eecd227aSSabrina Dubroca 	}
369eecd227aSSabrina Dubroca 
370eecd227aSSabrina Dubroca 	return (struct ip_esp_hdr *)(uh + 1);
371eecd227aSSabrina Dubroca }
372eecd227aSSabrina Dubroca 
373e27cca96SSabrina Dubroca #ifdef CONFIG_INET_ESPINTCP
374e27cca96SSabrina Dubroca static struct ip_esp_hdr *esp_output_tcp_encap(struct xfrm_state *x,
375e27cca96SSabrina Dubroca 						    struct sk_buff *skb,
376e27cca96SSabrina Dubroca 						    struct esp_info *esp)
377e27cca96SSabrina Dubroca {
378e27cca96SSabrina Dubroca 	__be16 *lenp = (void *)esp->esph;
379e27cca96SSabrina Dubroca 	struct ip_esp_hdr *esph;
380e27cca96SSabrina Dubroca 	unsigned int len;
381e27cca96SSabrina Dubroca 	struct sock *sk;
382e27cca96SSabrina Dubroca 
383e27cca96SSabrina Dubroca 	len = skb->len + esp->tailen - skb_transport_offset(skb);
384e27cca96SSabrina Dubroca 	if (len > IP_MAX_MTU)
385e27cca96SSabrina Dubroca 		return ERR_PTR(-EMSGSIZE);
386e27cca96SSabrina Dubroca 
387e27cca96SSabrina Dubroca 	rcu_read_lock();
388e27cca96SSabrina Dubroca 	sk = esp_find_tcp_sk(x);
389e27cca96SSabrina Dubroca 	rcu_read_unlock();
390e27cca96SSabrina Dubroca 
391e27cca96SSabrina Dubroca 	if (IS_ERR(sk))
392e27cca96SSabrina Dubroca 		return ERR_CAST(sk);
393e27cca96SSabrina Dubroca 
394e27cca96SSabrina Dubroca 	*lenp = htons(len);
395e27cca96SSabrina Dubroca 	esph = (struct ip_esp_hdr *)(lenp + 1);
396e27cca96SSabrina Dubroca 
397e27cca96SSabrina Dubroca 	return esph;
398e27cca96SSabrina Dubroca }
399e27cca96SSabrina Dubroca #else
400e27cca96SSabrina Dubroca static struct ip_esp_hdr *esp_output_tcp_encap(struct xfrm_state *x,
401e27cca96SSabrina Dubroca 						    struct sk_buff *skb,
402e27cca96SSabrina Dubroca 						    struct esp_info *esp)
403e27cca96SSabrina Dubroca {
404e27cca96SSabrina Dubroca 	return ERR_PTR(-EOPNOTSUPP);
405e27cca96SSabrina Dubroca }
406e27cca96SSabrina Dubroca #endif
407e27cca96SSabrina Dubroca 
408eecd227aSSabrina Dubroca static int esp_output_encap(struct xfrm_state *x, struct sk_buff *skb,
409eecd227aSSabrina Dubroca 			    struct esp_info *esp)
410eecd227aSSabrina Dubroca {
411eecd227aSSabrina Dubroca 	struct xfrm_encap_tmpl *encap = x->encap;
412eecd227aSSabrina Dubroca 	struct ip_esp_hdr *esph;
413eecd227aSSabrina Dubroca 	__be16 sport, dport;
414eecd227aSSabrina Dubroca 	int encap_type;
415eecd227aSSabrina Dubroca 
41638320c70SHerbert Xu 	spin_lock_bh(&x->lock);
41738320c70SHerbert Xu 	sport = encap->encap_sport;
41838320c70SHerbert Xu 	dport = encap->encap_dport;
41938320c70SHerbert Xu 	encap_type = encap->encap_type;
42038320c70SHerbert Xu 	spin_unlock_bh(&x->lock);
4211da177e4SLinus Torvalds 
42238320c70SHerbert Xu 	switch (encap_type) {
4231da177e4SLinus Torvalds 	default:
4241da177e4SLinus Torvalds 	case UDP_ENCAP_ESPINUDP:
4251da177e4SLinus Torvalds 	case UDP_ENCAP_ESPINUDP_NON_IKE:
426eecd227aSSabrina Dubroca 		esph = esp_output_udp_encap(skb, encap_type, esp, sport, dport);
4271da177e4SLinus Torvalds 		break;
428e27cca96SSabrina Dubroca 	case TCP_ENCAP_ESPINTCP:
429e27cca96SSabrina Dubroca 		esph = esp_output_tcp_encap(x, skb, esp);
430e27cca96SSabrina Dubroca 		break;
4311da177e4SLinus Torvalds 	}
4321da177e4SLinus Torvalds 
433eecd227aSSabrina Dubroca 	if (IS_ERR(esph))
434eecd227aSSabrina Dubroca 		return PTR_ERR(esph);
435eecd227aSSabrina Dubroca 
436fca11ebdSSteffen Klassert 	esp->esph = esph;
4378dfb4ebaSSabrina Dubroca 
4388dfb4ebaSSabrina Dubroca 	return 0;
43937fedd3aSHerbert Xu }
4401da177e4SLinus Torvalds 
441fca11ebdSSteffen Klassert int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *esp)
442fca11ebdSSteffen Klassert {
443fca11ebdSSteffen Klassert 	u8 *tail;
444fca11ebdSSteffen Klassert 	int nfrags;
4450e78a873SSteffen Klassert 	int esph_offset;
446fca11ebdSSteffen Klassert 	struct page *page;
447fca11ebdSSteffen Klassert 	struct sk_buff *trailer;
448fca11ebdSSteffen Klassert 	int tailen = esp->tailen;
449fca11ebdSSteffen Klassert 
450e27cca96SSabrina Dubroca 	/* this is non-NULL only with TCP/UDP Encapsulation */
4518dfb4ebaSSabrina Dubroca 	if (x->encap) {
452eecd227aSSabrina Dubroca 		int err = esp_output_encap(x, skb, esp);
4538dfb4ebaSSabrina Dubroca 
4548dfb4ebaSSabrina Dubroca 		if (err < 0)
4558dfb4ebaSSabrina Dubroca 			return err;
4568dfb4ebaSSabrina Dubroca 	}
457fca11ebdSSteffen Klassert 
458cac2661cSSteffen Klassert 	if (!skb_cloned(skb)) {
45954ffd790SSteffen Klassert 		if (tailen <= skb_tailroom(skb)) {
460cac2661cSSteffen Klassert 			nfrags = 1;
461cac2661cSSteffen Klassert 			trailer = skb;
462cac2661cSSteffen Klassert 			tail = skb_tail_pointer(trailer);
4631da177e4SLinus Torvalds 
464cac2661cSSteffen Klassert 			goto skip_cow;
465cac2661cSSteffen Klassert 		} else if ((skb_shinfo(skb)->nr_frags < MAX_SKB_FRAGS)
466cac2661cSSteffen Klassert 			   && !skb_has_frag_list(skb)) {
467cac2661cSSteffen Klassert 			int allocsize;
468cac2661cSSteffen Klassert 			struct sock *sk = skb->sk;
469cac2661cSSteffen Klassert 			struct page_frag *pfrag = &x->xfrag;
4707021b2e1SHerbert Xu 
471fca11ebdSSteffen Klassert 			esp->inplace = false;
472fca11ebdSSteffen Klassert 
473cac2661cSSteffen Klassert 			allocsize = ALIGN(tailen, L1_CACHE_BYTES);
474cac2661cSSteffen Klassert 
475cac2661cSSteffen Klassert 			spin_lock_bh(&x->lock);
476cac2661cSSteffen Klassert 
477cac2661cSSteffen Klassert 			if (unlikely(!skb_page_frag_refill(allocsize, pfrag, GFP_ATOMIC))) {
478cac2661cSSteffen Klassert 				spin_unlock_bh(&x->lock);
479cac2661cSSteffen Klassert 				goto cow;
4807021b2e1SHerbert Xu 			}
4817021b2e1SHerbert Xu 
482cac2661cSSteffen Klassert 			page = pfrag->page;
483cac2661cSSteffen Klassert 			get_page(page);
484cac2661cSSteffen Klassert 
4859bd6b629SWillem de Bruijn 			tail = page_address(page) + pfrag->offset;
486cac2661cSSteffen Klassert 
487fca11ebdSSteffen Klassert 			esp_output_fill_trailer(tail, esp->tfclen, esp->plen, esp->proto);
488cac2661cSSteffen Klassert 
489cac2661cSSteffen Klassert 			nfrags = skb_shinfo(skb)->nr_frags;
490cac2661cSSteffen Klassert 
491cac2661cSSteffen Klassert 			__skb_fill_page_desc(skb, nfrags, page, pfrag->offset,
492cac2661cSSteffen Klassert 					     tailen);
493cac2661cSSteffen Klassert 			skb_shinfo(skb)->nr_frags = ++nfrags;
494cac2661cSSteffen Klassert 
495cac2661cSSteffen Klassert 			pfrag->offset = pfrag->offset + allocsize;
49636ff0dd3SSteffen Klassert 
49736ff0dd3SSteffen Klassert 			spin_unlock_bh(&x->lock);
49836ff0dd3SSteffen Klassert 
499cac2661cSSteffen Klassert 			nfrags++;
500cac2661cSSteffen Klassert 
501cac2661cSSteffen Klassert 			skb->len += tailen;
502cac2661cSSteffen Klassert 			skb->data_len += tailen;
503cac2661cSSteffen Klassert 			skb->truesize += tailen;
50409db5124SMartin Willi 			if (sk && sk_fullsock(sk))
50514afee4bSReshetova, Elena 				refcount_add(tailen, &sk->sk_wmem_alloc);
506cac2661cSSteffen Klassert 
507fca11ebdSSteffen Klassert 			goto out;
508fca11ebdSSteffen Klassert 		}
509fca11ebdSSteffen Klassert 	}
510cac2661cSSteffen Klassert 
511fca11ebdSSteffen Klassert cow:
5120e78a873SSteffen Klassert 	esph_offset = (unsigned char *)esp->esph - skb_transport_header(skb);
5130e78a873SSteffen Klassert 
514fca11ebdSSteffen Klassert 	nfrags = skb_cow_data(skb, tailen, &trailer);
515fca11ebdSSteffen Klassert 	if (nfrags < 0)
516fca11ebdSSteffen Klassert 		goto out;
517fca11ebdSSteffen Klassert 	tail = skb_tail_pointer(trailer);
5180e78a873SSteffen Klassert 	esp->esph = (struct ip_esp_hdr *)(skb_transport_header(skb) + esph_offset);
5197021b2e1SHerbert Xu 
520fca11ebdSSteffen Klassert skip_cow:
521fca11ebdSSteffen Klassert 	esp_output_fill_trailer(tail, esp->tfclen, esp->plen, esp->proto);
522fca11ebdSSteffen Klassert 	pskb_put(skb, trailer, tailen);
523fca11ebdSSteffen Klassert 
524fca11ebdSSteffen Klassert out:
525fca11ebdSSteffen Klassert 	return nfrags;
526fca11ebdSSteffen Klassert }
527fca11ebdSSteffen Klassert EXPORT_SYMBOL_GPL(esp_output_head);
528fca11ebdSSteffen Klassert 
529fca11ebdSSteffen Klassert int esp_output_tail(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *esp)
530fca11ebdSSteffen Klassert {
531fca11ebdSSteffen Klassert 	u8 *iv;
532fca11ebdSSteffen Klassert 	int alen;
533fca11ebdSSteffen Klassert 	void *tmp;
534fca11ebdSSteffen Klassert 	int ivlen;
535fca11ebdSSteffen Klassert 	int assoclen;
536fca11ebdSSteffen Klassert 	int extralen;
537fca11ebdSSteffen Klassert 	struct page *page;
538fca11ebdSSteffen Klassert 	struct ip_esp_hdr *esph;
539fca11ebdSSteffen Klassert 	struct crypto_aead *aead;
540fca11ebdSSteffen Klassert 	struct aead_request *req;
541fca11ebdSSteffen Klassert 	struct scatterlist *sg, *dsg;
542fca11ebdSSteffen Klassert 	struct esp_output_extra *extra;
543fca11ebdSSteffen Klassert 	int err = -ENOMEM;
544fca11ebdSSteffen Klassert 
545fca11ebdSSteffen Klassert 	assoclen = sizeof(struct ip_esp_hdr);
546fca11ebdSSteffen Klassert 	extralen = 0;
547fca11ebdSSteffen Klassert 
548fca11ebdSSteffen Klassert 	if (x->props.flags & XFRM_STATE_ESN) {
549fca11ebdSSteffen Klassert 		extralen += sizeof(*extra);
550fca11ebdSSteffen Klassert 		assoclen += sizeof(__be32);
551fca11ebdSSteffen Klassert 	}
552fca11ebdSSteffen Klassert 
553fca11ebdSSteffen Klassert 	aead = x->data;
554fca11ebdSSteffen Klassert 	alen = crypto_aead_authsize(aead);
555fca11ebdSSteffen Klassert 	ivlen = crypto_aead_ivsize(aead);
556fca11ebdSSteffen Klassert 
557fca11ebdSSteffen Klassert 	tmp = esp_alloc_tmp(aead, esp->nfrags + 2, extralen);
558e892d2d4SSteffen Klassert 	if (!tmp)
559cac2661cSSteffen Klassert 		goto error;
560cac2661cSSteffen Klassert 
561cac2661cSSteffen Klassert 	extra = esp_tmp_extra(tmp);
562cac2661cSSteffen Klassert 	iv = esp_tmp_iv(aead, tmp, extralen);
563cac2661cSSteffen Klassert 	req = esp_tmp_req(aead, iv);
564cac2661cSSteffen Klassert 	sg = esp_req_sg(aead, req);
565cac2661cSSteffen Klassert 
566fca11ebdSSteffen Klassert 	if (esp->inplace)
567fca11ebdSSteffen Klassert 		dsg = sg;
568fca11ebdSSteffen Klassert 	else
569fca11ebdSSteffen Klassert 		dsg = &sg[esp->nfrags];
570cac2661cSSteffen Klassert 
571fca11ebdSSteffen Klassert 	esph = esp_output_set_extra(skb, x, esp->esph, extra);
572fca11ebdSSteffen Klassert 	esp->esph = esph;
573fca11ebdSSteffen Klassert 
574fca11ebdSSteffen Klassert 	sg_init_table(sg, esp->nfrags);
5753f297707SJason A. Donenfeld 	err = skb_to_sgvec(skb, sg,
5767021b2e1SHerbert Xu 		           (unsigned char *)esph - skb->data,
577fca11ebdSSteffen Klassert 		           assoclen + ivlen + esp->clen + alen);
5783f297707SJason A. Donenfeld 	if (unlikely(err < 0))
579e6194923SSteffen Klassert 		goto error_free;
580fca11ebdSSteffen Klassert 
581fca11ebdSSteffen Klassert 	if (!esp->inplace) {
582fca11ebdSSteffen Klassert 		int allocsize;
583fca11ebdSSteffen Klassert 		struct page_frag *pfrag = &x->xfrag;
5840dc49e9bSSteffen Klassert 
585cac2661cSSteffen Klassert 		allocsize = ALIGN(skb->data_len, L1_CACHE_BYTES);
586cac2661cSSteffen Klassert 
587fca11ebdSSteffen Klassert 		spin_lock_bh(&x->lock);
588cac2661cSSteffen Klassert 		if (unlikely(!skb_page_frag_refill(allocsize, pfrag, GFP_ATOMIC))) {
589cac2661cSSteffen Klassert 			spin_unlock_bh(&x->lock);
590e6194923SSteffen Klassert 			goto error_free;
591cac2661cSSteffen Klassert 		}
592cac2661cSSteffen Klassert 
593cac2661cSSteffen Klassert 		skb_shinfo(skb)->nr_frags = 1;
594cac2661cSSteffen Klassert 
595cac2661cSSteffen Klassert 		page = pfrag->page;
596cac2661cSSteffen Klassert 		get_page(page);
597cac2661cSSteffen Klassert 		/* replace page frags in skb with new page */
598cac2661cSSteffen Klassert 		__skb_fill_page_desc(skb, 0, page, pfrag->offset, skb->data_len);
599cac2661cSSteffen Klassert 		pfrag->offset = pfrag->offset + allocsize;
600fca11ebdSSteffen Klassert 		spin_unlock_bh(&x->lock);
601cac2661cSSteffen Klassert 
602cac2661cSSteffen Klassert 		sg_init_table(dsg, skb_shinfo(skb)->nr_frags + 1);
6033f297707SJason A. Donenfeld 		err = skb_to_sgvec(skb, dsg,
604cac2661cSSteffen Klassert 			           (unsigned char *)esph - skb->data,
605fca11ebdSSteffen Klassert 			           assoclen + ivlen + esp->clen + alen);
6063f297707SJason A. Donenfeld 		if (unlikely(err < 0))
607e6194923SSteffen Klassert 			goto error_free;
608cac2661cSSteffen Klassert 	}
609cac2661cSSteffen Klassert 
610cac2661cSSteffen Klassert 	if ((x->props.flags & XFRM_STATE_ESN))
611cac2661cSSteffen Klassert 		aead_request_set_callback(req, 0, esp_output_done_esn, skb);
612cac2661cSSteffen Klassert 	else
613cac2661cSSteffen Klassert 		aead_request_set_callback(req, 0, esp_output_done, skb);
614cac2661cSSteffen Klassert 
615fca11ebdSSteffen Klassert 	aead_request_set_crypt(req, sg, dsg, ivlen + esp->clen, iv);
6167021b2e1SHerbert Xu 	aead_request_set_ad(req, assoclen);
6171da177e4SLinus Torvalds 
6187021b2e1SHerbert Xu 	memset(iv, 0, ivlen);
619fca11ebdSSteffen Klassert 	memcpy(iv + ivlen - min(ivlen, 8), (u8 *)&esp->seqno + 8 - min(ivlen, 8),
6207021b2e1SHerbert Xu 	       min(ivlen, 8));
6216b7326c8SHerbert Xu 
62238320c70SHerbert Xu 	ESP_SKB_CB(skb)->tmp = tmp;
6237021b2e1SHerbert Xu 	err = crypto_aead_encrypt(req);
6247021b2e1SHerbert Xu 
6257021b2e1SHerbert Xu 	switch (err) {
6267021b2e1SHerbert Xu 	case -EINPROGRESS:
62738320c70SHerbert Xu 		goto error;
6281da177e4SLinus Torvalds 
629068c2e70SGilad Ben-Yossef 	case -ENOSPC:
63038320c70SHerbert Xu 		err = NET_XMIT_DROP;
6317021b2e1SHerbert Xu 		break;
6327021b2e1SHerbert Xu 
6337021b2e1SHerbert Xu 	case 0:
6347021b2e1SHerbert Xu 		if ((x->props.flags & XFRM_STATE_ESN))
6357021b2e1SHerbert Xu 			esp_output_restore_header(skb);
6367021b2e1SHerbert Xu 	}
6371da177e4SLinus Torvalds 
638cac2661cSSteffen Klassert 	if (sg != dsg)
639cac2661cSSteffen Klassert 		esp_ssg_unref(x, tmp);
640b7c6538cSHerbert Xu 
641e27cca96SSabrina Dubroca 	if (!err && x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP)
642e27cca96SSabrina Dubroca 		err = esp_output_tail_tcp(x, skb);
643e27cca96SSabrina Dubroca 
644e6194923SSteffen Klassert error_free:
645e6194923SSteffen Klassert 	kfree(tmp);
6461da177e4SLinus Torvalds error:
6471da177e4SLinus Torvalds 	return err;
6481da177e4SLinus Torvalds }
649fca11ebdSSteffen Klassert EXPORT_SYMBOL_GPL(esp_output_tail);
6501da177e4SLinus Torvalds 
651fca11ebdSSteffen Klassert static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
652fca11ebdSSteffen Klassert {
653fca11ebdSSteffen Klassert 	int alen;
654fca11ebdSSteffen Klassert 	int blksize;
655fca11ebdSSteffen Klassert 	struct ip_esp_hdr *esph;
656fca11ebdSSteffen Klassert 	struct crypto_aead *aead;
657fca11ebdSSteffen Klassert 	struct esp_info esp;
658fca11ebdSSteffen Klassert 
659fca11ebdSSteffen Klassert 	esp.inplace = true;
660fca11ebdSSteffen Klassert 
661fca11ebdSSteffen Klassert 	esp.proto = *skb_mac_header(skb);
662fca11ebdSSteffen Klassert 	*skb_mac_header(skb) = IPPROTO_ESP;
663fca11ebdSSteffen Klassert 
664fca11ebdSSteffen Klassert 	/* skb is pure payload to encrypt */
665fca11ebdSSteffen Klassert 
666fca11ebdSSteffen Klassert 	aead = x->data;
667fca11ebdSSteffen Klassert 	alen = crypto_aead_authsize(aead);
668fca11ebdSSteffen Klassert 
669fca11ebdSSteffen Klassert 	esp.tfclen = 0;
670fca11ebdSSteffen Klassert 	if (x->tfcpad) {
671fca11ebdSSteffen Klassert 		struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb);
672fca11ebdSSteffen Klassert 		u32 padto;
673fca11ebdSSteffen Klassert 
674*a6d95c5aSJiri Bohac 		padto = min(x->tfcpad, xfrm_state_mtu(x, dst->child_mtu_cached));
675fca11ebdSSteffen Klassert 		if (skb->len < padto)
676fca11ebdSSteffen Klassert 			esp.tfclen = padto - skb->len;
677fca11ebdSSteffen Klassert 	}
678fca11ebdSSteffen Klassert 	blksize = ALIGN(crypto_aead_blocksize(aead), 4);
679fca11ebdSSteffen Klassert 	esp.clen = ALIGN(skb->len + 2 + esp.tfclen, blksize);
680fca11ebdSSteffen Klassert 	esp.plen = esp.clen - skb->len - esp.tfclen;
681fca11ebdSSteffen Klassert 	esp.tailen = esp.tfclen + esp.plen + alen;
682fca11ebdSSteffen Klassert 
683fca11ebdSSteffen Klassert 	esp.esph = ip_esp_hdr(skb);
684fca11ebdSSteffen Klassert 
685fca11ebdSSteffen Klassert 	esp.nfrags = esp_output_head(x, skb, &esp);
686fca11ebdSSteffen Klassert 	if (esp.nfrags < 0)
687fca11ebdSSteffen Klassert 		return esp.nfrags;
688fca11ebdSSteffen Klassert 
689fca11ebdSSteffen Klassert 	esph = esp.esph;
690fca11ebdSSteffen Klassert 	esph->spi = x->id.spi;
691fca11ebdSSteffen Klassert 
692fca11ebdSSteffen Klassert 	esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low);
693fca11ebdSSteffen Klassert 	esp.seqno = cpu_to_be64(XFRM_SKB_CB(skb)->seq.output.low +
694fca11ebdSSteffen Klassert 				 ((u64)XFRM_SKB_CB(skb)->seq.output.hi << 32));
695fca11ebdSSteffen Klassert 
696fca11ebdSSteffen Klassert 	skb_push(skb, -skb_network_offset(skb));
697fca11ebdSSteffen Klassert 
698fca11ebdSSteffen Klassert 	return esp_output_tail(x, skb, &esp);
699fca11ebdSSteffen Klassert }
700fca11ebdSSteffen Klassert 
70147ebcc0bSYossi Kuperman static inline int esp_remove_trailer(struct sk_buff *skb)
70247ebcc0bSYossi Kuperman {
70347ebcc0bSYossi Kuperman 	struct xfrm_state *x = xfrm_input_state(skb);
70447ebcc0bSYossi Kuperman 	struct xfrm_offload *xo = xfrm_offload(skb);
70547ebcc0bSYossi Kuperman 	struct crypto_aead *aead = x->data;
70647ebcc0bSYossi Kuperman 	int alen, hlen, elen;
70747ebcc0bSYossi Kuperman 	int padlen, trimlen;
70847ebcc0bSYossi Kuperman 	__wsum csumdiff;
70947ebcc0bSYossi Kuperman 	u8 nexthdr[2];
71047ebcc0bSYossi Kuperman 	int ret;
71147ebcc0bSYossi Kuperman 
71247ebcc0bSYossi Kuperman 	alen = crypto_aead_authsize(aead);
71347ebcc0bSYossi Kuperman 	hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead);
71447ebcc0bSYossi Kuperman 	elen = skb->len - hlen;
71547ebcc0bSYossi Kuperman 
71647ebcc0bSYossi Kuperman 	if (xo && (xo->flags & XFRM_ESP_NO_TRAILER)) {
71747ebcc0bSYossi Kuperman 		ret = xo->proto;
71847ebcc0bSYossi Kuperman 		goto out;
71947ebcc0bSYossi Kuperman 	}
72047ebcc0bSYossi Kuperman 
72147ebcc0bSYossi Kuperman 	if (skb_copy_bits(skb, skb->len - alen - 2, nexthdr, 2))
72247ebcc0bSYossi Kuperman 		BUG();
72347ebcc0bSYossi Kuperman 
72447ebcc0bSYossi Kuperman 	ret = -EINVAL;
72547ebcc0bSYossi Kuperman 	padlen = nexthdr[0];
72647ebcc0bSYossi Kuperman 	if (padlen + 2 + alen >= elen) {
72747ebcc0bSYossi Kuperman 		net_dbg_ratelimited("ipsec esp packet is garbage padlen=%d, elen=%d\n",
72847ebcc0bSYossi Kuperman 				    padlen + 2, elen - alen);
72947ebcc0bSYossi Kuperman 		goto out;
73047ebcc0bSYossi Kuperman 	}
73147ebcc0bSYossi Kuperman 
73247ebcc0bSYossi Kuperman 	trimlen = alen + padlen + 2;
73347ebcc0bSYossi Kuperman 	if (skb->ip_summed == CHECKSUM_COMPLETE) {
73447ebcc0bSYossi Kuperman 		csumdiff = skb_checksum(skb, skb->len - trimlen, trimlen, 0);
73547ebcc0bSYossi Kuperman 		skb->csum = csum_block_sub(skb->csum, csumdiff,
73647ebcc0bSYossi Kuperman 					   skb->len - trimlen);
73747ebcc0bSYossi Kuperman 	}
73847ebcc0bSYossi Kuperman 	pskb_trim(skb, skb->len - trimlen);
73947ebcc0bSYossi Kuperman 
74047ebcc0bSYossi Kuperman 	ret = nexthdr[1];
74147ebcc0bSYossi Kuperman 
74247ebcc0bSYossi Kuperman out:
74347ebcc0bSYossi Kuperman 	return ret;
74447ebcc0bSYossi Kuperman }
74547ebcc0bSYossi Kuperman 
746fca11ebdSSteffen Klassert int esp_input_done2(struct sk_buff *skb, int err)
7471da177e4SLinus Torvalds {
748b71d1d42SEric Dumazet 	const struct iphdr *iph;
74938320c70SHerbert Xu 	struct xfrm_state *x = xfrm_input_state(skb);
750d77e38e6SSteffen Klassert 	struct xfrm_offload *xo = xfrm_offload(skb);
7511c5ad13fSMathias Krause 	struct crypto_aead *aead = x->data;
75238320c70SHerbert Xu 	int hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead);
75331a4ab93SHerbert Xu 	int ihl;
7541da177e4SLinus Torvalds 
7551d9bfacdSJiapeng Chong 	if (!xo || !(xo->flags & CRYPTO_DONE))
75638320c70SHerbert Xu 		kfree(ESP_SKB_CB(skb)->tmp);
7570ebea8efSHerbert Xu 
7586b7326c8SHerbert Xu 	if (unlikely(err))
759668dc8afSHerbert Xu 		goto out;
7601da177e4SLinus Torvalds 
76147ebcc0bSYossi Kuperman 	err = esp_remove_trailer(skb);
76247ebcc0bSYossi Kuperman 	if (unlikely(err < 0))
7631da177e4SLinus Torvalds 		goto out;
7641da177e4SLinus Torvalds 
765eddc9ec5SArnaldo Carvalho de Melo 	iph = ip_hdr(skb);
76631a4ab93SHerbert Xu 	ihl = iph->ihl * 4;
76731a4ab93SHerbert Xu 
7681da177e4SLinus Torvalds 	if (x->encap) {
769752c1f4cSHerbert Xu 		struct xfrm_encap_tmpl *encap = x->encap;
770e27cca96SSabrina Dubroca 		struct tcphdr *th = (void *)(skb_network_header(skb) + ihl);
771d56f90a7SArnaldo Carvalho de Melo 		struct udphdr *uh = (void *)(skb_network_header(skb) + ihl);
77225f6802bSSabrina Dubroca 		__be16 source;
77325f6802bSSabrina Dubroca 
77425f6802bSSabrina Dubroca 		switch (x->encap->encap_type) {
775e27cca96SSabrina Dubroca 		case TCP_ENCAP_ESPINTCP:
776e27cca96SSabrina Dubroca 			source = th->source;
777e27cca96SSabrina Dubroca 			break;
77825f6802bSSabrina Dubroca 		case UDP_ENCAP_ESPINUDP:
77925f6802bSSabrina Dubroca 		case UDP_ENCAP_ESPINUDP_NON_IKE:
78025f6802bSSabrina Dubroca 			source = uh->source;
78125f6802bSSabrina Dubroca 			break;
78225f6802bSSabrina Dubroca 		default:
78325f6802bSSabrina Dubroca 			WARN_ON_ONCE(1);
78425f6802bSSabrina Dubroca 			err = -EINVAL;
78525f6802bSSabrina Dubroca 			goto out;
78625f6802bSSabrina Dubroca 		}
787752c1f4cSHerbert Xu 
7881da177e4SLinus Torvalds 		/*
7891da177e4SLinus Torvalds 		 * 1) if the NAT-T peer's IP or port changed then
7901da177e4SLinus Torvalds 		 *    advertize the change to the keying daemon.
7911da177e4SLinus Torvalds 		 *    This is an inbound SA, so just compare
7921da177e4SLinus Torvalds 		 *    SRC ports.
7931da177e4SLinus Torvalds 		 */
794752c1f4cSHerbert Xu 		if (iph->saddr != x->props.saddr.a4 ||
79525f6802bSSabrina Dubroca 		    source != encap->encap_sport) {
7961da177e4SLinus Torvalds 			xfrm_address_t ipaddr;
7971da177e4SLinus Torvalds 
798752c1f4cSHerbert Xu 			ipaddr.a4 = iph->saddr;
79925f6802bSSabrina Dubroca 			km_new_mapping(x, &ipaddr, source);
8001da177e4SLinus Torvalds 
8011da177e4SLinus Torvalds 			/* XXX: perhaps add an extra
8021da177e4SLinus Torvalds 			 * policy check here, to see
8031da177e4SLinus Torvalds 			 * if we should allow or
8041da177e4SLinus Torvalds 			 * reject a packet from a
8051da177e4SLinus Torvalds 			 * different source
8061da177e4SLinus Torvalds 			 * address/port.
8071da177e4SLinus Torvalds 			 */
8081da177e4SLinus Torvalds 		}
8091da177e4SLinus Torvalds 
8101da177e4SLinus Torvalds 		/*
8111da177e4SLinus Torvalds 		 * 2) ignore UDP/TCP checksums in case
8121da177e4SLinus Torvalds 		 *    of NAT-T in Transport Mode, or
8131da177e4SLinus Torvalds 		 *    perform other post-processing fixes
814752c1f4cSHerbert Xu 		 *    as per draft-ietf-ipsec-udp-encaps-06,
8151da177e4SLinus Torvalds 		 *    section 3.1.2
8161da177e4SLinus Torvalds 		 */
8178bd17075SHerbert Xu 		if (x->props.mode == XFRM_MODE_TRANSPORT)
8181da177e4SLinus Torvalds 			skb->ip_summed = CHECKSUM_UNNECESSARY;
819752c1f4cSHerbert Xu 	}
8201da177e4SLinus Torvalds 
821ec9567a9SIlan Tayari 	skb_pull_rcsum(skb, hlen);
8227143dfacSLi RongQing 	if (x->props.mode == XFRM_MODE_TUNNEL)
8237143dfacSLi RongQing 		skb_reset_transport_header(skb);
8247143dfacSLi RongQing 	else
825967b05f6SArnaldo Carvalho de Melo 		skb_set_transport_header(skb, -ihl);
826752c1f4cSHerbert Xu 
82738320c70SHerbert Xu 	/* RFC4303: Drop dummy packets without any error */
82838320c70SHerbert Xu 	if (err == IPPROTO_NONE)
82938320c70SHerbert Xu 		err = -EINVAL;
83038320c70SHerbert Xu 
83138320c70SHerbert Xu out:
83238320c70SHerbert Xu 	return err;
83338320c70SHerbert Xu }
834fca11ebdSSteffen Klassert EXPORT_SYMBOL_GPL(esp_input_done2);
83538320c70SHerbert Xu 
83638320c70SHerbert Xu static void esp_input_done(struct crypto_async_request *base, int err)
83738320c70SHerbert Xu {
83838320c70SHerbert Xu 	struct sk_buff *skb = base->data;
83938320c70SHerbert Xu 
84038320c70SHerbert Xu 	xfrm_input_resume(skb, esp_input_done2(skb, err));
84138320c70SHerbert Xu }
84238320c70SHerbert Xu 
8437021b2e1SHerbert Xu static void esp_input_restore_header(struct sk_buff *skb)
8447021b2e1SHerbert Xu {
8457021b2e1SHerbert Xu 	esp_restore_header(skb, 0);
8467021b2e1SHerbert Xu 	__skb_pull(skb, 4);
8477021b2e1SHerbert Xu }
8487021b2e1SHerbert Xu 
849cac2661cSSteffen Klassert static void esp_input_set_header(struct sk_buff *skb, __be32 *seqhi)
850cac2661cSSteffen Klassert {
851cac2661cSSteffen Klassert 	struct xfrm_state *x = xfrm_input_state(skb);
85260aa8046SColin Ian King 	struct ip_esp_hdr *esph;
853cac2661cSSteffen Klassert 
854cac2661cSSteffen Klassert 	/* For ESN we move the header forward by 4 bytes to
855cbd801b3SLu Wei 	 * accommodate the high bits.  We will move it back after
856cac2661cSSteffen Klassert 	 * decryption.
857cac2661cSSteffen Klassert 	 */
858cac2661cSSteffen Klassert 	if ((x->props.flags & XFRM_STATE_ESN)) {
859d58ff351SJohannes Berg 		esph = skb_push(skb, 4);
860cac2661cSSteffen Klassert 		*seqhi = esph->spi;
861cac2661cSSteffen Klassert 		esph->spi = esph->seq_no;
862cac2661cSSteffen Klassert 		esph->seq_no = XFRM_SKB_CB(skb)->seq.input.hi;
863cac2661cSSteffen Klassert 	}
864cac2661cSSteffen Klassert }
865cac2661cSSteffen Klassert 
8667021b2e1SHerbert Xu static void esp_input_done_esn(struct crypto_async_request *base, int err)
8677021b2e1SHerbert Xu {
8687021b2e1SHerbert Xu 	struct sk_buff *skb = base->data;
8697021b2e1SHerbert Xu 
8707021b2e1SHerbert Xu 	esp_input_restore_header(skb);
8717021b2e1SHerbert Xu 	esp_input_done(base, err);
8727021b2e1SHerbert Xu }
8737021b2e1SHerbert Xu 
87438320c70SHerbert Xu /*
87538320c70SHerbert Xu  * Note: detecting truncated vs. non-truncated authentication data is very
87638320c70SHerbert Xu  * expensive, so we only support truncated data, which is the recommended
87738320c70SHerbert Xu  * and common case.
87838320c70SHerbert Xu  */
87938320c70SHerbert Xu static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
88038320c70SHerbert Xu {
8811c5ad13fSMathias Krause 	struct crypto_aead *aead = x->data;
88238320c70SHerbert Xu 	struct aead_request *req;
88338320c70SHerbert Xu 	struct sk_buff *trailer;
8847021b2e1SHerbert Xu 	int ivlen = crypto_aead_ivsize(aead);
8850c05f983SHaishuang Yan 	int elen = skb->len - sizeof(struct ip_esp_hdr) - ivlen;
88638320c70SHerbert Xu 	int nfrags;
8870dc49e9bSSteffen Klassert 	int assoclen;
8880dc49e9bSSteffen Klassert 	int seqhilen;
8890dc49e9bSSteffen Klassert 	__be32 *seqhi;
89038320c70SHerbert Xu 	void *tmp;
89138320c70SHerbert Xu 	u8 *iv;
89238320c70SHerbert Xu 	struct scatterlist *sg;
89338320c70SHerbert Xu 	int err = -EINVAL;
89438320c70SHerbert Xu 
8950c05f983SHaishuang Yan 	if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr) + ivlen))
89638320c70SHerbert Xu 		goto out;
89738320c70SHerbert Xu 
89838320c70SHerbert Xu 	if (elen <= 0)
89938320c70SHerbert Xu 		goto out;
90038320c70SHerbert Xu 
9010c05f983SHaishuang Yan 	assoclen = sizeof(struct ip_esp_hdr);
9020dc49e9bSSteffen Klassert 	seqhilen = 0;
9030dc49e9bSSteffen Klassert 
9040dc49e9bSSteffen Klassert 	if (x->props.flags & XFRM_STATE_ESN) {
9050dc49e9bSSteffen Klassert 		seqhilen += sizeof(__be32);
9060dc49e9bSSteffen Klassert 		assoclen += seqhilen;
9070dc49e9bSSteffen Klassert 	}
9080dc49e9bSSteffen Klassert 
909cac2661cSSteffen Klassert 	if (!skb_cloned(skb)) {
910cac2661cSSteffen Klassert 		if (!skb_is_nonlinear(skb)) {
911cac2661cSSteffen Klassert 			nfrags = 1;
912cac2661cSSteffen Klassert 
913cac2661cSSteffen Klassert 			goto skip_cow;
914cac2661cSSteffen Klassert 		} else if (!skb_has_frag_list(skb)) {
915cac2661cSSteffen Klassert 			nfrags = skb_shinfo(skb)->nr_frags;
916cac2661cSSteffen Klassert 			nfrags++;
917cac2661cSSteffen Klassert 
918cac2661cSSteffen Klassert 			goto skip_cow;
919cac2661cSSteffen Klassert 		}
920cac2661cSSteffen Klassert 	}
921cac2661cSSteffen Klassert 
922cac2661cSSteffen Klassert 	err = skb_cow_data(skb, 0, &trailer);
923cac2661cSSteffen Klassert 	if (err < 0)
924cac2661cSSteffen Klassert 		goto out;
925cac2661cSSteffen Klassert 
926cac2661cSSteffen Klassert 	nfrags = err;
927cac2661cSSteffen Klassert 
928cac2661cSSteffen Klassert skip_cow:
92938320c70SHerbert Xu 	err = -ENOMEM;
9307021b2e1SHerbert Xu 	tmp = esp_alloc_tmp(aead, nfrags, seqhilen);
93138320c70SHerbert Xu 	if (!tmp)
93238320c70SHerbert Xu 		goto out;
93338320c70SHerbert Xu 
93438320c70SHerbert Xu 	ESP_SKB_CB(skb)->tmp = tmp;
935962fcef3SHerbert Xu 	seqhi = esp_tmp_extra(tmp);
9360dc49e9bSSteffen Klassert 	iv = esp_tmp_iv(aead, tmp, seqhilen);
93738320c70SHerbert Xu 	req = esp_tmp_req(aead, iv);
9387021b2e1SHerbert Xu 	sg = esp_req_sg(aead, req);
93938320c70SHerbert Xu 
940cac2661cSSteffen Klassert 	esp_input_set_header(skb, seqhi);
94138320c70SHerbert Xu 
94238320c70SHerbert Xu 	sg_init_table(sg, nfrags);
9433f297707SJason A. Donenfeld 	err = skb_to_sgvec(skb, sg, 0, skb->len);
944e6194923SSteffen Klassert 	if (unlikely(err < 0)) {
945e6194923SSteffen Klassert 		kfree(tmp);
9463f297707SJason A. Donenfeld 		goto out;
947e6194923SSteffen Klassert 	}
9480dc49e9bSSteffen Klassert 
949cac2661cSSteffen Klassert 	skb->ip_summed = CHECKSUM_NONE;
950cac2661cSSteffen Klassert 
951cac2661cSSteffen Klassert 	if ((x->props.flags & XFRM_STATE_ESN))
952cac2661cSSteffen Klassert 		aead_request_set_callback(req, 0, esp_input_done_esn, skb);
953cac2661cSSteffen Klassert 	else
954cac2661cSSteffen Klassert 		aead_request_set_callback(req, 0, esp_input_done, skb);
955cac2661cSSteffen Klassert 
9567021b2e1SHerbert Xu 	aead_request_set_crypt(req, sg, sg, elen + ivlen, iv);
9577021b2e1SHerbert Xu 	aead_request_set_ad(req, assoclen);
95838320c70SHerbert Xu 
95938320c70SHerbert Xu 	err = crypto_aead_decrypt(req);
96038320c70SHerbert Xu 	if (err == -EINPROGRESS)
96138320c70SHerbert Xu 		goto out;
96238320c70SHerbert Xu 
9637021b2e1SHerbert Xu 	if ((x->props.flags & XFRM_STATE_ESN))
9647021b2e1SHerbert Xu 		esp_input_restore_header(skb);
9657021b2e1SHerbert Xu 
96638320c70SHerbert Xu 	err = esp_input_done2(skb, err);
967752c1f4cSHerbert Xu 
968752c1f4cSHerbert Xu out:
969668dc8afSHerbert Xu 	return err;
9701da177e4SLinus Torvalds }
9711da177e4SLinus Torvalds 
972827789cbSSteffen Klassert static int esp4_err(struct sk_buff *skb, u32 info)
9731da177e4SLinus Torvalds {
9744fb236baSAlexey Dobriyan 	struct net *net = dev_net(skb->dev);
975b71d1d42SEric Dumazet 	const struct iphdr *iph = (const struct iphdr *)skb->data;
9761da177e4SLinus Torvalds 	struct ip_esp_hdr *esph = (struct ip_esp_hdr *)(skb->data+(iph->ihl<<2));
9771da177e4SLinus Torvalds 	struct xfrm_state *x;
9781da177e4SLinus Torvalds 
97955be7a9cSDavid S. Miller 	switch (icmp_hdr(skb)->type) {
98055be7a9cSDavid S. Miller 	case ICMP_DEST_UNREACH:
98155be7a9cSDavid S. Miller 		if (icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
982827789cbSSteffen Klassert 			return 0;
98379121184SGustavo A. R. Silva 		break;
98455be7a9cSDavid S. Miller 	case ICMP_REDIRECT:
98555be7a9cSDavid S. Miller 		break;
98655be7a9cSDavid S. Miller 	default:
987827789cbSSteffen Klassert 		return 0;
98855be7a9cSDavid S. Miller 	}
9891da177e4SLinus Torvalds 
990b71d1d42SEric Dumazet 	x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
991b71d1d42SEric Dumazet 			      esph->spi, IPPROTO_ESP, AF_INET);
9921da177e4SLinus Torvalds 	if (!x)
993827789cbSSteffen Klassert 		return 0;
99455be7a9cSDavid S. Miller 
995387aa65aSTimo Teräs 	if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH)
996d888f396SMaciej Żenczykowski 		ipv4_update_pmtu(skb, net, info, 0, IPPROTO_ESP);
997387aa65aSTimo Teräs 	else
9981042caa7SMaciej Żenczykowski 		ipv4_redirect(skb, net, 0, IPPROTO_ESP);
9991da177e4SLinus Torvalds 	xfrm_state_put(x);
1000827789cbSSteffen Klassert 
1001827789cbSSteffen Klassert 	return 0;
10021da177e4SLinus Torvalds }
10031da177e4SLinus Torvalds 
10041da177e4SLinus Torvalds static void esp_destroy(struct xfrm_state *x)
10051da177e4SLinus Torvalds {
10061c5ad13fSMathias Krause 	struct crypto_aead *aead = x->data;
10071da177e4SLinus Torvalds 
10081c5ad13fSMathias Krause 	if (!aead)
10091da177e4SLinus Torvalds 		return;
10101da177e4SLinus Torvalds 
10111c5ad13fSMathias Krause 	crypto_free_aead(aead);
10121da177e4SLinus Torvalds }
10131da177e4SLinus Torvalds 
10141a6509d9SHerbert Xu static int esp_init_aead(struct xfrm_state *x)
10151da177e4SLinus Torvalds {
10167021b2e1SHerbert Xu 	char aead_name[CRYPTO_MAX_ALG_NAME];
10171a6509d9SHerbert Xu 	struct crypto_aead *aead;
10181a6509d9SHerbert Xu 	int err;
10191a6509d9SHerbert Xu 
10207021b2e1SHerbert Xu 	err = -ENAMETOOLONG;
10217021b2e1SHerbert Xu 	if (snprintf(aead_name, CRYPTO_MAX_ALG_NAME, "%s(%s)",
10227021b2e1SHerbert Xu 		     x->geniv, x->aead->alg_name) >= CRYPTO_MAX_ALG_NAME)
10237021b2e1SHerbert Xu 		goto error;
10247021b2e1SHerbert Xu 
1025f58869c4SSteffen Klassert 	aead = crypto_alloc_aead(aead_name, 0, 0);
10261a6509d9SHerbert Xu 	err = PTR_ERR(aead);
10271a6509d9SHerbert Xu 	if (IS_ERR(aead))
10281a6509d9SHerbert Xu 		goto error;
10291a6509d9SHerbert Xu 
10301c5ad13fSMathias Krause 	x->data = aead;
10311a6509d9SHerbert Xu 
10321a6509d9SHerbert Xu 	err = crypto_aead_setkey(aead, x->aead->alg_key,
10331a6509d9SHerbert Xu 				 (x->aead->alg_key_len + 7) / 8);
10341a6509d9SHerbert Xu 	if (err)
10351a6509d9SHerbert Xu 		goto error;
10361a6509d9SHerbert Xu 
10371a6509d9SHerbert Xu 	err = crypto_aead_setauthsize(aead, x->aead->alg_icv_len / 8);
10381a6509d9SHerbert Xu 	if (err)
10391a6509d9SHerbert Xu 		goto error;
10401a6509d9SHerbert Xu 
10411a6509d9SHerbert Xu error:
10421a6509d9SHerbert Xu 	return err;
10431a6509d9SHerbert Xu }
10441a6509d9SHerbert Xu 
10451a6509d9SHerbert Xu static int esp_init_authenc(struct xfrm_state *x)
10461a6509d9SHerbert Xu {
104738320c70SHerbert Xu 	struct crypto_aead *aead;
104838320c70SHerbert Xu 	struct crypto_authenc_key_param *param;
104938320c70SHerbert Xu 	struct rtattr *rta;
105038320c70SHerbert Xu 	char *key;
105138320c70SHerbert Xu 	char *p;
105238320c70SHerbert Xu 	char authenc_name[CRYPTO_MAX_ALG_NAME];
105338320c70SHerbert Xu 	unsigned int keylen;
105438320c70SHerbert Xu 	int err;
10551da177e4SLinus Torvalds 
10561a6509d9SHerbert Xu 	err = -EINVAL;
105751456b29SIan Morris 	if (!x->ealg)
10581a6509d9SHerbert Xu 		goto error;
105938320c70SHerbert Xu 
10601a6509d9SHerbert Xu 	err = -ENAMETOOLONG;
10610dc49e9bSSteffen Klassert 
10620dc49e9bSSteffen Klassert 	if ((x->props.flags & XFRM_STATE_ESN)) {
10630dc49e9bSSteffen Klassert 		if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME,
10647021b2e1SHerbert Xu 			     "%s%sauthencesn(%s,%s)%s",
10657021b2e1SHerbert Xu 			     x->geniv ?: "", x->geniv ? "(" : "",
106638320c70SHerbert Xu 			     x->aalg ? x->aalg->alg_name : "digest_null",
10677021b2e1SHerbert Xu 			     x->ealg->alg_name,
10687021b2e1SHerbert Xu 			     x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME)
10691a6509d9SHerbert Xu 			goto error;
10700dc49e9bSSteffen Klassert 	} else {
10710dc49e9bSSteffen Klassert 		if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME,
10727021b2e1SHerbert Xu 			     "%s%sauthenc(%s,%s)%s",
10737021b2e1SHerbert Xu 			     x->geniv ?: "", x->geniv ? "(" : "",
10740dc49e9bSSteffen Klassert 			     x->aalg ? x->aalg->alg_name : "digest_null",
10757021b2e1SHerbert Xu 			     x->ealg->alg_name,
10767021b2e1SHerbert Xu 			     x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME)
10770dc49e9bSSteffen Klassert 			goto error;
10780dc49e9bSSteffen Klassert 	}
107938320c70SHerbert Xu 
1080f58869c4SSteffen Klassert 	aead = crypto_alloc_aead(authenc_name, 0, 0);
108138320c70SHerbert Xu 	err = PTR_ERR(aead);
108238320c70SHerbert Xu 	if (IS_ERR(aead))
108338320c70SHerbert Xu 		goto error;
108438320c70SHerbert Xu 
10851c5ad13fSMathias Krause 	x->data = aead;
108638320c70SHerbert Xu 
108738320c70SHerbert Xu 	keylen = (x->aalg ? (x->aalg->alg_key_len + 7) / 8 : 0) +
108838320c70SHerbert Xu 		 (x->ealg->alg_key_len + 7) / 8 + RTA_SPACE(sizeof(*param));
108938320c70SHerbert Xu 	err = -ENOMEM;
109038320c70SHerbert Xu 	key = kmalloc(keylen, GFP_KERNEL);
109138320c70SHerbert Xu 	if (!key)
109238320c70SHerbert Xu 		goto error;
109338320c70SHerbert Xu 
109438320c70SHerbert Xu 	p = key;
109538320c70SHerbert Xu 	rta = (void *)p;
109638320c70SHerbert Xu 	rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM;
109738320c70SHerbert Xu 	rta->rta_len = RTA_LENGTH(sizeof(*param));
109838320c70SHerbert Xu 	param = RTA_DATA(rta);
109938320c70SHerbert Xu 	p += RTA_SPACE(sizeof(*param));
110038320c70SHerbert Xu 
11011da177e4SLinus Torvalds 	if (x->aalg) {
11021da177e4SLinus Torvalds 		struct xfrm_algo_desc *aalg_desc;
11031da177e4SLinus Torvalds 
110438320c70SHerbert Xu 		memcpy(p, x->aalg->alg_key, (x->aalg->alg_key_len + 7) / 8);
110538320c70SHerbert Xu 		p += (x->aalg->alg_key_len + 7) / 8;
11061da177e4SLinus Torvalds 
11071da177e4SLinus Torvalds 		aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
11081da177e4SLinus Torvalds 		BUG_ON(!aalg_desc);
11091da177e4SLinus Torvalds 
111038320c70SHerbert Xu 		err = -EINVAL;
11111da177e4SLinus Torvalds 		if (aalg_desc->uinfo.auth.icv_fullbits / 8 !=
111238320c70SHerbert Xu 		    crypto_aead_authsize(aead)) {
111345083497SJoe Perches 			pr_info("ESP: %s digestsize %u != %hu\n",
11141da177e4SLinus Torvalds 				x->aalg->alg_name,
111538320c70SHerbert Xu 				crypto_aead_authsize(aead),
111664ce2073SPatrick McHardy 				aalg_desc->uinfo.auth.icv_fullbits / 8);
111738320c70SHerbert Xu 			goto free_key;
11181da177e4SLinus Torvalds 		}
11191da177e4SLinus Torvalds 
112038320c70SHerbert Xu 		err = crypto_aead_setauthsize(
11218f8a088cSMartin Willi 			aead, x->aalg->alg_trunc_len / 8);
112238320c70SHerbert Xu 		if (err)
112338320c70SHerbert Xu 			goto free_key;
11241da177e4SLinus Torvalds 	}
11254b7137ffSHerbert Xu 
112638320c70SHerbert Xu 	param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8);
112738320c70SHerbert Xu 	memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8);
112838320c70SHerbert Xu 
112938320c70SHerbert Xu 	err = crypto_aead_setkey(aead, key, keylen);
113038320c70SHerbert Xu 
113138320c70SHerbert Xu free_key:
113238320c70SHerbert Xu 	kfree(key);
113338320c70SHerbert Xu 
11341a6509d9SHerbert Xu error:
11351a6509d9SHerbert Xu 	return err;
11361a6509d9SHerbert Xu }
11371a6509d9SHerbert Xu 
11381a6509d9SHerbert Xu static int esp_init_state(struct xfrm_state *x)
11391a6509d9SHerbert Xu {
11401a6509d9SHerbert Xu 	struct crypto_aead *aead;
11411a6509d9SHerbert Xu 	u32 align;
11421a6509d9SHerbert Xu 	int err;
11431a6509d9SHerbert Xu 
11441c5ad13fSMathias Krause 	x->data = NULL;
11451a6509d9SHerbert Xu 
11461a6509d9SHerbert Xu 	if (x->aead)
11471a6509d9SHerbert Xu 		err = esp_init_aead(x);
11481a6509d9SHerbert Xu 	else
11491a6509d9SHerbert Xu 		err = esp_init_authenc(x);
11501a6509d9SHerbert Xu 
115138320c70SHerbert Xu 	if (err)
11521da177e4SLinus Torvalds 		goto error;
115338320c70SHerbert Xu 
11541c5ad13fSMathias Krause 	aead = x->data;
11551a6509d9SHerbert Xu 
115638320c70SHerbert Xu 	x->props.header_len = sizeof(struct ip_esp_hdr) +
115738320c70SHerbert Xu 			      crypto_aead_ivsize(aead);
11587e49e6deSMasahide NAKAMURA 	if (x->props.mode == XFRM_MODE_TUNNEL)
11591da177e4SLinus Torvalds 		x->props.header_len += sizeof(struct iphdr);
1160eb49e630SJoakim Koskela 	else if (x->props.mode == XFRM_MODE_BEET && x->sel.family != AF_INET6)
1161ac758e3cSPatrick McHardy 		x->props.header_len += IPV4_BEET_PHMAXLEN;
11621da177e4SLinus Torvalds 	if (x->encap) {
11631da177e4SLinus Torvalds 		struct xfrm_encap_tmpl *encap = x->encap;
11641da177e4SLinus Torvalds 
11651da177e4SLinus Torvalds 		switch (encap->encap_type) {
11661da177e4SLinus Torvalds 		default:
1167bcfd09f7SHerbert Xu 			err = -EINVAL;
11681da177e4SLinus Torvalds 			goto error;
11691da177e4SLinus Torvalds 		case UDP_ENCAP_ESPINUDP:
11701da177e4SLinus Torvalds 			x->props.header_len += sizeof(struct udphdr);
11711da177e4SLinus Torvalds 			break;
11721da177e4SLinus Torvalds 		case UDP_ENCAP_ESPINUDP_NON_IKE:
11731da177e4SLinus Torvalds 			x->props.header_len += sizeof(struct udphdr) + 2 * sizeof(u32);
11741da177e4SLinus Torvalds 			break;
1175e27cca96SSabrina Dubroca #ifdef CONFIG_INET_ESPINTCP
1176e27cca96SSabrina Dubroca 		case TCP_ENCAP_ESPINTCP:
1177e27cca96SSabrina Dubroca 			/* only the length field, TCP encap is done by
1178e27cca96SSabrina Dubroca 			 * the socket
1179e27cca96SSabrina Dubroca 			 */
1180e27cca96SSabrina Dubroca 			x->props.header_len += 2;
1181e27cca96SSabrina Dubroca 			break;
1182e27cca96SSabrina Dubroca #endif
11831da177e4SLinus Torvalds 		}
11841da177e4SLinus Torvalds 	}
118538320c70SHerbert Xu 
118638320c70SHerbert Xu 	align = ALIGN(crypto_aead_blocksize(aead), 4);
11871c5ad13fSMathias Krause 	x->props.trailer_len = align + 1 + crypto_aead_authsize(aead);
11881da177e4SLinus Torvalds 
11891da177e4SLinus Torvalds error:
119038320c70SHerbert Xu 	return err;
11911da177e4SLinus Torvalds }
11921da177e4SLinus Torvalds 
1193827789cbSSteffen Klassert static int esp4_rcv_cb(struct sk_buff *skb, int err)
1194827789cbSSteffen Klassert {
1195827789cbSSteffen Klassert 	return 0;
1196827789cbSSteffen Klassert }
1197827789cbSSteffen Klassert 
1198533cb5b0SEric Dumazet static const struct xfrm_type esp_type =
11991da177e4SLinus Torvalds {
12001da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
12011da177e4SLinus Torvalds 	.proto	     	= IPPROTO_ESP,
1202436a0a40SHerbert Xu 	.flags		= XFRM_TYPE_REPLAY_PROT,
12031da177e4SLinus Torvalds 	.init_state	= esp_init_state,
12041da177e4SLinus Torvalds 	.destructor	= esp_destroy,
12051da177e4SLinus Torvalds 	.input		= esp_input,
1206fca11ebdSSteffen Klassert 	.output		= esp_output,
12071da177e4SLinus Torvalds };
12081da177e4SLinus Torvalds 
1209827789cbSSteffen Klassert static struct xfrm4_protocol esp4_protocol = {
12101da177e4SLinus Torvalds 	.handler	=	xfrm4_rcv,
1211827789cbSSteffen Klassert 	.input_handler	=	xfrm_input,
1212827789cbSSteffen Klassert 	.cb_handler	=	esp4_rcv_cb,
12131da177e4SLinus Torvalds 	.err_handler	=	esp4_err,
1214827789cbSSteffen Klassert 	.priority	=	0,
12151da177e4SLinus Torvalds };
12161da177e4SLinus Torvalds 
12171da177e4SLinus Torvalds static int __init esp4_init(void)
12181da177e4SLinus Torvalds {
12191da177e4SLinus Torvalds 	if (xfrm_register_type(&esp_type, AF_INET) < 0) {
1220058bd4d2SJoe Perches 		pr_info("%s: can't add xfrm type\n", __func__);
12211da177e4SLinus Torvalds 		return -EAGAIN;
12221da177e4SLinus Torvalds 	}
1223827789cbSSteffen Klassert 	if (xfrm4_protocol_register(&esp4_protocol, IPPROTO_ESP) < 0) {
1224058bd4d2SJoe Perches 		pr_info("%s: can't add protocol\n", __func__);
12251da177e4SLinus Torvalds 		xfrm_unregister_type(&esp_type, AF_INET);
12261da177e4SLinus Torvalds 		return -EAGAIN;
12271da177e4SLinus Torvalds 	}
12281da177e4SLinus Torvalds 	return 0;
12291da177e4SLinus Torvalds }
12301da177e4SLinus Torvalds 
12311da177e4SLinus Torvalds static void __exit esp4_fini(void)
12321da177e4SLinus Torvalds {
1233827789cbSSteffen Klassert 	if (xfrm4_protocol_deregister(&esp4_protocol, IPPROTO_ESP) < 0)
1234058bd4d2SJoe Perches 		pr_info("%s: can't remove protocol\n", __func__);
12354f518e80SFlorian Westphal 	xfrm_unregister_type(&esp_type, AF_INET);
12361da177e4SLinus Torvalds }
12371da177e4SLinus Torvalds 
12381da177e4SLinus Torvalds module_init(esp4_init);
12391da177e4SLinus Torvalds module_exit(esp4_fini);
12401da177e4SLinus Torvalds MODULE_LICENSE("GPL");
1241d3d6dd3aSMasahide NAKAMURA MODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_ESP);
1242