xref: /linux/net/ipv4/esp4.c (revision 9410645520e9b820069761f3450ef6661418e279)
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>
23f6d827b1SMina Almasry #include <linux/skbuff_ref.h>
241da177e4SLinus Torvalds 
25cac2661cSSteffen Klassert #include <linux/highmem.h>
26cac2661cSSteffen Klassert 
2738320c70SHerbert Xu struct esp_skb_cb {
2838320c70SHerbert Xu 	struct xfrm_skb_cb xfrm;
2938320c70SHerbert Xu 	void *tmp;
3038320c70SHerbert Xu };
3138320c70SHerbert Xu 
32962fcef3SHerbert Xu struct esp_output_extra {
33962fcef3SHerbert Xu 	__be32 seqhi;
34962fcef3SHerbert Xu 	u32 esphoff;
35962fcef3SHerbert Xu };
36962fcef3SHerbert Xu 
3738320c70SHerbert Xu #define ESP_SKB_CB(__skb) ((struct esp_skb_cb *)&((__skb)->cb[0]))
3838320c70SHerbert Xu 
3938320c70SHerbert Xu /*
4038320c70SHerbert Xu  * Allocate an AEAD request structure with extra space for SG and IV.
4138320c70SHerbert Xu  *
4238320c70SHerbert Xu  * For alignment considerations the IV is placed at the front, followed
4338320c70SHerbert Xu  * by the request and finally the SG list.
4438320c70SHerbert Xu  *
4538320c70SHerbert Xu  * TODO: Use spare space in skb for this where possible.
4638320c70SHerbert Xu  */
esp_alloc_tmp(struct crypto_aead * aead,int nfrags,int extralen)47962fcef3SHerbert Xu static void *esp_alloc_tmp(struct crypto_aead *aead, int nfrags, int extralen)
4838320c70SHerbert Xu {
4938320c70SHerbert Xu 	unsigned int len;
5038320c70SHerbert Xu 
51962fcef3SHerbert Xu 	len = extralen;
520dc49e9bSSteffen Klassert 
530dc49e9bSSteffen Klassert 	len += crypto_aead_ivsize(aead);
540dc49e9bSSteffen Klassert 
5538320c70SHerbert Xu 	if (len) {
5638320c70SHerbert Xu 		len += crypto_aead_alignmask(aead) &
5738320c70SHerbert Xu 		       ~(crypto_tfm_ctx_alignment() - 1);
5838320c70SHerbert Xu 		len = ALIGN(len, crypto_tfm_ctx_alignment());
5938320c70SHerbert Xu 	}
6038320c70SHerbert Xu 
617021b2e1SHerbert Xu 	len += sizeof(struct aead_request) + crypto_aead_reqsize(aead);
6238320c70SHerbert Xu 	len = ALIGN(len, __alignof__(struct scatterlist));
6338320c70SHerbert Xu 
6438320c70SHerbert Xu 	len += sizeof(struct scatterlist) * nfrags;
6538320c70SHerbert Xu 
6638320c70SHerbert Xu 	return kmalloc(len, GFP_ATOMIC);
6738320c70SHerbert Xu }
6838320c70SHerbert Xu 
esp_tmp_extra(void * tmp)69962fcef3SHerbert Xu static inline void *esp_tmp_extra(void *tmp)
700dc49e9bSSteffen Klassert {
71962fcef3SHerbert Xu 	return PTR_ALIGN(tmp, __alignof__(struct esp_output_extra));
720dc49e9bSSteffen Klassert }
73962fcef3SHerbert Xu 
esp_tmp_iv(struct crypto_aead * aead,void * tmp,int extralen)74962fcef3SHerbert Xu static inline u8 *esp_tmp_iv(struct crypto_aead *aead, void *tmp, int extralen)
7538320c70SHerbert Xu {
7638320c70SHerbert Xu 	return crypto_aead_ivsize(aead) ?
77962fcef3SHerbert Xu 	       PTR_ALIGN((u8 *)tmp + extralen,
78962fcef3SHerbert Xu 			 crypto_aead_alignmask(aead) + 1) : tmp + extralen;
7938320c70SHerbert Xu }
8038320c70SHerbert Xu 
esp_tmp_req(struct crypto_aead * aead,u8 * iv)8138320c70SHerbert Xu static inline struct aead_request *esp_tmp_req(struct crypto_aead *aead, u8 *iv)
8238320c70SHerbert Xu {
8338320c70SHerbert Xu 	struct aead_request *req;
8438320c70SHerbert Xu 
8538320c70SHerbert Xu 	req = (void *)PTR_ALIGN(iv + crypto_aead_ivsize(aead),
8638320c70SHerbert Xu 				crypto_tfm_ctx_alignment());
8738320c70SHerbert Xu 	aead_request_set_tfm(req, aead);
8838320c70SHerbert Xu 	return req;
8938320c70SHerbert Xu }
9038320c70SHerbert Xu 
esp_req_sg(struct crypto_aead * aead,struct aead_request * req)9138320c70SHerbert Xu static inline struct scatterlist *esp_req_sg(struct crypto_aead *aead,
9238320c70SHerbert Xu 					     struct aead_request *req)
9338320c70SHerbert Xu {
9438320c70SHerbert Xu 	return (void *)ALIGN((unsigned long)(req + 1) +
9538320c70SHerbert Xu 			     crypto_aead_reqsize(aead),
9638320c70SHerbert Xu 			     __alignof__(struct scatterlist));
9738320c70SHerbert Xu }
9838320c70SHerbert Xu 
esp_ssg_unref(struct xfrm_state * x,void * tmp,struct sk_buff * skb)99c3198822SDragos Tatulea static void esp_ssg_unref(struct xfrm_state *x, void *tmp, struct sk_buff *skb)
100cac2661cSSteffen Klassert {
101cac2661cSSteffen Klassert 	struct crypto_aead *aead = x->data;
102cac2661cSSteffen Klassert 	int extralen = 0;
103cac2661cSSteffen Klassert 	u8 *iv;
104cac2661cSSteffen Klassert 	struct aead_request *req;
105cac2661cSSteffen Klassert 	struct scatterlist *sg;
106cac2661cSSteffen Klassert 
107cac2661cSSteffen Klassert 	if (x->props.flags & XFRM_STATE_ESN)
108f8fdadefSCorey Minyard 		extralen += sizeof(struct esp_output_extra);
109cac2661cSSteffen Klassert 
110cac2661cSSteffen Klassert 	iv = esp_tmp_iv(aead, tmp, extralen);
111cac2661cSSteffen Klassert 	req = esp_tmp_req(aead, iv);
112cac2661cSSteffen Klassert 
113cac2661cSSteffen Klassert 	/* Unref skb_frag_pages in the src scatterlist if necessary.
114cac2661cSSteffen Klassert 	 * Skip the first sg which comes from skb->data.
115cac2661cSSteffen Klassert 	 */
116cac2661cSSteffen Klassert 	if (req->src != req->dst)
117cac2661cSSteffen Klassert 		for (sg = sg_next(req->src); sg; sg = sg_next(sg))
118*9f6b619eSMina Almasry 			skb_page_unref(page_to_netmem(sg_page(sg)),
119*9f6b619eSMina Almasry 				       skb->pp_recycle);
120cac2661cSSteffen Klassert }
121cac2661cSSteffen Klassert 
122e27cca96SSabrina Dubroca #ifdef CONFIG_INET_ESPINTCP
123e27cca96SSabrina Dubroca struct esp_tcp_sk {
124e27cca96SSabrina Dubroca 	struct sock *sk;
125e27cca96SSabrina Dubroca 	struct rcu_head rcu;
126e27cca96SSabrina Dubroca };
127e27cca96SSabrina Dubroca 
esp_free_tcp_sk(struct rcu_head * head)128e27cca96SSabrina Dubroca static void esp_free_tcp_sk(struct rcu_head *head)
129e27cca96SSabrina Dubroca {
130e27cca96SSabrina Dubroca 	struct esp_tcp_sk *esk = container_of(head, struct esp_tcp_sk, rcu);
131e27cca96SSabrina Dubroca 
132e27cca96SSabrina Dubroca 	sock_put(esk->sk);
133e27cca96SSabrina Dubroca 	kfree(esk);
134e27cca96SSabrina Dubroca }
135e27cca96SSabrina Dubroca 
esp_find_tcp_sk(struct xfrm_state * x)136e27cca96SSabrina Dubroca static struct sock *esp_find_tcp_sk(struct xfrm_state *x)
137e27cca96SSabrina Dubroca {
138e27cca96SSabrina Dubroca 	struct xfrm_encap_tmpl *encap = x->encap;
1394461568aSKuniyuki Iwashima 	struct net *net = xs_net(x);
140e27cca96SSabrina Dubroca 	struct esp_tcp_sk *esk;
141e27cca96SSabrina Dubroca 	__be16 sport, dport;
142e27cca96SSabrina Dubroca 	struct sock *nsk;
143e27cca96SSabrina Dubroca 	struct sock *sk;
144e27cca96SSabrina Dubroca 
145e27cca96SSabrina Dubroca 	sk = rcu_dereference(x->encap_sk);
146e27cca96SSabrina Dubroca 	if (sk && sk->sk_state == TCP_ESTABLISHED)
147e27cca96SSabrina Dubroca 		return sk;
148e27cca96SSabrina Dubroca 
149e27cca96SSabrina Dubroca 	spin_lock_bh(&x->lock);
150e27cca96SSabrina Dubroca 	sport = encap->encap_sport;
151e27cca96SSabrina Dubroca 	dport = encap->encap_dport;
152e27cca96SSabrina Dubroca 	nsk = rcu_dereference_protected(x->encap_sk,
153e27cca96SSabrina Dubroca 					lockdep_is_held(&x->lock));
154e27cca96SSabrina Dubroca 	if (sk && sk == nsk) {
155e27cca96SSabrina Dubroca 		esk = kmalloc(sizeof(*esk), GFP_ATOMIC);
156e27cca96SSabrina Dubroca 		if (!esk) {
157e27cca96SSabrina Dubroca 			spin_unlock_bh(&x->lock);
158e27cca96SSabrina Dubroca 			return ERR_PTR(-ENOMEM);
159e27cca96SSabrina Dubroca 		}
160e27cca96SSabrina Dubroca 		RCU_INIT_POINTER(x->encap_sk, NULL);
161e27cca96SSabrina Dubroca 		esk->sk = sk;
162e27cca96SSabrina Dubroca 		call_rcu(&esk->rcu, esp_free_tcp_sk);
163e27cca96SSabrina Dubroca 	}
164e27cca96SSabrina Dubroca 	spin_unlock_bh(&x->lock);
165e27cca96SSabrina Dubroca 
1664461568aSKuniyuki Iwashima 	sk = inet_lookup_established(net, net->ipv4.tcp_death_row.hashinfo, x->id.daddr.a4,
167e27cca96SSabrina Dubroca 				     dport, x->props.saddr.a4, sport, 0);
168e27cca96SSabrina Dubroca 	if (!sk)
169e27cca96SSabrina Dubroca 		return ERR_PTR(-ENOENT);
170e27cca96SSabrina Dubroca 
171e27cca96SSabrina Dubroca 	if (!tcp_is_ulp_esp(sk)) {
172e27cca96SSabrina Dubroca 		sock_put(sk);
173e27cca96SSabrina Dubroca 		return ERR_PTR(-EINVAL);
174e27cca96SSabrina Dubroca 	}
175e27cca96SSabrina Dubroca 
176e27cca96SSabrina Dubroca 	spin_lock_bh(&x->lock);
177e27cca96SSabrina Dubroca 	nsk = rcu_dereference_protected(x->encap_sk,
178e27cca96SSabrina Dubroca 					lockdep_is_held(&x->lock));
179e27cca96SSabrina Dubroca 	if (encap->encap_sport != sport ||
180e27cca96SSabrina Dubroca 	    encap->encap_dport != dport) {
181e27cca96SSabrina Dubroca 		sock_put(sk);
182e27cca96SSabrina Dubroca 		sk = nsk ?: ERR_PTR(-EREMCHG);
183e27cca96SSabrina Dubroca 	} else if (sk == nsk) {
184e27cca96SSabrina Dubroca 		sock_put(sk);
185e27cca96SSabrina Dubroca 	} else {
186e27cca96SSabrina Dubroca 		rcu_assign_pointer(x->encap_sk, sk);
187e27cca96SSabrina Dubroca 	}
188e27cca96SSabrina Dubroca 	spin_unlock_bh(&x->lock);
189e27cca96SSabrina Dubroca 
190e27cca96SSabrina Dubroca 	return sk;
191e27cca96SSabrina Dubroca }
192e27cca96SSabrina Dubroca 
esp_output_tcp_finish(struct xfrm_state * x,struct sk_buff * skb)193e27cca96SSabrina Dubroca static int esp_output_tcp_finish(struct xfrm_state *x, struct sk_buff *skb)
194e27cca96SSabrina Dubroca {
195e27cca96SSabrina Dubroca 	struct sock *sk;
196e27cca96SSabrina Dubroca 	int err;
197e27cca96SSabrina Dubroca 
198e27cca96SSabrina Dubroca 	rcu_read_lock();
199e27cca96SSabrina Dubroca 
200e27cca96SSabrina Dubroca 	sk = esp_find_tcp_sk(x);
201e27cca96SSabrina Dubroca 	err = PTR_ERR_OR_ZERO(sk);
202e27cca96SSabrina Dubroca 	if (err)
203e27cca96SSabrina Dubroca 		goto out;
204e27cca96SSabrina Dubroca 
205e27cca96SSabrina Dubroca 	bh_lock_sock(sk);
206e27cca96SSabrina Dubroca 	if (sock_owned_by_user(sk))
207e27cca96SSabrina Dubroca 		err = espintcp_queue_out(sk, skb);
208e27cca96SSabrina Dubroca 	else
209e27cca96SSabrina Dubroca 		err = espintcp_push_skb(sk, skb);
210e27cca96SSabrina Dubroca 	bh_unlock_sock(sk);
211e27cca96SSabrina Dubroca 
212e27cca96SSabrina Dubroca out:
213e27cca96SSabrina Dubroca 	rcu_read_unlock();
214e27cca96SSabrina Dubroca 	return err;
215e27cca96SSabrina Dubroca }
216e27cca96SSabrina Dubroca 
esp_output_tcp_encap_cb(struct net * net,struct sock * sk,struct sk_buff * skb)217e27cca96SSabrina Dubroca static int esp_output_tcp_encap_cb(struct net *net, struct sock *sk,
218e27cca96SSabrina Dubroca 				   struct sk_buff *skb)
219e27cca96SSabrina Dubroca {
220e27cca96SSabrina Dubroca 	struct dst_entry *dst = skb_dst(skb);
221e27cca96SSabrina Dubroca 	struct xfrm_state *x = dst->xfrm;
222e27cca96SSabrina Dubroca 
223e27cca96SSabrina Dubroca 	return esp_output_tcp_finish(x, skb);
224e27cca96SSabrina Dubroca }
225e27cca96SSabrina Dubroca 
esp_output_tail_tcp(struct xfrm_state * x,struct sk_buff * skb)226e27cca96SSabrina Dubroca static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)
227e27cca96SSabrina Dubroca {
228e27cca96SSabrina Dubroca 	int err;
229e27cca96SSabrina Dubroca 
230e27cca96SSabrina Dubroca 	local_bh_disable();
231e27cca96SSabrina Dubroca 	err = xfrm_trans_queue_net(xs_net(x), skb, esp_output_tcp_encap_cb);
232e27cca96SSabrina Dubroca 	local_bh_enable();
233e27cca96SSabrina Dubroca 
234e27cca96SSabrina Dubroca 	/* EINPROGRESS just happens to do the right thing.  It
235e27cca96SSabrina Dubroca 	 * actually means that the skb has been consumed and
236e27cca96SSabrina Dubroca 	 * isn't coming back.
237e27cca96SSabrina Dubroca 	 */
238e27cca96SSabrina Dubroca 	return err ?: -EINPROGRESS;
239e27cca96SSabrina Dubroca }
240e27cca96SSabrina Dubroca #else
esp_output_tail_tcp(struct xfrm_state * x,struct sk_buff * skb)241e27cca96SSabrina Dubroca static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)
242e27cca96SSabrina Dubroca {
24396f887a6SHagar Hemdan 	WARN_ON(1);
244e27cca96SSabrina Dubroca 	return -EOPNOTSUPP;
245e27cca96SSabrina Dubroca }
246e27cca96SSabrina Dubroca #endif
247e27cca96SSabrina Dubroca 
esp_output_done(void * data,int err)248fd5dabf7SHerbert Xu static void esp_output_done(void *data, int err)
24938320c70SHerbert Xu {
250fd5dabf7SHerbert Xu 	struct sk_buff *skb = data;
251f53c7239SSteffen Klassert 	struct xfrm_offload *xo = xfrm_offload(skb);
252cac2661cSSteffen Klassert 	void *tmp;
253f53c7239SSteffen Klassert 	struct xfrm_state *x;
254f53c7239SSteffen Klassert 
2552294be0fSFlorian Westphal 	if (xo && (xo->flags & XFRM_DEV_RESUME)) {
2562294be0fSFlorian Westphal 		struct sec_path *sp = skb_sec_path(skb);
2572294be0fSFlorian Westphal 
2582294be0fSFlorian Westphal 		x = sp->xvec[sp->len - 1];
2592294be0fSFlorian Westphal 	} else {
260f53c7239SSteffen Klassert 		x = skb_dst(skb)->xfrm;
2612294be0fSFlorian Westphal 	}
26238320c70SHerbert Xu 
263cac2661cSSteffen Klassert 	tmp = ESP_SKB_CB(skb)->tmp;
264c3198822SDragos Tatulea 	esp_ssg_unref(x, tmp, skb);
265cac2661cSSteffen Klassert 	kfree(tmp);
266f53c7239SSteffen Klassert 
267f53c7239SSteffen Klassert 	if (xo && (xo->flags & XFRM_DEV_RESUME)) {
268f53c7239SSteffen Klassert 		if (err) {
269f53c7239SSteffen Klassert 			XFRM_INC_STATS(xs_net(x), LINUX_MIB_XFRMOUTSTATEPROTOERROR);
270f53c7239SSteffen Klassert 			kfree_skb(skb);
271f53c7239SSteffen Klassert 			return;
272f53c7239SSteffen Klassert 		}
273f53c7239SSteffen Klassert 
274f53c7239SSteffen Klassert 		skb_push(skb, skb->data - skb_mac_header(skb));
275f53c7239SSteffen Klassert 		secpath_reset(skb);
276f53c7239SSteffen Klassert 		xfrm_dev_resume(skb);
277f53c7239SSteffen Klassert 	} else {
278e27cca96SSabrina Dubroca 		if (!err &&
279e27cca96SSabrina Dubroca 		    x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP)
280e27cca96SSabrina Dubroca 			esp_output_tail_tcp(x, skb);
281e27cca96SSabrina Dubroca 		else
2829ab1265dSEvan Nimmo 			xfrm_output_resume(skb->sk, skb, err);
28338320c70SHerbert Xu 	}
284f53c7239SSteffen Klassert }
28538320c70SHerbert Xu 
2867021b2e1SHerbert Xu /* Move ESP header back into place. */
esp_restore_header(struct sk_buff * skb,unsigned int offset)2877021b2e1SHerbert Xu static void esp_restore_header(struct sk_buff *skb, unsigned int offset)
2887021b2e1SHerbert Xu {
2897021b2e1SHerbert Xu 	struct ip_esp_hdr *esph = (void *)(skb->data + offset);
2907021b2e1SHerbert Xu 	void *tmp = ESP_SKB_CB(skb)->tmp;
291962fcef3SHerbert Xu 	__be32 *seqhi = esp_tmp_extra(tmp);
2927021b2e1SHerbert Xu 
2937021b2e1SHerbert Xu 	esph->seq_no = esph->spi;
2947021b2e1SHerbert Xu 	esph->spi = *seqhi;
2957021b2e1SHerbert Xu }
2967021b2e1SHerbert Xu 
esp_output_restore_header(struct sk_buff * skb)2977021b2e1SHerbert Xu static void esp_output_restore_header(struct sk_buff *skb)
2987021b2e1SHerbert Xu {
299962fcef3SHerbert Xu 	void *tmp = ESP_SKB_CB(skb)->tmp;
300962fcef3SHerbert Xu 	struct esp_output_extra *extra = esp_tmp_extra(tmp);
301962fcef3SHerbert Xu 
302962fcef3SHerbert Xu 	esp_restore_header(skb, skb_transport_offset(skb) + extra->esphoff -
303962fcef3SHerbert Xu 				sizeof(__be32));
3047021b2e1SHerbert Xu }
3057021b2e1SHerbert Xu 
esp_output_set_extra(struct sk_buff * skb,struct xfrm_state * x,struct ip_esp_hdr * esph,struct esp_output_extra * extra)306cac2661cSSteffen Klassert static struct ip_esp_hdr *esp_output_set_extra(struct sk_buff *skb,
307fca11ebdSSteffen Klassert 					       struct xfrm_state *x,
308cac2661cSSteffen Klassert 					       struct ip_esp_hdr *esph,
309cac2661cSSteffen Klassert 					       struct esp_output_extra *extra)
310cac2661cSSteffen Klassert {
311cac2661cSSteffen Klassert 	/* For ESN we move the header forward by 4 bytes to
312cbd801b3SLu Wei 	 * accommodate the high bits.  We will move it back after
313cac2661cSSteffen Klassert 	 * encryption.
314cac2661cSSteffen Klassert 	 */
315cac2661cSSteffen Klassert 	if ((x->props.flags & XFRM_STATE_ESN)) {
3167862b405SSteffen Klassert 		__u32 seqhi;
3177862b405SSteffen Klassert 		struct xfrm_offload *xo = xfrm_offload(skb);
3187862b405SSteffen Klassert 
3197862b405SSteffen Klassert 		if (xo)
3207862b405SSteffen Klassert 			seqhi = xo->seq.hi;
3217862b405SSteffen Klassert 		else
3227862b405SSteffen Klassert 			seqhi = XFRM_SKB_CB(skb)->seq.output.hi;
3237862b405SSteffen Klassert 
324cac2661cSSteffen Klassert 		extra->esphoff = (unsigned char *)esph -
325cac2661cSSteffen Klassert 				 skb_transport_header(skb);
326cac2661cSSteffen Klassert 		esph = (struct ip_esp_hdr *)((unsigned char *)esph - 4);
327cac2661cSSteffen Klassert 		extra->seqhi = esph->spi;
3287862b405SSteffen Klassert 		esph->seq_no = htonl(seqhi);
329cac2661cSSteffen Klassert 	}
330cac2661cSSteffen Klassert 
331cac2661cSSteffen Klassert 	esph->spi = x->id.spi;
332cac2661cSSteffen Klassert 
333cac2661cSSteffen Klassert 	return esph;
334cac2661cSSteffen Klassert }
335cac2661cSSteffen Klassert 
esp_output_done_esn(void * data,int err)336fd5dabf7SHerbert Xu static void esp_output_done_esn(void *data, int err)
3377021b2e1SHerbert Xu {
338fd5dabf7SHerbert Xu 	struct sk_buff *skb = data;
3397021b2e1SHerbert Xu 
3407021b2e1SHerbert Xu 	esp_output_restore_header(skb);
34114d3109cSHerbert Xu 	esp_output_done(data, err);
3427021b2e1SHerbert Xu }
3437021b2e1SHerbert Xu 
esp_output_udp_encap(struct sk_buff * skb,int encap_type,struct esp_info * esp,__be16 sport,__be16 dport)344eecd227aSSabrina Dubroca static struct ip_esp_hdr *esp_output_udp_encap(struct sk_buff *skb,
345eecd227aSSabrina Dubroca 					       int encap_type,
346eecd227aSSabrina Dubroca 					       struct esp_info *esp,
347eecd227aSSabrina Dubroca 					       __be16 sport,
348eecd227aSSabrina Dubroca 					       __be16 dport)
3491da177e4SLinus Torvalds {
3501da177e4SLinus Torvalds 	struct udphdr *uh;
3518dfb4ebaSSabrina Dubroca 	unsigned int len;
352447bc4b1SMike Yu 	struct xfrm_offload *xo = xfrm_offload(skb);
35338320c70SHerbert Xu 
354eecd227aSSabrina Dubroca 	len = skb->len + esp->tailen - skb_transport_offset(skb);
355e27cca96SSabrina Dubroca 	if (len + sizeof(struct iphdr) > IP_MAX_MTU)
356eecd227aSSabrina Dubroca 		return ERR_PTR(-EMSGSIZE);
357eecd227aSSabrina Dubroca 
358eecd227aSSabrina Dubroca 	uh = (struct udphdr *)esp->esph;
359eecd227aSSabrina Dubroca 	uh->source = sport;
360eecd227aSSabrina Dubroca 	uh->dest = dport;
361eecd227aSSabrina Dubroca 	uh->len = htons(len);
362eecd227aSSabrina Dubroca 	uh->check = 0;
363eecd227aSSabrina Dubroca 
364447bc4b1SMike Yu 	/* For IPv4 ESP with UDP encapsulation, if xo is not null, the skb is in the crypto offload
365447bc4b1SMike Yu 	 * data path, which means that esp_output_udp_encap is called outside of the XFRM stack.
366447bc4b1SMike Yu 	 * In this case, the mac header doesn't point to the IPv4 protocol field, so don't set it.
367447bc4b1SMike Yu 	 */
368447bc4b1SMike Yu 	if (!xo || encap_type != UDP_ENCAP_ESPINUDP)
369eecd227aSSabrina Dubroca 		*skb_mac_header(skb) = IPPROTO_UDP;
370eecd227aSSabrina Dubroca 
371eecd227aSSabrina Dubroca 	return (struct ip_esp_hdr *)(uh + 1);
372eecd227aSSabrina Dubroca }
373eecd227aSSabrina Dubroca 
374e27cca96SSabrina Dubroca #ifdef CONFIG_INET_ESPINTCP
esp_output_tcp_encap(struct xfrm_state * x,struct sk_buff * skb,struct esp_info * esp)375e27cca96SSabrina Dubroca static struct ip_esp_hdr *esp_output_tcp_encap(struct xfrm_state *x,
376e27cca96SSabrina Dubroca 						    struct sk_buff *skb,
377e27cca96SSabrina Dubroca 						    struct esp_info *esp)
378e27cca96SSabrina Dubroca {
379e27cca96SSabrina Dubroca 	__be16 *lenp = (void *)esp->esph;
380e27cca96SSabrina Dubroca 	struct ip_esp_hdr *esph;
381e27cca96SSabrina Dubroca 	unsigned int len;
382e27cca96SSabrina Dubroca 	struct sock *sk;
383e27cca96SSabrina Dubroca 
384e27cca96SSabrina Dubroca 	len = skb->len + esp->tailen - skb_transport_offset(skb);
385e27cca96SSabrina Dubroca 	if (len > IP_MAX_MTU)
386e27cca96SSabrina Dubroca 		return ERR_PTR(-EMSGSIZE);
387e27cca96SSabrina Dubroca 
388e27cca96SSabrina Dubroca 	rcu_read_lock();
389e27cca96SSabrina Dubroca 	sk = esp_find_tcp_sk(x);
390e27cca96SSabrina Dubroca 	rcu_read_unlock();
391e27cca96SSabrina Dubroca 
392e27cca96SSabrina Dubroca 	if (IS_ERR(sk))
393e27cca96SSabrina Dubroca 		return ERR_CAST(sk);
394e27cca96SSabrina Dubroca 
395e27cca96SSabrina Dubroca 	*lenp = htons(len);
396e27cca96SSabrina Dubroca 	esph = (struct ip_esp_hdr *)(lenp + 1);
397e27cca96SSabrina Dubroca 
398e27cca96SSabrina Dubroca 	return esph;
399e27cca96SSabrina Dubroca }
400e27cca96SSabrina Dubroca #else
esp_output_tcp_encap(struct xfrm_state * x,struct sk_buff * skb,struct esp_info * esp)401e27cca96SSabrina Dubroca static struct ip_esp_hdr *esp_output_tcp_encap(struct xfrm_state *x,
402e27cca96SSabrina Dubroca 						    struct sk_buff *skb,
403e27cca96SSabrina Dubroca 						    struct esp_info *esp)
404e27cca96SSabrina Dubroca {
405e27cca96SSabrina Dubroca 	return ERR_PTR(-EOPNOTSUPP);
406e27cca96SSabrina Dubroca }
407e27cca96SSabrina Dubroca #endif
408e27cca96SSabrina Dubroca 
esp_output_encap(struct xfrm_state * x,struct sk_buff * skb,struct esp_info * esp)409eecd227aSSabrina Dubroca static int esp_output_encap(struct xfrm_state *x, struct sk_buff *skb,
410eecd227aSSabrina Dubroca 			    struct esp_info *esp)
411eecd227aSSabrina Dubroca {
412eecd227aSSabrina Dubroca 	struct xfrm_encap_tmpl *encap = x->encap;
413eecd227aSSabrina Dubroca 	struct ip_esp_hdr *esph;
414eecd227aSSabrina Dubroca 	__be16 sport, dport;
415eecd227aSSabrina Dubroca 	int encap_type;
416eecd227aSSabrina Dubroca 
41738320c70SHerbert Xu 	spin_lock_bh(&x->lock);
41838320c70SHerbert Xu 	sport = encap->encap_sport;
41938320c70SHerbert Xu 	dport = encap->encap_dport;
42038320c70SHerbert Xu 	encap_type = encap->encap_type;
42138320c70SHerbert Xu 	spin_unlock_bh(&x->lock);
4221da177e4SLinus Torvalds 
42338320c70SHerbert Xu 	switch (encap_type) {
4241da177e4SLinus Torvalds 	default:
4251da177e4SLinus Torvalds 	case UDP_ENCAP_ESPINUDP:
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 
esp_output_head(struct xfrm_state * x,struct sk_buff * skb,struct esp_info * esp)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 
4585bd8baabSSabrina Dubroca 	if (ALIGN(tailen, L1_CACHE_BYTES) > PAGE_SIZE ||
4595bd8baabSSabrina Dubroca 	    ALIGN(skb->data_len, L1_CACHE_BYTES) > PAGE_SIZE)
460ebe48d36SSteffen Klassert 		goto cow;
461ebe48d36SSteffen Klassert 
462cac2661cSSteffen Klassert 	if (!skb_cloned(skb)) {
46354ffd790SSteffen Klassert 		if (tailen <= skb_tailroom(skb)) {
464cac2661cSSteffen Klassert 			nfrags = 1;
465cac2661cSSteffen Klassert 			trailer = skb;
466cac2661cSSteffen Klassert 			tail = skb_tail_pointer(trailer);
4671da177e4SLinus Torvalds 
468cac2661cSSteffen Klassert 			goto skip_cow;
469cac2661cSSteffen Klassert 		} else if ((skb_shinfo(skb)->nr_frags < MAX_SKB_FRAGS)
470cac2661cSSteffen Klassert 			   && !skb_has_frag_list(skb)) {
471cac2661cSSteffen Klassert 			int allocsize;
472cac2661cSSteffen Klassert 			struct sock *sk = skb->sk;
473cac2661cSSteffen Klassert 			struct page_frag *pfrag = &x->xfrag;
4747021b2e1SHerbert Xu 
475fca11ebdSSteffen Klassert 			esp->inplace = false;
476fca11ebdSSteffen Klassert 
477cac2661cSSteffen Klassert 			allocsize = ALIGN(tailen, L1_CACHE_BYTES);
478cac2661cSSteffen Klassert 
479cac2661cSSteffen Klassert 			spin_lock_bh(&x->lock);
480cac2661cSSteffen Klassert 
481cac2661cSSteffen Klassert 			if (unlikely(!skb_page_frag_refill(allocsize, pfrag, GFP_ATOMIC))) {
482cac2661cSSteffen Klassert 				spin_unlock_bh(&x->lock);
483cac2661cSSteffen Klassert 				goto cow;
4847021b2e1SHerbert Xu 			}
4857021b2e1SHerbert Xu 
486cac2661cSSteffen Klassert 			page = pfrag->page;
487cac2661cSSteffen Klassert 			get_page(page);
488cac2661cSSteffen Klassert 
4899bd6b629SWillem de Bruijn 			tail = page_address(page) + pfrag->offset;
490cac2661cSSteffen Klassert 
491fca11ebdSSteffen Klassert 			esp_output_fill_trailer(tail, esp->tfclen, esp->plen, esp->proto);
492cac2661cSSteffen Klassert 
493cac2661cSSteffen Klassert 			nfrags = skb_shinfo(skb)->nr_frags;
494cac2661cSSteffen Klassert 
495cac2661cSSteffen Klassert 			__skb_fill_page_desc(skb, nfrags, page, pfrag->offset,
496cac2661cSSteffen Klassert 					     tailen);
497cac2661cSSteffen Klassert 			skb_shinfo(skb)->nr_frags = ++nfrags;
498cac2661cSSteffen Klassert 
499cac2661cSSteffen Klassert 			pfrag->offset = pfrag->offset + allocsize;
50036ff0dd3SSteffen Klassert 
50136ff0dd3SSteffen Klassert 			spin_unlock_bh(&x->lock);
50236ff0dd3SSteffen Klassert 
503cac2661cSSteffen Klassert 			nfrags++;
504cac2661cSSteffen Klassert 
505ede57d58SRichard Gobert 			skb_len_add(skb, tailen);
50609db5124SMartin Willi 			if (sk && sk_fullsock(sk))
50714afee4bSReshetova, Elena 				refcount_add(tailen, &sk->sk_wmem_alloc);
508cac2661cSSteffen Klassert 
509fca11ebdSSteffen Klassert 			goto out;
510fca11ebdSSteffen Klassert 		}
511fca11ebdSSteffen Klassert 	}
512cac2661cSSteffen Klassert 
513fca11ebdSSteffen Klassert cow:
5140e78a873SSteffen Klassert 	esph_offset = (unsigned char *)esp->esph - skb_transport_header(skb);
5150e78a873SSteffen Klassert 
516fca11ebdSSteffen Klassert 	nfrags = skb_cow_data(skb, tailen, &trailer);
517fca11ebdSSteffen Klassert 	if (nfrags < 0)
518fca11ebdSSteffen Klassert 		goto out;
519fca11ebdSSteffen Klassert 	tail = skb_tail_pointer(trailer);
5200e78a873SSteffen Klassert 	esp->esph = (struct ip_esp_hdr *)(skb_transport_header(skb) + esph_offset);
5217021b2e1SHerbert Xu 
522fca11ebdSSteffen Klassert skip_cow:
523fca11ebdSSteffen Klassert 	esp_output_fill_trailer(tail, esp->tfclen, esp->plen, esp->proto);
524fca11ebdSSteffen Klassert 	pskb_put(skb, trailer, tailen);
525fca11ebdSSteffen Klassert 
526fca11ebdSSteffen Klassert out:
527fca11ebdSSteffen Klassert 	return nfrags;
528fca11ebdSSteffen Klassert }
529fca11ebdSSteffen Klassert EXPORT_SYMBOL_GPL(esp_output_head);
530fca11ebdSSteffen Klassert 
esp_output_tail(struct xfrm_state * x,struct sk_buff * skb,struct esp_info * esp)531fca11ebdSSteffen Klassert int esp_output_tail(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *esp)
532fca11ebdSSteffen Klassert {
533fca11ebdSSteffen Klassert 	u8 *iv;
534fca11ebdSSteffen Klassert 	int alen;
535fca11ebdSSteffen Klassert 	void *tmp;
536fca11ebdSSteffen Klassert 	int ivlen;
537fca11ebdSSteffen Klassert 	int assoclen;
538fca11ebdSSteffen Klassert 	int extralen;
539fca11ebdSSteffen Klassert 	struct page *page;
540fca11ebdSSteffen Klassert 	struct ip_esp_hdr *esph;
541fca11ebdSSteffen Klassert 	struct crypto_aead *aead;
542fca11ebdSSteffen Klassert 	struct aead_request *req;
543fca11ebdSSteffen Klassert 	struct scatterlist *sg, *dsg;
544fca11ebdSSteffen Klassert 	struct esp_output_extra *extra;
545fca11ebdSSteffen Klassert 	int err = -ENOMEM;
546fca11ebdSSteffen Klassert 
547fca11ebdSSteffen Klassert 	assoclen = sizeof(struct ip_esp_hdr);
548fca11ebdSSteffen Klassert 	extralen = 0;
549fca11ebdSSteffen Klassert 
550fca11ebdSSteffen Klassert 	if (x->props.flags & XFRM_STATE_ESN) {
551fca11ebdSSteffen Klassert 		extralen += sizeof(*extra);
552fca11ebdSSteffen Klassert 		assoclen += sizeof(__be32);
553fca11ebdSSteffen Klassert 	}
554fca11ebdSSteffen Klassert 
555fca11ebdSSteffen Klassert 	aead = x->data;
556fca11ebdSSteffen Klassert 	alen = crypto_aead_authsize(aead);
557fca11ebdSSteffen Klassert 	ivlen = crypto_aead_ivsize(aead);
558fca11ebdSSteffen Klassert 
559fca11ebdSSteffen Klassert 	tmp = esp_alloc_tmp(aead, esp->nfrags + 2, extralen);
560e892d2d4SSteffen Klassert 	if (!tmp)
561cac2661cSSteffen Klassert 		goto error;
562cac2661cSSteffen Klassert 
563cac2661cSSteffen Klassert 	extra = esp_tmp_extra(tmp);
564cac2661cSSteffen Klassert 	iv = esp_tmp_iv(aead, tmp, extralen);
565cac2661cSSteffen Klassert 	req = esp_tmp_req(aead, iv);
566cac2661cSSteffen Klassert 	sg = esp_req_sg(aead, req);
567cac2661cSSteffen Klassert 
568fca11ebdSSteffen Klassert 	if (esp->inplace)
569fca11ebdSSteffen Klassert 		dsg = sg;
570fca11ebdSSteffen Klassert 	else
571fca11ebdSSteffen Klassert 		dsg = &sg[esp->nfrags];
572cac2661cSSteffen Klassert 
573fca11ebdSSteffen Klassert 	esph = esp_output_set_extra(skb, x, esp->esph, extra);
574fca11ebdSSteffen Klassert 	esp->esph = esph;
575fca11ebdSSteffen Klassert 
576fca11ebdSSteffen Klassert 	sg_init_table(sg, esp->nfrags);
5773f297707SJason A. Donenfeld 	err = skb_to_sgvec(skb, sg,
5787021b2e1SHerbert Xu 		           (unsigned char *)esph - skb->data,
579fca11ebdSSteffen Klassert 		           assoclen + ivlen + esp->clen + alen);
5803f297707SJason A. Donenfeld 	if (unlikely(err < 0))
581e6194923SSteffen Klassert 		goto error_free;
582fca11ebdSSteffen Klassert 
583fca11ebdSSteffen Klassert 	if (!esp->inplace) {
584fca11ebdSSteffen Klassert 		int allocsize;
585fca11ebdSSteffen Klassert 		struct page_frag *pfrag = &x->xfrag;
5860dc49e9bSSteffen Klassert 
587cac2661cSSteffen Klassert 		allocsize = ALIGN(skb->data_len, L1_CACHE_BYTES);
588cac2661cSSteffen Klassert 
589fca11ebdSSteffen Klassert 		spin_lock_bh(&x->lock);
590cac2661cSSteffen Klassert 		if (unlikely(!skb_page_frag_refill(allocsize, pfrag, GFP_ATOMIC))) {
591cac2661cSSteffen Klassert 			spin_unlock_bh(&x->lock);
592e6194923SSteffen Klassert 			goto error_free;
593cac2661cSSteffen Klassert 		}
594cac2661cSSteffen Klassert 
595cac2661cSSteffen Klassert 		skb_shinfo(skb)->nr_frags = 1;
596cac2661cSSteffen Klassert 
597cac2661cSSteffen Klassert 		page = pfrag->page;
598cac2661cSSteffen Klassert 		get_page(page);
599cac2661cSSteffen Klassert 		/* replace page frags in skb with new page */
600cac2661cSSteffen Klassert 		__skb_fill_page_desc(skb, 0, page, pfrag->offset, skb->data_len);
601cac2661cSSteffen Klassert 		pfrag->offset = pfrag->offset + allocsize;
602fca11ebdSSteffen Klassert 		spin_unlock_bh(&x->lock);
603cac2661cSSteffen Klassert 
604cac2661cSSteffen Klassert 		sg_init_table(dsg, skb_shinfo(skb)->nr_frags + 1);
6053f297707SJason A. Donenfeld 		err = skb_to_sgvec(skb, dsg,
606cac2661cSSteffen Klassert 			           (unsigned char *)esph - skb->data,
607fca11ebdSSteffen Klassert 			           assoclen + ivlen + esp->clen + alen);
6083f297707SJason A. Donenfeld 		if (unlikely(err < 0))
609e6194923SSteffen Klassert 			goto error_free;
610cac2661cSSteffen Klassert 	}
611cac2661cSSteffen Klassert 
612cac2661cSSteffen Klassert 	if ((x->props.flags & XFRM_STATE_ESN))
613cac2661cSSteffen Klassert 		aead_request_set_callback(req, 0, esp_output_done_esn, skb);
614cac2661cSSteffen Klassert 	else
615cac2661cSSteffen Klassert 		aead_request_set_callback(req, 0, esp_output_done, skb);
616cac2661cSSteffen Klassert 
617fca11ebdSSteffen Klassert 	aead_request_set_crypt(req, sg, dsg, ivlen + esp->clen, iv);
6187021b2e1SHerbert Xu 	aead_request_set_ad(req, assoclen);
6191da177e4SLinus Torvalds 
6207021b2e1SHerbert Xu 	memset(iv, 0, ivlen);
621fca11ebdSSteffen Klassert 	memcpy(iv + ivlen - min(ivlen, 8), (u8 *)&esp->seqno + 8 - min(ivlen, 8),
6227021b2e1SHerbert Xu 	       min(ivlen, 8));
6236b7326c8SHerbert Xu 
62438320c70SHerbert Xu 	ESP_SKB_CB(skb)->tmp = tmp;
6257021b2e1SHerbert Xu 	err = crypto_aead_encrypt(req);
6267021b2e1SHerbert Xu 
6277021b2e1SHerbert Xu 	switch (err) {
6287021b2e1SHerbert Xu 	case -EINPROGRESS:
62938320c70SHerbert Xu 		goto error;
6301da177e4SLinus Torvalds 
631068c2e70SGilad Ben-Yossef 	case -ENOSPC:
63238320c70SHerbert Xu 		err = NET_XMIT_DROP;
6337021b2e1SHerbert Xu 		break;
6347021b2e1SHerbert Xu 
6357021b2e1SHerbert Xu 	case 0:
6367021b2e1SHerbert Xu 		if ((x->props.flags & XFRM_STATE_ESN))
6377021b2e1SHerbert Xu 			esp_output_restore_header(skb);
6387021b2e1SHerbert Xu 	}
6391da177e4SLinus Torvalds 
640cac2661cSSteffen Klassert 	if (sg != dsg)
641c3198822SDragos Tatulea 		esp_ssg_unref(x, tmp, skb);
642b7c6538cSHerbert Xu 
643e27cca96SSabrina Dubroca 	if (!err && x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP)
644e27cca96SSabrina Dubroca 		err = esp_output_tail_tcp(x, skb);
645e27cca96SSabrina Dubroca 
646e6194923SSteffen Klassert error_free:
647e6194923SSteffen Klassert 	kfree(tmp);
6481da177e4SLinus Torvalds error:
6491da177e4SLinus Torvalds 	return err;
6501da177e4SLinus Torvalds }
651fca11ebdSSteffen Klassert EXPORT_SYMBOL_GPL(esp_output_tail);
6521da177e4SLinus Torvalds 
esp_output(struct xfrm_state * x,struct sk_buff * skb)653fca11ebdSSteffen Klassert static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
654fca11ebdSSteffen Klassert {
655fca11ebdSSteffen Klassert 	int alen;
656fca11ebdSSteffen Klassert 	int blksize;
657fca11ebdSSteffen Klassert 	struct ip_esp_hdr *esph;
658fca11ebdSSteffen Klassert 	struct crypto_aead *aead;
659fca11ebdSSteffen Klassert 	struct esp_info esp;
660fca11ebdSSteffen Klassert 
661fca11ebdSSteffen Klassert 	esp.inplace = true;
662fca11ebdSSteffen Klassert 
663fca11ebdSSteffen Klassert 	esp.proto = *skb_mac_header(skb);
664fca11ebdSSteffen Klassert 	*skb_mac_header(skb) = IPPROTO_ESP;
665fca11ebdSSteffen Klassert 
666fca11ebdSSteffen Klassert 	/* skb is pure payload to encrypt */
667fca11ebdSSteffen Klassert 
668fca11ebdSSteffen Klassert 	aead = x->data;
669fca11ebdSSteffen Klassert 	alen = crypto_aead_authsize(aead);
670fca11ebdSSteffen Klassert 
671fca11ebdSSteffen Klassert 	esp.tfclen = 0;
672fca11ebdSSteffen Klassert 	if (x->tfcpad) {
673fca11ebdSSteffen Klassert 		struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb);
674fca11ebdSSteffen Klassert 		u32 padto;
675fca11ebdSSteffen Klassert 
676a6d95c5aSJiri Bohac 		padto = min(x->tfcpad, xfrm_state_mtu(x, dst->child_mtu_cached));
677fca11ebdSSteffen Klassert 		if (skb->len < padto)
678fca11ebdSSteffen Klassert 			esp.tfclen = padto - skb->len;
679fca11ebdSSteffen Klassert 	}
680fca11ebdSSteffen Klassert 	blksize = ALIGN(crypto_aead_blocksize(aead), 4);
681fca11ebdSSteffen Klassert 	esp.clen = ALIGN(skb->len + 2 + esp.tfclen, blksize);
682fca11ebdSSteffen Klassert 	esp.plen = esp.clen - skb->len - esp.tfclen;
683fca11ebdSSteffen Klassert 	esp.tailen = esp.tfclen + esp.plen + alen;
684fca11ebdSSteffen Klassert 
685fca11ebdSSteffen Klassert 	esp.esph = ip_esp_hdr(skb);
686fca11ebdSSteffen Klassert 
687fca11ebdSSteffen Klassert 	esp.nfrags = esp_output_head(x, skb, &esp);
688fca11ebdSSteffen Klassert 	if (esp.nfrags < 0)
689fca11ebdSSteffen Klassert 		return esp.nfrags;
690fca11ebdSSteffen Klassert 
691fca11ebdSSteffen Klassert 	esph = esp.esph;
692fca11ebdSSteffen Klassert 	esph->spi = x->id.spi;
693fca11ebdSSteffen Klassert 
694fca11ebdSSteffen Klassert 	esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low);
695fca11ebdSSteffen Klassert 	esp.seqno = cpu_to_be64(XFRM_SKB_CB(skb)->seq.output.low +
696fca11ebdSSteffen Klassert 				 ((u64)XFRM_SKB_CB(skb)->seq.output.hi << 32));
697fca11ebdSSteffen Klassert 
698fca11ebdSSteffen Klassert 	skb_push(skb, -skb_network_offset(skb));
699fca11ebdSSteffen Klassert 
700fca11ebdSSteffen Klassert 	return esp_output_tail(x, skb, &esp);
701fca11ebdSSteffen Klassert }
702fca11ebdSSteffen Klassert 
esp_remove_trailer(struct sk_buff * skb)70347ebcc0bSYossi Kuperman static inline int esp_remove_trailer(struct sk_buff *skb)
70447ebcc0bSYossi Kuperman {
70547ebcc0bSYossi Kuperman 	struct xfrm_state *x = xfrm_input_state(skb);
70647ebcc0bSYossi Kuperman 	struct crypto_aead *aead = x->data;
70747ebcc0bSYossi Kuperman 	int alen, hlen, elen;
70847ebcc0bSYossi Kuperman 	int padlen, trimlen;
70947ebcc0bSYossi Kuperman 	__wsum csumdiff;
71047ebcc0bSYossi Kuperman 	u8 nexthdr[2];
71147ebcc0bSYossi Kuperman 	int ret;
71247ebcc0bSYossi Kuperman 
71347ebcc0bSYossi Kuperman 	alen = crypto_aead_authsize(aead);
71447ebcc0bSYossi Kuperman 	hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead);
71547ebcc0bSYossi Kuperman 	elen = skb->len - hlen;
71647ebcc0bSYossi Kuperman 
71747ebcc0bSYossi Kuperman 	if (skb_copy_bits(skb, skb->len - alen - 2, nexthdr, 2))
71847ebcc0bSYossi Kuperman 		BUG();
71947ebcc0bSYossi Kuperman 
72047ebcc0bSYossi Kuperman 	ret = -EINVAL;
72147ebcc0bSYossi Kuperman 	padlen = nexthdr[0];
72247ebcc0bSYossi Kuperman 	if (padlen + 2 + alen >= elen) {
72347ebcc0bSYossi Kuperman 		net_dbg_ratelimited("ipsec esp packet is garbage padlen=%d, elen=%d\n",
72447ebcc0bSYossi Kuperman 				    padlen + 2, elen - alen);
72547ebcc0bSYossi Kuperman 		goto out;
72647ebcc0bSYossi Kuperman 	}
72747ebcc0bSYossi Kuperman 
72847ebcc0bSYossi Kuperman 	trimlen = alen + padlen + 2;
72947ebcc0bSYossi Kuperman 	if (skb->ip_summed == CHECKSUM_COMPLETE) {
73047ebcc0bSYossi Kuperman 		csumdiff = skb_checksum(skb, skb->len - trimlen, trimlen, 0);
73147ebcc0bSYossi Kuperman 		skb->csum = csum_block_sub(skb->csum, csumdiff,
73247ebcc0bSYossi Kuperman 					   skb->len - trimlen);
73347ebcc0bSYossi Kuperman 	}
734513f61e2SMa Ke 	ret = pskb_trim(skb, skb->len - trimlen);
735513f61e2SMa Ke 	if (unlikely(ret))
736513f61e2SMa Ke 		return ret;
73747ebcc0bSYossi Kuperman 
73847ebcc0bSYossi Kuperman 	ret = nexthdr[1];
73947ebcc0bSYossi Kuperman 
74047ebcc0bSYossi Kuperman out:
74147ebcc0bSYossi Kuperman 	return ret;
74247ebcc0bSYossi Kuperman }
74347ebcc0bSYossi Kuperman 
esp_input_done2(struct sk_buff * skb,int err)744fca11ebdSSteffen Klassert int esp_input_done2(struct sk_buff *skb, int err)
7451da177e4SLinus Torvalds {
746b71d1d42SEric Dumazet 	const struct iphdr *iph;
74738320c70SHerbert Xu 	struct xfrm_state *x = xfrm_input_state(skb);
748d77e38e6SSteffen Klassert 	struct xfrm_offload *xo = xfrm_offload(skb);
7491c5ad13fSMathias Krause 	struct crypto_aead *aead = x->data;
75038320c70SHerbert Xu 	int hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead);
75131a4ab93SHerbert Xu 	int ihl;
7521da177e4SLinus Torvalds 
7531d9bfacdSJiapeng Chong 	if (!xo || !(xo->flags & CRYPTO_DONE))
75438320c70SHerbert Xu 		kfree(ESP_SKB_CB(skb)->tmp);
7550ebea8efSHerbert Xu 
7566b7326c8SHerbert Xu 	if (unlikely(err))
757668dc8afSHerbert Xu 		goto out;
7581da177e4SLinus Torvalds 
75947ebcc0bSYossi Kuperman 	err = esp_remove_trailer(skb);
76047ebcc0bSYossi Kuperman 	if (unlikely(err < 0))
7611da177e4SLinus Torvalds 		goto out;
7621da177e4SLinus Torvalds 
763eddc9ec5SArnaldo Carvalho de Melo 	iph = ip_hdr(skb);
76431a4ab93SHerbert Xu 	ihl = iph->ihl * 4;
76531a4ab93SHerbert Xu 
7661da177e4SLinus Torvalds 	if (x->encap) {
767752c1f4cSHerbert Xu 		struct xfrm_encap_tmpl *encap = x->encap;
768e27cca96SSabrina Dubroca 		struct tcphdr *th = (void *)(skb_network_header(skb) + ihl);
769d56f90a7SArnaldo Carvalho de Melo 		struct udphdr *uh = (void *)(skb_network_header(skb) + ihl);
77025f6802bSSabrina Dubroca 		__be16 source;
77125f6802bSSabrina Dubroca 
77225f6802bSSabrina Dubroca 		switch (x->encap->encap_type) {
773e27cca96SSabrina Dubroca 		case TCP_ENCAP_ESPINTCP:
774e27cca96SSabrina Dubroca 			source = th->source;
775e27cca96SSabrina Dubroca 			break;
77625f6802bSSabrina Dubroca 		case UDP_ENCAP_ESPINUDP:
77725f6802bSSabrina Dubroca 			source = uh->source;
77825f6802bSSabrina Dubroca 			break;
77925f6802bSSabrina Dubroca 		default:
78025f6802bSSabrina Dubroca 			WARN_ON_ONCE(1);
78125f6802bSSabrina Dubroca 			err = -EINVAL;
78225f6802bSSabrina Dubroca 			goto out;
78325f6802bSSabrina Dubroca 		}
784752c1f4cSHerbert Xu 
7851da177e4SLinus Torvalds 		/*
7861da177e4SLinus Torvalds 		 * 1) if the NAT-T peer's IP or port changed then
787197f9fbaSDeming Wang 		 *    advertise the change to the keying daemon.
7881da177e4SLinus Torvalds 		 *    This is an inbound SA, so just compare
7891da177e4SLinus Torvalds 		 *    SRC ports.
7901da177e4SLinus Torvalds 		 */
791752c1f4cSHerbert Xu 		if (iph->saddr != x->props.saddr.a4 ||
79225f6802bSSabrina Dubroca 		    source != encap->encap_sport) {
7931da177e4SLinus Torvalds 			xfrm_address_t ipaddr;
7941da177e4SLinus Torvalds 
795752c1f4cSHerbert Xu 			ipaddr.a4 = iph->saddr;
79625f6802bSSabrina Dubroca 			km_new_mapping(x, &ipaddr, source);
7971da177e4SLinus Torvalds 
7981da177e4SLinus Torvalds 			/* XXX: perhaps add an extra
7991da177e4SLinus Torvalds 			 * policy check here, to see
8001da177e4SLinus Torvalds 			 * if we should allow or
8011da177e4SLinus Torvalds 			 * reject a packet from a
8021da177e4SLinus Torvalds 			 * different source
8031da177e4SLinus Torvalds 			 * address/port.
8041da177e4SLinus Torvalds 			 */
8051da177e4SLinus Torvalds 		}
8061da177e4SLinus Torvalds 
8071da177e4SLinus Torvalds 		/*
8081da177e4SLinus Torvalds 		 * 2) ignore UDP/TCP checksums in case
8091da177e4SLinus Torvalds 		 *    of NAT-T in Transport Mode, or
8101da177e4SLinus Torvalds 		 *    perform other post-processing fixes
811752c1f4cSHerbert Xu 		 *    as per draft-ietf-ipsec-udp-encaps-06,
8121da177e4SLinus Torvalds 		 *    section 3.1.2
8131da177e4SLinus Torvalds 		 */
8148bd17075SHerbert Xu 		if (x->props.mode == XFRM_MODE_TRANSPORT)
8151da177e4SLinus Torvalds 			skb->ip_summed = CHECKSUM_UNNECESSARY;
816752c1f4cSHerbert Xu 	}
8171da177e4SLinus Torvalds 
818ec9567a9SIlan Tayari 	skb_pull_rcsum(skb, hlen);
8197143dfacSLi RongQing 	if (x->props.mode == XFRM_MODE_TUNNEL)
8207143dfacSLi RongQing 		skb_reset_transport_header(skb);
8217143dfacSLi RongQing 	else
822967b05f6SArnaldo Carvalho de Melo 		skb_set_transport_header(skb, -ihl);
823752c1f4cSHerbert Xu 
82438320c70SHerbert Xu 	/* RFC4303: Drop dummy packets without any error */
82538320c70SHerbert Xu 	if (err == IPPROTO_NONE)
82638320c70SHerbert Xu 		err = -EINVAL;
82738320c70SHerbert Xu 
82838320c70SHerbert Xu out:
82938320c70SHerbert Xu 	return err;
83038320c70SHerbert Xu }
831fca11ebdSSteffen Klassert EXPORT_SYMBOL_GPL(esp_input_done2);
83238320c70SHerbert Xu 
esp_input_done(void * data,int err)833fd5dabf7SHerbert Xu static void esp_input_done(void *data, int err)
83438320c70SHerbert Xu {
835fd5dabf7SHerbert Xu 	struct sk_buff *skb = data;
83638320c70SHerbert Xu 
83738320c70SHerbert Xu 	xfrm_input_resume(skb, esp_input_done2(skb, err));
83838320c70SHerbert Xu }
83938320c70SHerbert Xu 
esp_input_restore_header(struct sk_buff * skb)8407021b2e1SHerbert Xu static void esp_input_restore_header(struct sk_buff *skb)
8417021b2e1SHerbert Xu {
8427021b2e1SHerbert Xu 	esp_restore_header(skb, 0);
8437021b2e1SHerbert Xu 	__skb_pull(skb, 4);
8447021b2e1SHerbert Xu }
8457021b2e1SHerbert Xu 
esp_input_set_header(struct sk_buff * skb,__be32 * seqhi)846cac2661cSSteffen Klassert static void esp_input_set_header(struct sk_buff *skb, __be32 *seqhi)
847cac2661cSSteffen Klassert {
848cac2661cSSteffen Klassert 	struct xfrm_state *x = xfrm_input_state(skb);
84960aa8046SColin Ian King 	struct ip_esp_hdr *esph;
850cac2661cSSteffen Klassert 
851cac2661cSSteffen Klassert 	/* For ESN we move the header forward by 4 bytes to
852cbd801b3SLu Wei 	 * accommodate the high bits.  We will move it back after
853cac2661cSSteffen Klassert 	 * decryption.
854cac2661cSSteffen Klassert 	 */
855cac2661cSSteffen Klassert 	if ((x->props.flags & XFRM_STATE_ESN)) {
856d58ff351SJohannes Berg 		esph = skb_push(skb, 4);
857cac2661cSSteffen Klassert 		*seqhi = esph->spi;
858cac2661cSSteffen Klassert 		esph->spi = esph->seq_no;
859cac2661cSSteffen Klassert 		esph->seq_no = XFRM_SKB_CB(skb)->seq.input.hi;
860cac2661cSSteffen Klassert 	}
861cac2661cSSteffen Klassert }
862cac2661cSSteffen Klassert 
esp_input_done_esn(void * data,int err)863fd5dabf7SHerbert Xu static void esp_input_done_esn(void *data, int err)
8647021b2e1SHerbert Xu {
865fd5dabf7SHerbert Xu 	struct sk_buff *skb = data;
8667021b2e1SHerbert Xu 
8677021b2e1SHerbert Xu 	esp_input_restore_header(skb);
86814d3109cSHerbert Xu 	esp_input_done(data, err);
8697021b2e1SHerbert Xu }
8707021b2e1SHerbert Xu 
87138320c70SHerbert Xu /*
87238320c70SHerbert Xu  * Note: detecting truncated vs. non-truncated authentication data is very
87338320c70SHerbert Xu  * expensive, so we only support truncated data, which is the recommended
87438320c70SHerbert Xu  * and common case.
87538320c70SHerbert Xu  */
esp_input(struct xfrm_state * x,struct sk_buff * skb)87638320c70SHerbert Xu static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
87738320c70SHerbert Xu {
8781c5ad13fSMathias Krause 	struct crypto_aead *aead = x->data;
87938320c70SHerbert Xu 	struct aead_request *req;
88038320c70SHerbert Xu 	struct sk_buff *trailer;
8817021b2e1SHerbert Xu 	int ivlen = crypto_aead_ivsize(aead);
8820c05f983SHaishuang Yan 	int elen = skb->len - sizeof(struct ip_esp_hdr) - ivlen;
88338320c70SHerbert Xu 	int nfrags;
8840dc49e9bSSteffen Klassert 	int assoclen;
8850dc49e9bSSteffen Klassert 	int seqhilen;
8860dc49e9bSSteffen Klassert 	__be32 *seqhi;
88738320c70SHerbert Xu 	void *tmp;
88838320c70SHerbert Xu 	u8 *iv;
88938320c70SHerbert Xu 	struct scatterlist *sg;
89038320c70SHerbert Xu 	int err = -EINVAL;
89138320c70SHerbert Xu 
8920c05f983SHaishuang Yan 	if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr) + ivlen))
89338320c70SHerbert Xu 		goto out;
89438320c70SHerbert Xu 
89538320c70SHerbert Xu 	if (elen <= 0)
89638320c70SHerbert Xu 		goto out;
89738320c70SHerbert Xu 
8980c05f983SHaishuang Yan 	assoclen = sizeof(struct ip_esp_hdr);
8990dc49e9bSSteffen Klassert 	seqhilen = 0;
9000dc49e9bSSteffen Klassert 
9010dc49e9bSSteffen Klassert 	if (x->props.flags & XFRM_STATE_ESN) {
9020dc49e9bSSteffen Klassert 		seqhilen += sizeof(__be32);
9030dc49e9bSSteffen Klassert 		assoclen += seqhilen;
9040dc49e9bSSteffen Klassert 	}
9050dc49e9bSSteffen Klassert 
906cac2661cSSteffen Klassert 	if (!skb_cloned(skb)) {
907cac2661cSSteffen Klassert 		if (!skb_is_nonlinear(skb)) {
908cac2661cSSteffen Klassert 			nfrags = 1;
909cac2661cSSteffen Klassert 
910cac2661cSSteffen Klassert 			goto skip_cow;
911cac2661cSSteffen Klassert 		} else if (!skb_has_frag_list(skb)) {
912cac2661cSSteffen Klassert 			nfrags = skb_shinfo(skb)->nr_frags;
913cac2661cSSteffen Klassert 			nfrags++;
914cac2661cSSteffen Klassert 
915cac2661cSSteffen Klassert 			goto skip_cow;
916cac2661cSSteffen Klassert 		}
917cac2661cSSteffen Klassert 	}
918cac2661cSSteffen Klassert 
919cac2661cSSteffen Klassert 	err = skb_cow_data(skb, 0, &trailer);
920cac2661cSSteffen Klassert 	if (err < 0)
921cac2661cSSteffen Klassert 		goto out;
922cac2661cSSteffen Klassert 
923cac2661cSSteffen Klassert 	nfrags = err;
924cac2661cSSteffen Klassert 
925cac2661cSSteffen Klassert skip_cow:
92638320c70SHerbert Xu 	err = -ENOMEM;
9277021b2e1SHerbert Xu 	tmp = esp_alloc_tmp(aead, nfrags, seqhilen);
92838320c70SHerbert Xu 	if (!tmp)
92938320c70SHerbert Xu 		goto out;
93038320c70SHerbert Xu 
93138320c70SHerbert Xu 	ESP_SKB_CB(skb)->tmp = tmp;
932962fcef3SHerbert Xu 	seqhi = esp_tmp_extra(tmp);
9330dc49e9bSSteffen Klassert 	iv = esp_tmp_iv(aead, tmp, seqhilen);
93438320c70SHerbert Xu 	req = esp_tmp_req(aead, iv);
9357021b2e1SHerbert Xu 	sg = esp_req_sg(aead, req);
93638320c70SHerbert Xu 
937cac2661cSSteffen Klassert 	esp_input_set_header(skb, seqhi);
93838320c70SHerbert Xu 
93938320c70SHerbert Xu 	sg_init_table(sg, nfrags);
9403f297707SJason A. Donenfeld 	err = skb_to_sgvec(skb, sg, 0, skb->len);
941e6194923SSteffen Klassert 	if (unlikely(err < 0)) {
942e6194923SSteffen Klassert 		kfree(tmp);
9433f297707SJason A. Donenfeld 		goto out;
944e6194923SSteffen Klassert 	}
9450dc49e9bSSteffen Klassert 
946cac2661cSSteffen Klassert 	skb->ip_summed = CHECKSUM_NONE;
947cac2661cSSteffen Klassert 
948cac2661cSSteffen Klassert 	if ((x->props.flags & XFRM_STATE_ESN))
949cac2661cSSteffen Klassert 		aead_request_set_callback(req, 0, esp_input_done_esn, skb);
950cac2661cSSteffen Klassert 	else
951cac2661cSSteffen Klassert 		aead_request_set_callback(req, 0, esp_input_done, skb);
952cac2661cSSteffen Klassert 
9537021b2e1SHerbert Xu 	aead_request_set_crypt(req, sg, sg, elen + ivlen, iv);
9547021b2e1SHerbert Xu 	aead_request_set_ad(req, assoclen);
95538320c70SHerbert Xu 
95638320c70SHerbert Xu 	err = crypto_aead_decrypt(req);
95738320c70SHerbert Xu 	if (err == -EINPROGRESS)
95838320c70SHerbert Xu 		goto out;
95938320c70SHerbert Xu 
9607021b2e1SHerbert Xu 	if ((x->props.flags & XFRM_STATE_ESN))
9617021b2e1SHerbert Xu 		esp_input_restore_header(skb);
9627021b2e1SHerbert Xu 
96338320c70SHerbert Xu 	err = esp_input_done2(skb, err);
964752c1f4cSHerbert Xu 
965752c1f4cSHerbert Xu out:
966668dc8afSHerbert Xu 	return err;
9671da177e4SLinus Torvalds }
9681da177e4SLinus Torvalds 
esp4_err(struct sk_buff * skb,u32 info)969827789cbSSteffen Klassert static int esp4_err(struct sk_buff *skb, u32 info)
9701da177e4SLinus Torvalds {
9714fb236baSAlexey Dobriyan 	struct net *net = dev_net(skb->dev);
972b71d1d42SEric Dumazet 	const struct iphdr *iph = (const struct iphdr *)skb->data;
9731da177e4SLinus Torvalds 	struct ip_esp_hdr *esph = (struct ip_esp_hdr *)(skb->data+(iph->ihl<<2));
9741da177e4SLinus Torvalds 	struct xfrm_state *x;
9751da177e4SLinus Torvalds 
97655be7a9cSDavid S. Miller 	switch (icmp_hdr(skb)->type) {
97755be7a9cSDavid S. Miller 	case ICMP_DEST_UNREACH:
97855be7a9cSDavid S. Miller 		if (icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
979827789cbSSteffen Klassert 			return 0;
98079121184SGustavo A. R. Silva 		break;
98155be7a9cSDavid S. Miller 	case ICMP_REDIRECT:
98255be7a9cSDavid S. Miller 		break;
98355be7a9cSDavid S. Miller 	default:
984827789cbSSteffen Klassert 		return 0;
98555be7a9cSDavid S. Miller 	}
9861da177e4SLinus Torvalds 
987b71d1d42SEric Dumazet 	x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
988b71d1d42SEric Dumazet 			      esph->spi, IPPROTO_ESP, AF_INET);
9891da177e4SLinus Torvalds 	if (!x)
990827789cbSSteffen Klassert 		return 0;
99155be7a9cSDavid S. Miller 
992387aa65aSTimo Teräs 	if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH)
993d888f396SMaciej Żenczykowski 		ipv4_update_pmtu(skb, net, info, 0, IPPROTO_ESP);
994387aa65aSTimo Teräs 	else
9951042caa7SMaciej Żenczykowski 		ipv4_redirect(skb, net, 0, IPPROTO_ESP);
9961da177e4SLinus Torvalds 	xfrm_state_put(x);
997827789cbSSteffen Klassert 
998827789cbSSteffen Klassert 	return 0;
9991da177e4SLinus Torvalds }
10001da177e4SLinus Torvalds 
esp_destroy(struct xfrm_state * x)10011da177e4SLinus Torvalds static void esp_destroy(struct xfrm_state *x)
10021da177e4SLinus Torvalds {
10031c5ad13fSMathias Krause 	struct crypto_aead *aead = x->data;
10041da177e4SLinus Torvalds 
10051c5ad13fSMathias Krause 	if (!aead)
10061da177e4SLinus Torvalds 		return;
10071da177e4SLinus Torvalds 
10081c5ad13fSMathias Krause 	crypto_free_aead(aead);
10091da177e4SLinus Torvalds }
10101da177e4SLinus Torvalds 
esp_init_aead(struct xfrm_state * x,struct netlink_ext_ack * extack)101167c44f93SSabrina Dubroca static int esp_init_aead(struct xfrm_state *x, struct netlink_ext_ack *extack)
10121da177e4SLinus Torvalds {
10137021b2e1SHerbert Xu 	char aead_name[CRYPTO_MAX_ALG_NAME];
10141a6509d9SHerbert Xu 	struct crypto_aead *aead;
10151a6509d9SHerbert Xu 	int err;
10161a6509d9SHerbert Xu 
10177021b2e1SHerbert Xu 	if (snprintf(aead_name, CRYPTO_MAX_ALG_NAME, "%s(%s)",
101867c44f93SSabrina Dubroca 		     x->geniv, x->aead->alg_name) >= CRYPTO_MAX_ALG_NAME) {
101967c44f93SSabrina Dubroca 		NL_SET_ERR_MSG(extack, "Algorithm name is too long");
102067c44f93SSabrina Dubroca 		return -ENAMETOOLONG;
102167c44f93SSabrina Dubroca 	}
10227021b2e1SHerbert Xu 
1023f58869c4SSteffen Klassert 	aead = crypto_alloc_aead(aead_name, 0, 0);
10241a6509d9SHerbert Xu 	err = PTR_ERR(aead);
10251a6509d9SHerbert Xu 	if (IS_ERR(aead))
10261a6509d9SHerbert Xu 		goto error;
10271a6509d9SHerbert Xu 
10281c5ad13fSMathias Krause 	x->data = aead;
10291a6509d9SHerbert Xu 
10301a6509d9SHerbert Xu 	err = crypto_aead_setkey(aead, x->aead->alg_key,
10311a6509d9SHerbert Xu 				 (x->aead->alg_key_len + 7) / 8);
10321a6509d9SHerbert Xu 	if (err)
10331a6509d9SHerbert Xu 		goto error;
10341a6509d9SHerbert Xu 
10351a6509d9SHerbert Xu 	err = crypto_aead_setauthsize(aead, x->aead->alg_icv_len / 8);
10361a6509d9SHerbert Xu 	if (err)
10371a6509d9SHerbert Xu 		goto error;
10381a6509d9SHerbert Xu 
103967c44f93SSabrina Dubroca 	return 0;
104067c44f93SSabrina Dubroca 
10411a6509d9SHerbert Xu error:
104267c44f93SSabrina Dubroca 	NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
10431a6509d9SHerbert Xu 	return err;
10441a6509d9SHerbert Xu }
10451a6509d9SHerbert Xu 
esp_init_authenc(struct xfrm_state * x,struct netlink_ext_ack * extack)104667c44f93SSabrina Dubroca static int esp_init_authenc(struct xfrm_state *x,
104767c44f93SSabrina Dubroca 			    struct netlink_ext_ack *extack)
10481a6509d9SHerbert Xu {
104938320c70SHerbert Xu 	struct crypto_aead *aead;
105038320c70SHerbert Xu 	struct crypto_authenc_key_param *param;
105138320c70SHerbert Xu 	struct rtattr *rta;
105238320c70SHerbert Xu 	char *key;
105338320c70SHerbert Xu 	char *p;
105438320c70SHerbert Xu 	char authenc_name[CRYPTO_MAX_ALG_NAME];
105538320c70SHerbert Xu 	unsigned int keylen;
105638320c70SHerbert Xu 	int err;
10571da177e4SLinus Torvalds 
10581a6509d9SHerbert Xu 	err = -ENAMETOOLONG;
10590dc49e9bSSteffen Klassert 
10600dc49e9bSSteffen Klassert 	if ((x->props.flags & XFRM_STATE_ESN)) {
10610dc49e9bSSteffen Klassert 		if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME,
10627021b2e1SHerbert Xu 			     "%s%sauthencesn(%s,%s)%s",
10637021b2e1SHerbert Xu 			     x->geniv ?: "", x->geniv ? "(" : "",
106438320c70SHerbert Xu 			     x->aalg ? x->aalg->alg_name : "digest_null",
10657021b2e1SHerbert Xu 			     x->ealg->alg_name,
106667c44f93SSabrina Dubroca 			     x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME) {
106767c44f93SSabrina Dubroca 			NL_SET_ERR_MSG(extack, "Algorithm name is too long");
10681a6509d9SHerbert Xu 			goto error;
106967c44f93SSabrina Dubroca 		}
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,
107667c44f93SSabrina Dubroca 			     x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME) {
107767c44f93SSabrina Dubroca 			NL_SET_ERR_MSG(extack, "Algorithm name is too long");
10780dc49e9bSSteffen Klassert 			goto error;
10790dc49e9bSSteffen Klassert 		}
108067c44f93SSabrina Dubroca 	}
108138320c70SHerbert Xu 
1082f58869c4SSteffen Klassert 	aead = crypto_alloc_aead(authenc_name, 0, 0);
108338320c70SHerbert Xu 	err = PTR_ERR(aead);
108467c44f93SSabrina Dubroca 	if (IS_ERR(aead)) {
108567c44f93SSabrina Dubroca 		NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
108638320c70SHerbert Xu 		goto error;
108767c44f93SSabrina Dubroca 	}
108838320c70SHerbert Xu 
10891c5ad13fSMathias Krause 	x->data = aead;
109038320c70SHerbert Xu 
109138320c70SHerbert Xu 	keylen = (x->aalg ? (x->aalg->alg_key_len + 7) / 8 : 0) +
109238320c70SHerbert Xu 		 (x->ealg->alg_key_len + 7) / 8 + RTA_SPACE(sizeof(*param));
109338320c70SHerbert Xu 	err = -ENOMEM;
109438320c70SHerbert Xu 	key = kmalloc(keylen, GFP_KERNEL);
109538320c70SHerbert Xu 	if (!key)
109638320c70SHerbert Xu 		goto error;
109738320c70SHerbert Xu 
109838320c70SHerbert Xu 	p = key;
109938320c70SHerbert Xu 	rta = (void *)p;
110038320c70SHerbert Xu 	rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM;
110138320c70SHerbert Xu 	rta->rta_len = RTA_LENGTH(sizeof(*param));
110238320c70SHerbert Xu 	param = RTA_DATA(rta);
110338320c70SHerbert Xu 	p += RTA_SPACE(sizeof(*param));
110438320c70SHerbert Xu 
11051da177e4SLinus Torvalds 	if (x->aalg) {
11061da177e4SLinus Torvalds 		struct xfrm_algo_desc *aalg_desc;
11071da177e4SLinus Torvalds 
110838320c70SHerbert Xu 		memcpy(p, x->aalg->alg_key, (x->aalg->alg_key_len + 7) / 8);
110938320c70SHerbert Xu 		p += (x->aalg->alg_key_len + 7) / 8;
11101da177e4SLinus Torvalds 
11111da177e4SLinus Torvalds 		aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
11121da177e4SLinus Torvalds 		BUG_ON(!aalg_desc);
11131da177e4SLinus Torvalds 
111438320c70SHerbert Xu 		err = -EINVAL;
11151da177e4SLinus Torvalds 		if (aalg_desc->uinfo.auth.icv_fullbits / 8 !=
111638320c70SHerbert Xu 		    crypto_aead_authsize(aead)) {
111767c44f93SSabrina Dubroca 			NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
111838320c70SHerbert Xu 			goto free_key;
11191da177e4SLinus Torvalds 		}
11201da177e4SLinus Torvalds 
112138320c70SHerbert Xu 		err = crypto_aead_setauthsize(
11228f8a088cSMartin Willi 			aead, x->aalg->alg_trunc_len / 8);
112367c44f93SSabrina Dubroca 		if (err) {
112467c44f93SSabrina Dubroca 			NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
112538320c70SHerbert Xu 			goto free_key;
11261da177e4SLinus Torvalds 		}
112767c44f93SSabrina Dubroca 	}
11284b7137ffSHerbert Xu 
112938320c70SHerbert Xu 	param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8);
113038320c70SHerbert Xu 	memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8);
113138320c70SHerbert Xu 
113238320c70SHerbert Xu 	err = crypto_aead_setkey(aead, key, keylen);
113338320c70SHerbert Xu 
113438320c70SHerbert Xu free_key:
1135daa75144SWang Ming 	kfree_sensitive(key);
113638320c70SHerbert Xu 
11371a6509d9SHerbert Xu error:
11381a6509d9SHerbert Xu 	return err;
11391a6509d9SHerbert Xu }
11401a6509d9SHerbert Xu 
esp_init_state(struct xfrm_state * x,struct netlink_ext_ack * extack)1141e1e10b44SSabrina Dubroca static int esp_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
11421a6509d9SHerbert Xu {
11431a6509d9SHerbert Xu 	struct crypto_aead *aead;
11441a6509d9SHerbert Xu 	u32 align;
11451a6509d9SHerbert Xu 	int err;
11461a6509d9SHerbert Xu 
11471c5ad13fSMathias Krause 	x->data = NULL;
11481a6509d9SHerbert Xu 
114967c44f93SSabrina Dubroca 	if (x->aead) {
115067c44f93SSabrina Dubroca 		err = esp_init_aead(x, extack);
115167c44f93SSabrina Dubroca 	} else if (x->ealg) {
115267c44f93SSabrina Dubroca 		err = esp_init_authenc(x, extack);
115367c44f93SSabrina Dubroca 	} else {
115467c44f93SSabrina Dubroca 		NL_SET_ERR_MSG(extack, "ESP: AEAD or CRYPT must be provided");
115567c44f93SSabrina Dubroca 		err = -EINVAL;
115667c44f93SSabrina Dubroca 	}
11571a6509d9SHerbert Xu 
115838320c70SHerbert Xu 	if (err)
11591da177e4SLinus Torvalds 		goto error;
116038320c70SHerbert Xu 
11611c5ad13fSMathias Krause 	aead = x->data;
11621a6509d9SHerbert Xu 
116338320c70SHerbert Xu 	x->props.header_len = sizeof(struct ip_esp_hdr) +
116438320c70SHerbert Xu 			      crypto_aead_ivsize(aead);
11657e49e6deSMasahide NAKAMURA 	if (x->props.mode == XFRM_MODE_TUNNEL)
11661da177e4SLinus Torvalds 		x->props.header_len += sizeof(struct iphdr);
1167eb49e630SJoakim Koskela 	else if (x->props.mode == XFRM_MODE_BEET && x->sel.family != AF_INET6)
1168ac758e3cSPatrick McHardy 		x->props.header_len += IPV4_BEET_PHMAXLEN;
11691da177e4SLinus Torvalds 	if (x->encap) {
11701da177e4SLinus Torvalds 		struct xfrm_encap_tmpl *encap = x->encap;
11711da177e4SLinus Torvalds 
11721da177e4SLinus Torvalds 		switch (encap->encap_type) {
11731da177e4SLinus Torvalds 		default:
117467c44f93SSabrina Dubroca 			NL_SET_ERR_MSG(extack, "Unsupported encapsulation type for ESP");
1175bcfd09f7SHerbert Xu 			err = -EINVAL;
11761da177e4SLinus Torvalds 			goto error;
11771da177e4SLinus Torvalds 		case UDP_ENCAP_ESPINUDP:
11781da177e4SLinus Torvalds 			x->props.header_len += sizeof(struct udphdr);
11791da177e4SLinus Torvalds 			break;
1180e27cca96SSabrina Dubroca #ifdef CONFIG_INET_ESPINTCP
1181e27cca96SSabrina Dubroca 		case TCP_ENCAP_ESPINTCP:
1182e27cca96SSabrina Dubroca 			/* only the length field, TCP encap is done by
1183e27cca96SSabrina Dubroca 			 * the socket
1184e27cca96SSabrina Dubroca 			 */
1185e27cca96SSabrina Dubroca 			x->props.header_len += 2;
1186e27cca96SSabrina Dubroca 			break;
1187e27cca96SSabrina Dubroca #endif
11881da177e4SLinus Torvalds 		}
11891da177e4SLinus Torvalds 	}
119038320c70SHerbert Xu 
119138320c70SHerbert Xu 	align = ALIGN(crypto_aead_blocksize(aead), 4);
11921c5ad13fSMathias Krause 	x->props.trailer_len = align + 1 + crypto_aead_authsize(aead);
11931da177e4SLinus Torvalds 
11941da177e4SLinus Torvalds error:
119538320c70SHerbert Xu 	return err;
11961da177e4SLinus Torvalds }
11971da177e4SLinus Torvalds 
esp4_rcv_cb(struct sk_buff * skb,int err)1198827789cbSSteffen Klassert static int esp4_rcv_cb(struct sk_buff *skb, int err)
1199827789cbSSteffen Klassert {
1200827789cbSSteffen Klassert 	return 0;
1201827789cbSSteffen Klassert }
1202827789cbSSteffen Klassert 
1203533cb5b0SEric Dumazet static const struct xfrm_type esp_type =
12041da177e4SLinus Torvalds {
12051da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
12061da177e4SLinus Torvalds 	.proto	     	= IPPROTO_ESP,
1207436a0a40SHerbert Xu 	.flags		= XFRM_TYPE_REPLAY_PROT,
12081da177e4SLinus Torvalds 	.init_state	= esp_init_state,
12091da177e4SLinus Torvalds 	.destructor	= esp_destroy,
12101da177e4SLinus Torvalds 	.input		= esp_input,
1211fca11ebdSSteffen Klassert 	.output		= esp_output,
12121da177e4SLinus Torvalds };
12131da177e4SLinus Torvalds 
1214827789cbSSteffen Klassert static struct xfrm4_protocol esp4_protocol = {
12151da177e4SLinus Torvalds 	.handler	=	xfrm4_rcv,
1216827789cbSSteffen Klassert 	.input_handler	=	xfrm_input,
1217827789cbSSteffen Klassert 	.cb_handler	=	esp4_rcv_cb,
12181da177e4SLinus Torvalds 	.err_handler	=	esp4_err,
1219827789cbSSteffen Klassert 	.priority	=	0,
12201da177e4SLinus Torvalds };
12211da177e4SLinus Torvalds 
esp4_init(void)12221da177e4SLinus Torvalds static int __init esp4_init(void)
12231da177e4SLinus Torvalds {
12241da177e4SLinus Torvalds 	if (xfrm_register_type(&esp_type, AF_INET) < 0) {
1225058bd4d2SJoe Perches 		pr_info("%s: can't add xfrm type\n", __func__);
12261da177e4SLinus Torvalds 		return -EAGAIN;
12271da177e4SLinus Torvalds 	}
1228827789cbSSteffen Klassert 	if (xfrm4_protocol_register(&esp4_protocol, IPPROTO_ESP) < 0) {
1229058bd4d2SJoe Perches 		pr_info("%s: can't add protocol\n", __func__);
12301da177e4SLinus Torvalds 		xfrm_unregister_type(&esp_type, AF_INET);
12311da177e4SLinus Torvalds 		return -EAGAIN;
12321da177e4SLinus Torvalds 	}
12331da177e4SLinus Torvalds 	return 0;
12341da177e4SLinus Torvalds }
12351da177e4SLinus Torvalds 
esp4_fini(void)12361da177e4SLinus Torvalds static void __exit esp4_fini(void)
12371da177e4SLinus Torvalds {
1238827789cbSSteffen Klassert 	if (xfrm4_protocol_deregister(&esp4_protocol, IPPROTO_ESP) < 0)
1239058bd4d2SJoe Perches 		pr_info("%s: can't remove protocol\n", __func__);
12404f518e80SFlorian Westphal 	xfrm_unregister_type(&esp_type, AF_INET);
12411da177e4SLinus Torvalds }
12421da177e4SLinus Torvalds 
12431da177e4SLinus Torvalds module_init(esp4_init);
12441da177e4SLinus Torvalds module_exit(esp4_fini);
1245b058a5d2SBreno Leitao MODULE_DESCRIPTION("IPv4 ESP transformation library");
12461da177e4SLinus Torvalds MODULE_LICENSE("GPL");
1247d3d6dd3aSMasahide NAKAMURA MODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_ESP);
1248