xref: /linux/net/ipv4/esp4.c (revision fd5dabf764f79ced0b128ddad39fb272e884a5b8)
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;
1374461568aSKuniyuki Iwashima 	struct net *net = xs_net(x);
138e27cca96SSabrina Dubroca 	struct esp_tcp_sk *esk;
139e27cca96SSabrina Dubroca 	__be16 sport, dport;
140e27cca96SSabrina Dubroca 	struct sock *nsk;
141e27cca96SSabrina Dubroca 	struct sock *sk;
142e27cca96SSabrina Dubroca 
143e27cca96SSabrina Dubroca 	sk = rcu_dereference(x->encap_sk);
144e27cca96SSabrina Dubroca 	if (sk && sk->sk_state == TCP_ESTABLISHED)
145e27cca96SSabrina Dubroca 		return sk;
146e27cca96SSabrina Dubroca 
147e27cca96SSabrina Dubroca 	spin_lock_bh(&x->lock);
148e27cca96SSabrina Dubroca 	sport = encap->encap_sport;
149e27cca96SSabrina Dubroca 	dport = encap->encap_dport;
150e27cca96SSabrina Dubroca 	nsk = rcu_dereference_protected(x->encap_sk,
151e27cca96SSabrina Dubroca 					lockdep_is_held(&x->lock));
152e27cca96SSabrina Dubroca 	if (sk && sk == nsk) {
153e27cca96SSabrina Dubroca 		esk = kmalloc(sizeof(*esk), GFP_ATOMIC);
154e27cca96SSabrina Dubroca 		if (!esk) {
155e27cca96SSabrina Dubroca 			spin_unlock_bh(&x->lock);
156e27cca96SSabrina Dubroca 			return ERR_PTR(-ENOMEM);
157e27cca96SSabrina Dubroca 		}
158e27cca96SSabrina Dubroca 		RCU_INIT_POINTER(x->encap_sk, NULL);
159e27cca96SSabrina Dubroca 		esk->sk = sk;
160e27cca96SSabrina Dubroca 		call_rcu(&esk->rcu, esp_free_tcp_sk);
161e27cca96SSabrina Dubroca 	}
162e27cca96SSabrina Dubroca 	spin_unlock_bh(&x->lock);
163e27cca96SSabrina Dubroca 
1644461568aSKuniyuki Iwashima 	sk = inet_lookup_established(net, net->ipv4.tcp_death_row.hashinfo, x->id.daddr.a4,
165e27cca96SSabrina Dubroca 				     dport, x->props.saddr.a4, sport, 0);
166e27cca96SSabrina Dubroca 	if (!sk)
167e27cca96SSabrina Dubroca 		return ERR_PTR(-ENOENT);
168e27cca96SSabrina Dubroca 
169e27cca96SSabrina Dubroca 	if (!tcp_is_ulp_esp(sk)) {
170e27cca96SSabrina Dubroca 		sock_put(sk);
171e27cca96SSabrina Dubroca 		return ERR_PTR(-EINVAL);
172e27cca96SSabrina Dubroca 	}
173e27cca96SSabrina Dubroca 
174e27cca96SSabrina Dubroca 	spin_lock_bh(&x->lock);
175e27cca96SSabrina Dubroca 	nsk = rcu_dereference_protected(x->encap_sk,
176e27cca96SSabrina Dubroca 					lockdep_is_held(&x->lock));
177e27cca96SSabrina Dubroca 	if (encap->encap_sport != sport ||
178e27cca96SSabrina Dubroca 	    encap->encap_dport != dport) {
179e27cca96SSabrina Dubroca 		sock_put(sk);
180e27cca96SSabrina Dubroca 		sk = nsk ?: ERR_PTR(-EREMCHG);
181e27cca96SSabrina Dubroca 	} else if (sk == nsk) {
182e27cca96SSabrina Dubroca 		sock_put(sk);
183e27cca96SSabrina Dubroca 	} else {
184e27cca96SSabrina Dubroca 		rcu_assign_pointer(x->encap_sk, sk);
185e27cca96SSabrina Dubroca 	}
186e27cca96SSabrina Dubroca 	spin_unlock_bh(&x->lock);
187e27cca96SSabrina Dubroca 
188e27cca96SSabrina Dubroca 	return sk;
189e27cca96SSabrina Dubroca }
190e27cca96SSabrina Dubroca 
191e27cca96SSabrina Dubroca static int esp_output_tcp_finish(struct xfrm_state *x, struct sk_buff *skb)
192e27cca96SSabrina Dubroca {
193e27cca96SSabrina Dubroca 	struct sock *sk;
194e27cca96SSabrina Dubroca 	int err;
195e27cca96SSabrina Dubroca 
196e27cca96SSabrina Dubroca 	rcu_read_lock();
197e27cca96SSabrina Dubroca 
198e27cca96SSabrina Dubroca 	sk = esp_find_tcp_sk(x);
199e27cca96SSabrina Dubroca 	err = PTR_ERR_OR_ZERO(sk);
200e27cca96SSabrina Dubroca 	if (err)
201e27cca96SSabrina Dubroca 		goto out;
202e27cca96SSabrina Dubroca 
203e27cca96SSabrina Dubroca 	bh_lock_sock(sk);
204e27cca96SSabrina Dubroca 	if (sock_owned_by_user(sk))
205e27cca96SSabrina Dubroca 		err = espintcp_queue_out(sk, skb);
206e27cca96SSabrina Dubroca 	else
207e27cca96SSabrina Dubroca 		err = espintcp_push_skb(sk, skb);
208e27cca96SSabrina Dubroca 	bh_unlock_sock(sk);
209e27cca96SSabrina Dubroca 
210e27cca96SSabrina Dubroca out:
211e27cca96SSabrina Dubroca 	rcu_read_unlock();
212e27cca96SSabrina Dubroca 	return err;
213e27cca96SSabrina Dubroca }
214e27cca96SSabrina Dubroca 
215e27cca96SSabrina Dubroca static int esp_output_tcp_encap_cb(struct net *net, struct sock *sk,
216e27cca96SSabrina Dubroca 				   struct sk_buff *skb)
217e27cca96SSabrina Dubroca {
218e27cca96SSabrina Dubroca 	struct dst_entry *dst = skb_dst(skb);
219e27cca96SSabrina Dubroca 	struct xfrm_state *x = dst->xfrm;
220e27cca96SSabrina Dubroca 
221e27cca96SSabrina Dubroca 	return esp_output_tcp_finish(x, skb);
222e27cca96SSabrina Dubroca }
223e27cca96SSabrina Dubroca 
224e27cca96SSabrina Dubroca static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)
225e27cca96SSabrina Dubroca {
226e27cca96SSabrina Dubroca 	int err;
227e27cca96SSabrina Dubroca 
228e27cca96SSabrina Dubroca 	local_bh_disable();
229e27cca96SSabrina Dubroca 	err = xfrm_trans_queue_net(xs_net(x), skb, esp_output_tcp_encap_cb);
230e27cca96SSabrina Dubroca 	local_bh_enable();
231e27cca96SSabrina Dubroca 
232e27cca96SSabrina Dubroca 	/* EINPROGRESS just happens to do the right thing.  It
233e27cca96SSabrina Dubroca 	 * actually means that the skb has been consumed and
234e27cca96SSabrina Dubroca 	 * isn't coming back.
235e27cca96SSabrina Dubroca 	 */
236e27cca96SSabrina Dubroca 	return err ?: -EINPROGRESS;
237e27cca96SSabrina Dubroca }
238e27cca96SSabrina Dubroca #else
239e27cca96SSabrina Dubroca static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)
240e27cca96SSabrina Dubroca {
241e27cca96SSabrina Dubroca 	kfree_skb(skb);
242e27cca96SSabrina Dubroca 
243e27cca96SSabrina Dubroca 	return -EOPNOTSUPP;
244e27cca96SSabrina Dubroca }
245e27cca96SSabrina Dubroca #endif
246e27cca96SSabrina Dubroca 
247*fd5dabf7SHerbert Xu static void esp_output_done(void *data, int err)
24838320c70SHerbert Xu {
249*fd5dabf7SHerbert Xu 	struct sk_buff *skb = data;
250f53c7239SSteffen Klassert 	struct xfrm_offload *xo = xfrm_offload(skb);
251cac2661cSSteffen Klassert 	void *tmp;
252f53c7239SSteffen Klassert 	struct xfrm_state *x;
253f53c7239SSteffen Klassert 
2542294be0fSFlorian Westphal 	if (xo && (xo->flags & XFRM_DEV_RESUME)) {
2552294be0fSFlorian Westphal 		struct sec_path *sp = skb_sec_path(skb);
2562294be0fSFlorian Westphal 
2572294be0fSFlorian Westphal 		x = sp->xvec[sp->len - 1];
2582294be0fSFlorian Westphal 	} else {
259f53c7239SSteffen Klassert 		x = skb_dst(skb)->xfrm;
2602294be0fSFlorian Westphal 	}
26138320c70SHerbert Xu 
262cac2661cSSteffen Klassert 	tmp = ESP_SKB_CB(skb)->tmp;
263cac2661cSSteffen Klassert 	esp_ssg_unref(x, tmp);
264cac2661cSSteffen Klassert 	kfree(tmp);
265f53c7239SSteffen Klassert 
266f53c7239SSteffen Klassert 	if (xo && (xo->flags & XFRM_DEV_RESUME)) {
267f53c7239SSteffen Klassert 		if (err) {
268f53c7239SSteffen Klassert 			XFRM_INC_STATS(xs_net(x), LINUX_MIB_XFRMOUTSTATEPROTOERROR);
269f53c7239SSteffen Klassert 			kfree_skb(skb);
270f53c7239SSteffen Klassert 			return;
271f53c7239SSteffen Klassert 		}
272f53c7239SSteffen Klassert 
273f53c7239SSteffen Klassert 		skb_push(skb, skb->data - skb_mac_header(skb));
274f53c7239SSteffen Klassert 		secpath_reset(skb);
275f53c7239SSteffen Klassert 		xfrm_dev_resume(skb);
276f53c7239SSteffen Klassert 	} else {
277e27cca96SSabrina Dubroca 		if (!err &&
278e27cca96SSabrina Dubroca 		    x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP)
279e27cca96SSabrina Dubroca 			esp_output_tail_tcp(x, skb);
280e27cca96SSabrina Dubroca 		else
2819ab1265dSEvan Nimmo 			xfrm_output_resume(skb->sk, skb, err);
28238320c70SHerbert Xu 	}
283f53c7239SSteffen Klassert }
28438320c70SHerbert Xu 
2857021b2e1SHerbert Xu /* Move ESP header back into place. */
2867021b2e1SHerbert Xu static void esp_restore_header(struct sk_buff *skb, unsigned int offset)
2877021b2e1SHerbert Xu {
2887021b2e1SHerbert Xu 	struct ip_esp_hdr *esph = (void *)(skb->data + offset);
2897021b2e1SHerbert Xu 	void *tmp = ESP_SKB_CB(skb)->tmp;
290962fcef3SHerbert Xu 	__be32 *seqhi = esp_tmp_extra(tmp);
2917021b2e1SHerbert Xu 
2927021b2e1SHerbert Xu 	esph->seq_no = esph->spi;
2937021b2e1SHerbert Xu 	esph->spi = *seqhi;
2947021b2e1SHerbert Xu }
2957021b2e1SHerbert Xu 
2967021b2e1SHerbert Xu static void esp_output_restore_header(struct sk_buff *skb)
2977021b2e1SHerbert Xu {
298962fcef3SHerbert Xu 	void *tmp = ESP_SKB_CB(skb)->tmp;
299962fcef3SHerbert Xu 	struct esp_output_extra *extra = esp_tmp_extra(tmp);
300962fcef3SHerbert Xu 
301962fcef3SHerbert Xu 	esp_restore_header(skb, skb_transport_offset(skb) + extra->esphoff -
302962fcef3SHerbert Xu 				sizeof(__be32));
3037021b2e1SHerbert Xu }
3047021b2e1SHerbert Xu 
305cac2661cSSteffen Klassert static struct ip_esp_hdr *esp_output_set_extra(struct sk_buff *skb,
306fca11ebdSSteffen Klassert 					       struct xfrm_state *x,
307cac2661cSSteffen Klassert 					       struct ip_esp_hdr *esph,
308cac2661cSSteffen Klassert 					       struct esp_output_extra *extra)
309cac2661cSSteffen Klassert {
310cac2661cSSteffen Klassert 	/* For ESN we move the header forward by 4 bytes to
311cbd801b3SLu Wei 	 * accommodate the high bits.  We will move it back after
312cac2661cSSteffen Klassert 	 * encryption.
313cac2661cSSteffen Klassert 	 */
314cac2661cSSteffen Klassert 	if ((x->props.flags & XFRM_STATE_ESN)) {
3157862b405SSteffen Klassert 		__u32 seqhi;
3167862b405SSteffen Klassert 		struct xfrm_offload *xo = xfrm_offload(skb);
3177862b405SSteffen Klassert 
3187862b405SSteffen Klassert 		if (xo)
3197862b405SSteffen Klassert 			seqhi = xo->seq.hi;
3207862b405SSteffen Klassert 		else
3217862b405SSteffen Klassert 			seqhi = XFRM_SKB_CB(skb)->seq.output.hi;
3227862b405SSteffen Klassert 
323cac2661cSSteffen Klassert 		extra->esphoff = (unsigned char *)esph -
324cac2661cSSteffen Klassert 				 skb_transport_header(skb);
325cac2661cSSteffen Klassert 		esph = (struct ip_esp_hdr *)((unsigned char *)esph - 4);
326cac2661cSSteffen Klassert 		extra->seqhi = esph->spi;
3277862b405SSteffen Klassert 		esph->seq_no = htonl(seqhi);
328cac2661cSSteffen Klassert 	}
329cac2661cSSteffen Klassert 
330cac2661cSSteffen Klassert 	esph->spi = x->id.spi;
331cac2661cSSteffen Klassert 
332cac2661cSSteffen Klassert 	return esph;
333cac2661cSSteffen Klassert }
334cac2661cSSteffen Klassert 
335*fd5dabf7SHerbert Xu static void esp_output_done_esn(void *data, int err)
3367021b2e1SHerbert Xu {
337*fd5dabf7SHerbert Xu 	struct sk_buff *skb = data;
3387021b2e1SHerbert Xu 
3397021b2e1SHerbert Xu 	esp_output_restore_header(skb);
34014d3109cSHerbert Xu 	esp_output_done(data, err);
3417021b2e1SHerbert Xu }
3427021b2e1SHerbert Xu 
343eecd227aSSabrina Dubroca static struct ip_esp_hdr *esp_output_udp_encap(struct sk_buff *skb,
344eecd227aSSabrina Dubroca 					       int encap_type,
345eecd227aSSabrina Dubroca 					       struct esp_info *esp,
346eecd227aSSabrina Dubroca 					       __be16 sport,
347eecd227aSSabrina Dubroca 					       __be16 dport)
3481da177e4SLinus Torvalds {
3491da177e4SLinus Torvalds 	struct udphdr *uh;
350d5a0a1e3SAl Viro 	__be32 *udpdata32;
3518dfb4ebaSSabrina Dubroca 	unsigned int len;
35238320c70SHerbert Xu 
353eecd227aSSabrina Dubroca 	len = skb->len + esp->tailen - skb_transport_offset(skb);
354e27cca96SSabrina Dubroca 	if (len + sizeof(struct iphdr) > IP_MAX_MTU)
355eecd227aSSabrina Dubroca 		return ERR_PTR(-EMSGSIZE);
356eecd227aSSabrina Dubroca 
357eecd227aSSabrina Dubroca 	uh = (struct udphdr *)esp->esph;
358eecd227aSSabrina Dubroca 	uh->source = sport;
359eecd227aSSabrina Dubroca 	uh->dest = dport;
360eecd227aSSabrina Dubroca 	uh->len = htons(len);
361eecd227aSSabrina Dubroca 	uh->check = 0;
362eecd227aSSabrina Dubroca 
363eecd227aSSabrina Dubroca 	*skb_mac_header(skb) = IPPROTO_UDP;
364eecd227aSSabrina Dubroca 
365eecd227aSSabrina Dubroca 	if (encap_type == UDP_ENCAP_ESPINUDP_NON_IKE) {
366eecd227aSSabrina Dubroca 		udpdata32 = (__be32 *)(uh + 1);
367eecd227aSSabrina Dubroca 		udpdata32[0] = udpdata32[1] = 0;
368eecd227aSSabrina Dubroca 		return (struct ip_esp_hdr *)(udpdata32 + 2);
369eecd227aSSabrina Dubroca 	}
370eecd227aSSabrina Dubroca 
371eecd227aSSabrina Dubroca 	return (struct ip_esp_hdr *)(uh + 1);
372eecd227aSSabrina Dubroca }
373eecd227aSSabrina Dubroca 
374e27cca96SSabrina Dubroca #ifdef CONFIG_INET_ESPINTCP
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
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 
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:
4261da177e4SLinus Torvalds 	case UDP_ENCAP_ESPINUDP_NON_IKE:
427eecd227aSSabrina Dubroca 		esph = esp_output_udp_encap(skb, encap_type, esp, sport, dport);
4281da177e4SLinus Torvalds 		break;
429e27cca96SSabrina Dubroca 	case TCP_ENCAP_ESPINTCP:
430e27cca96SSabrina Dubroca 		esph = esp_output_tcp_encap(x, skb, esp);
431e27cca96SSabrina Dubroca 		break;
4321da177e4SLinus Torvalds 	}
4331da177e4SLinus Torvalds 
434eecd227aSSabrina Dubroca 	if (IS_ERR(esph))
435eecd227aSSabrina Dubroca 		return PTR_ERR(esph);
436eecd227aSSabrina Dubroca 
437fca11ebdSSteffen Klassert 	esp->esph = esph;
4388dfb4ebaSSabrina Dubroca 
4398dfb4ebaSSabrina Dubroca 	return 0;
44037fedd3aSHerbert Xu }
4411da177e4SLinus Torvalds 
442fca11ebdSSteffen Klassert int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *esp)
443fca11ebdSSteffen Klassert {
444fca11ebdSSteffen Klassert 	u8 *tail;
445fca11ebdSSteffen Klassert 	int nfrags;
4460e78a873SSteffen Klassert 	int esph_offset;
447fca11ebdSSteffen Klassert 	struct page *page;
448fca11ebdSSteffen Klassert 	struct sk_buff *trailer;
449fca11ebdSSteffen Klassert 	int tailen = esp->tailen;
450fca11ebdSSteffen Klassert 
451e27cca96SSabrina Dubroca 	/* this is non-NULL only with TCP/UDP Encapsulation */
4528dfb4ebaSSabrina Dubroca 	if (x->encap) {
453eecd227aSSabrina Dubroca 		int err = esp_output_encap(x, skb, esp);
4548dfb4ebaSSabrina Dubroca 
4558dfb4ebaSSabrina Dubroca 		if (err < 0)
4568dfb4ebaSSabrina Dubroca 			return err;
4578dfb4ebaSSabrina Dubroca 	}
458fca11ebdSSteffen Klassert 
4595bd8baabSSabrina Dubroca 	if (ALIGN(tailen, L1_CACHE_BYTES) > PAGE_SIZE ||
4605bd8baabSSabrina Dubroca 	    ALIGN(skb->data_len, L1_CACHE_BYTES) > PAGE_SIZE)
461ebe48d36SSteffen Klassert 		goto cow;
462ebe48d36SSteffen Klassert 
463cac2661cSSteffen Klassert 	if (!skb_cloned(skb)) {
46454ffd790SSteffen Klassert 		if (tailen <= skb_tailroom(skb)) {
465cac2661cSSteffen Klassert 			nfrags = 1;
466cac2661cSSteffen Klassert 			trailer = skb;
467cac2661cSSteffen Klassert 			tail = skb_tail_pointer(trailer);
4681da177e4SLinus Torvalds 
469cac2661cSSteffen Klassert 			goto skip_cow;
470cac2661cSSteffen Klassert 		} else if ((skb_shinfo(skb)->nr_frags < MAX_SKB_FRAGS)
471cac2661cSSteffen Klassert 			   && !skb_has_frag_list(skb)) {
472cac2661cSSteffen Klassert 			int allocsize;
473cac2661cSSteffen Klassert 			struct sock *sk = skb->sk;
474cac2661cSSteffen Klassert 			struct page_frag *pfrag = &x->xfrag;
4757021b2e1SHerbert Xu 
476fca11ebdSSteffen Klassert 			esp->inplace = false;
477fca11ebdSSteffen Klassert 
478cac2661cSSteffen Klassert 			allocsize = ALIGN(tailen, L1_CACHE_BYTES);
479cac2661cSSteffen Klassert 
480cac2661cSSteffen Klassert 			spin_lock_bh(&x->lock);
481cac2661cSSteffen Klassert 
482cac2661cSSteffen Klassert 			if (unlikely(!skb_page_frag_refill(allocsize, pfrag, GFP_ATOMIC))) {
483cac2661cSSteffen Klassert 				spin_unlock_bh(&x->lock);
484cac2661cSSteffen Klassert 				goto cow;
4857021b2e1SHerbert Xu 			}
4867021b2e1SHerbert Xu 
487cac2661cSSteffen Klassert 			page = pfrag->page;
488cac2661cSSteffen Klassert 			get_page(page);
489cac2661cSSteffen Klassert 
4909bd6b629SWillem de Bruijn 			tail = page_address(page) + pfrag->offset;
491cac2661cSSteffen Klassert 
492fca11ebdSSteffen Klassert 			esp_output_fill_trailer(tail, esp->tfclen, esp->plen, esp->proto);
493cac2661cSSteffen Klassert 
494cac2661cSSteffen Klassert 			nfrags = skb_shinfo(skb)->nr_frags;
495cac2661cSSteffen Klassert 
496cac2661cSSteffen Klassert 			__skb_fill_page_desc(skb, nfrags, page, pfrag->offset,
497cac2661cSSteffen Klassert 					     tailen);
498cac2661cSSteffen Klassert 			skb_shinfo(skb)->nr_frags = ++nfrags;
499cac2661cSSteffen Klassert 
500cac2661cSSteffen Klassert 			pfrag->offset = pfrag->offset + allocsize;
50136ff0dd3SSteffen Klassert 
50236ff0dd3SSteffen Klassert 			spin_unlock_bh(&x->lock);
50336ff0dd3SSteffen Klassert 
504cac2661cSSteffen Klassert 			nfrags++;
505cac2661cSSteffen Klassert 
506ede57d58SRichard Gobert 			skb_len_add(skb, tailen);
50709db5124SMartin Willi 			if (sk && sk_fullsock(sk))
50814afee4bSReshetova, Elena 				refcount_add(tailen, &sk->sk_wmem_alloc);
509cac2661cSSteffen Klassert 
510fca11ebdSSteffen Klassert 			goto out;
511fca11ebdSSteffen Klassert 		}
512fca11ebdSSteffen Klassert 	}
513cac2661cSSteffen Klassert 
514fca11ebdSSteffen Klassert cow:
5150e78a873SSteffen Klassert 	esph_offset = (unsigned char *)esp->esph - skb_transport_header(skb);
5160e78a873SSteffen Klassert 
517fca11ebdSSteffen Klassert 	nfrags = skb_cow_data(skb, tailen, &trailer);
518fca11ebdSSteffen Klassert 	if (nfrags < 0)
519fca11ebdSSteffen Klassert 		goto out;
520fca11ebdSSteffen Klassert 	tail = skb_tail_pointer(trailer);
5210e78a873SSteffen Klassert 	esp->esph = (struct ip_esp_hdr *)(skb_transport_header(skb) + esph_offset);
5227021b2e1SHerbert Xu 
523fca11ebdSSteffen Klassert skip_cow:
524fca11ebdSSteffen Klassert 	esp_output_fill_trailer(tail, esp->tfclen, esp->plen, esp->proto);
525fca11ebdSSteffen Klassert 	pskb_put(skb, trailer, tailen);
526fca11ebdSSteffen Klassert 
527fca11ebdSSteffen Klassert out:
528fca11ebdSSteffen Klassert 	return nfrags;
529fca11ebdSSteffen Klassert }
530fca11ebdSSteffen Klassert EXPORT_SYMBOL_GPL(esp_output_head);
531fca11ebdSSteffen Klassert 
532fca11ebdSSteffen Klassert int esp_output_tail(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *esp)
533fca11ebdSSteffen Klassert {
534fca11ebdSSteffen Klassert 	u8 *iv;
535fca11ebdSSteffen Klassert 	int alen;
536fca11ebdSSteffen Klassert 	void *tmp;
537fca11ebdSSteffen Klassert 	int ivlen;
538fca11ebdSSteffen Klassert 	int assoclen;
539fca11ebdSSteffen Klassert 	int extralen;
540fca11ebdSSteffen Klassert 	struct page *page;
541fca11ebdSSteffen Klassert 	struct ip_esp_hdr *esph;
542fca11ebdSSteffen Klassert 	struct crypto_aead *aead;
543fca11ebdSSteffen Klassert 	struct aead_request *req;
544fca11ebdSSteffen Klassert 	struct scatterlist *sg, *dsg;
545fca11ebdSSteffen Klassert 	struct esp_output_extra *extra;
546fca11ebdSSteffen Klassert 	int err = -ENOMEM;
547fca11ebdSSteffen Klassert 
548fca11ebdSSteffen Klassert 	assoclen = sizeof(struct ip_esp_hdr);
549fca11ebdSSteffen Klassert 	extralen = 0;
550fca11ebdSSteffen Klassert 
551fca11ebdSSteffen Klassert 	if (x->props.flags & XFRM_STATE_ESN) {
552fca11ebdSSteffen Klassert 		extralen += sizeof(*extra);
553fca11ebdSSteffen Klassert 		assoclen += sizeof(__be32);
554fca11ebdSSteffen Klassert 	}
555fca11ebdSSteffen Klassert 
556fca11ebdSSteffen Klassert 	aead = x->data;
557fca11ebdSSteffen Klassert 	alen = crypto_aead_authsize(aead);
558fca11ebdSSteffen Klassert 	ivlen = crypto_aead_ivsize(aead);
559fca11ebdSSteffen Klassert 
560fca11ebdSSteffen Klassert 	tmp = esp_alloc_tmp(aead, esp->nfrags + 2, extralen);
561e892d2d4SSteffen Klassert 	if (!tmp)
562cac2661cSSteffen Klassert 		goto error;
563cac2661cSSteffen Klassert 
564cac2661cSSteffen Klassert 	extra = esp_tmp_extra(tmp);
565cac2661cSSteffen Klassert 	iv = esp_tmp_iv(aead, tmp, extralen);
566cac2661cSSteffen Klassert 	req = esp_tmp_req(aead, iv);
567cac2661cSSteffen Klassert 	sg = esp_req_sg(aead, req);
568cac2661cSSteffen Klassert 
569fca11ebdSSteffen Klassert 	if (esp->inplace)
570fca11ebdSSteffen Klassert 		dsg = sg;
571fca11ebdSSteffen Klassert 	else
572fca11ebdSSteffen Klassert 		dsg = &sg[esp->nfrags];
573cac2661cSSteffen Klassert 
574fca11ebdSSteffen Klassert 	esph = esp_output_set_extra(skb, x, esp->esph, extra);
575fca11ebdSSteffen Klassert 	esp->esph = esph;
576fca11ebdSSteffen Klassert 
577fca11ebdSSteffen Klassert 	sg_init_table(sg, esp->nfrags);
5783f297707SJason A. Donenfeld 	err = skb_to_sgvec(skb, sg,
5797021b2e1SHerbert Xu 		           (unsigned char *)esph - skb->data,
580fca11ebdSSteffen Klassert 		           assoclen + ivlen + esp->clen + alen);
5813f297707SJason A. Donenfeld 	if (unlikely(err < 0))
582e6194923SSteffen Klassert 		goto error_free;
583fca11ebdSSteffen Klassert 
584fca11ebdSSteffen Klassert 	if (!esp->inplace) {
585fca11ebdSSteffen Klassert 		int allocsize;
586fca11ebdSSteffen Klassert 		struct page_frag *pfrag = &x->xfrag;
5870dc49e9bSSteffen Klassert 
588cac2661cSSteffen Klassert 		allocsize = ALIGN(skb->data_len, L1_CACHE_BYTES);
589cac2661cSSteffen Klassert 
590fca11ebdSSteffen Klassert 		spin_lock_bh(&x->lock);
591cac2661cSSteffen Klassert 		if (unlikely(!skb_page_frag_refill(allocsize, pfrag, GFP_ATOMIC))) {
592cac2661cSSteffen Klassert 			spin_unlock_bh(&x->lock);
593e6194923SSteffen Klassert 			goto error_free;
594cac2661cSSteffen Klassert 		}
595cac2661cSSteffen Klassert 
596cac2661cSSteffen Klassert 		skb_shinfo(skb)->nr_frags = 1;
597cac2661cSSteffen Klassert 
598cac2661cSSteffen Klassert 		page = pfrag->page;
599cac2661cSSteffen Klassert 		get_page(page);
600cac2661cSSteffen Klassert 		/* replace page frags in skb with new page */
601cac2661cSSteffen Klassert 		__skb_fill_page_desc(skb, 0, page, pfrag->offset, skb->data_len);
602cac2661cSSteffen Klassert 		pfrag->offset = pfrag->offset + allocsize;
603fca11ebdSSteffen Klassert 		spin_unlock_bh(&x->lock);
604cac2661cSSteffen Klassert 
605cac2661cSSteffen Klassert 		sg_init_table(dsg, skb_shinfo(skb)->nr_frags + 1);
6063f297707SJason A. Donenfeld 		err = skb_to_sgvec(skb, dsg,
607cac2661cSSteffen Klassert 			           (unsigned char *)esph - skb->data,
608fca11ebdSSteffen Klassert 			           assoclen + ivlen + esp->clen + alen);
6093f297707SJason A. Donenfeld 		if (unlikely(err < 0))
610e6194923SSteffen Klassert 			goto error_free;
611cac2661cSSteffen Klassert 	}
612cac2661cSSteffen Klassert 
613cac2661cSSteffen Klassert 	if ((x->props.flags & XFRM_STATE_ESN))
614cac2661cSSteffen Klassert 		aead_request_set_callback(req, 0, esp_output_done_esn, skb);
615cac2661cSSteffen Klassert 	else
616cac2661cSSteffen Klassert 		aead_request_set_callback(req, 0, esp_output_done, skb);
617cac2661cSSteffen Klassert 
618fca11ebdSSteffen Klassert 	aead_request_set_crypt(req, sg, dsg, ivlen + esp->clen, iv);
6197021b2e1SHerbert Xu 	aead_request_set_ad(req, assoclen);
6201da177e4SLinus Torvalds 
6217021b2e1SHerbert Xu 	memset(iv, 0, ivlen);
622fca11ebdSSteffen Klassert 	memcpy(iv + ivlen - min(ivlen, 8), (u8 *)&esp->seqno + 8 - min(ivlen, 8),
6237021b2e1SHerbert Xu 	       min(ivlen, 8));
6246b7326c8SHerbert Xu 
62538320c70SHerbert Xu 	ESP_SKB_CB(skb)->tmp = tmp;
6267021b2e1SHerbert Xu 	err = crypto_aead_encrypt(req);
6277021b2e1SHerbert Xu 
6287021b2e1SHerbert Xu 	switch (err) {
6297021b2e1SHerbert Xu 	case -EINPROGRESS:
63038320c70SHerbert Xu 		goto error;
6311da177e4SLinus Torvalds 
632068c2e70SGilad Ben-Yossef 	case -ENOSPC:
63338320c70SHerbert Xu 		err = NET_XMIT_DROP;
6347021b2e1SHerbert Xu 		break;
6357021b2e1SHerbert Xu 
6367021b2e1SHerbert Xu 	case 0:
6377021b2e1SHerbert Xu 		if ((x->props.flags & XFRM_STATE_ESN))
6387021b2e1SHerbert Xu 			esp_output_restore_header(skb);
6397021b2e1SHerbert Xu 	}
6401da177e4SLinus Torvalds 
641cac2661cSSteffen Klassert 	if (sg != dsg)
642cac2661cSSteffen Klassert 		esp_ssg_unref(x, tmp);
643b7c6538cSHerbert Xu 
644e27cca96SSabrina Dubroca 	if (!err && x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP)
645e27cca96SSabrina Dubroca 		err = esp_output_tail_tcp(x, skb);
646e27cca96SSabrina Dubroca 
647e6194923SSteffen Klassert error_free:
648e6194923SSteffen Klassert 	kfree(tmp);
6491da177e4SLinus Torvalds error:
6501da177e4SLinus Torvalds 	return err;
6511da177e4SLinus Torvalds }
652fca11ebdSSteffen Klassert EXPORT_SYMBOL_GPL(esp_output_tail);
6531da177e4SLinus Torvalds 
654fca11ebdSSteffen Klassert static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
655fca11ebdSSteffen Klassert {
656fca11ebdSSteffen Klassert 	int alen;
657fca11ebdSSteffen Klassert 	int blksize;
658fca11ebdSSteffen Klassert 	struct ip_esp_hdr *esph;
659fca11ebdSSteffen Klassert 	struct crypto_aead *aead;
660fca11ebdSSteffen Klassert 	struct esp_info esp;
661fca11ebdSSteffen Klassert 
662fca11ebdSSteffen Klassert 	esp.inplace = true;
663fca11ebdSSteffen Klassert 
664fca11ebdSSteffen Klassert 	esp.proto = *skb_mac_header(skb);
665fca11ebdSSteffen Klassert 	*skb_mac_header(skb) = IPPROTO_ESP;
666fca11ebdSSteffen Klassert 
667fca11ebdSSteffen Klassert 	/* skb is pure payload to encrypt */
668fca11ebdSSteffen Klassert 
669fca11ebdSSteffen Klassert 	aead = x->data;
670fca11ebdSSteffen Klassert 	alen = crypto_aead_authsize(aead);
671fca11ebdSSteffen Klassert 
672fca11ebdSSteffen Klassert 	esp.tfclen = 0;
673fca11ebdSSteffen Klassert 	if (x->tfcpad) {
674fca11ebdSSteffen Klassert 		struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb);
675fca11ebdSSteffen Klassert 		u32 padto;
676fca11ebdSSteffen Klassert 
677a6d95c5aSJiri Bohac 		padto = min(x->tfcpad, xfrm_state_mtu(x, dst->child_mtu_cached));
678fca11ebdSSteffen Klassert 		if (skb->len < padto)
679fca11ebdSSteffen Klassert 			esp.tfclen = padto - skb->len;
680fca11ebdSSteffen Klassert 	}
681fca11ebdSSteffen Klassert 	blksize = ALIGN(crypto_aead_blocksize(aead), 4);
682fca11ebdSSteffen Klassert 	esp.clen = ALIGN(skb->len + 2 + esp.tfclen, blksize);
683fca11ebdSSteffen Klassert 	esp.plen = esp.clen - skb->len - esp.tfclen;
684fca11ebdSSteffen Klassert 	esp.tailen = esp.tfclen + esp.plen + alen;
685fca11ebdSSteffen Klassert 
686fca11ebdSSteffen Klassert 	esp.esph = ip_esp_hdr(skb);
687fca11ebdSSteffen Klassert 
688fca11ebdSSteffen Klassert 	esp.nfrags = esp_output_head(x, skb, &esp);
689fca11ebdSSteffen Klassert 	if (esp.nfrags < 0)
690fca11ebdSSteffen Klassert 		return esp.nfrags;
691fca11ebdSSteffen Klassert 
692fca11ebdSSteffen Klassert 	esph = esp.esph;
693fca11ebdSSteffen Klassert 	esph->spi = x->id.spi;
694fca11ebdSSteffen Klassert 
695fca11ebdSSteffen Klassert 	esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low);
696fca11ebdSSteffen Klassert 	esp.seqno = cpu_to_be64(XFRM_SKB_CB(skb)->seq.output.low +
697fca11ebdSSteffen Klassert 				 ((u64)XFRM_SKB_CB(skb)->seq.output.hi << 32));
698fca11ebdSSteffen Klassert 
699fca11ebdSSteffen Klassert 	skb_push(skb, -skb_network_offset(skb));
700fca11ebdSSteffen Klassert 
701fca11ebdSSteffen Klassert 	return esp_output_tail(x, skb, &esp);
702fca11ebdSSteffen Klassert }
703fca11ebdSSteffen Klassert 
70447ebcc0bSYossi Kuperman static inline int esp_remove_trailer(struct sk_buff *skb)
70547ebcc0bSYossi Kuperman {
70647ebcc0bSYossi Kuperman 	struct xfrm_state *x = xfrm_input_state(skb);
70747ebcc0bSYossi Kuperman 	struct crypto_aead *aead = x->data;
70847ebcc0bSYossi Kuperman 	int alen, hlen, elen;
70947ebcc0bSYossi Kuperman 	int padlen, trimlen;
71047ebcc0bSYossi Kuperman 	__wsum csumdiff;
71147ebcc0bSYossi Kuperman 	u8 nexthdr[2];
71247ebcc0bSYossi Kuperman 	int ret;
71347ebcc0bSYossi Kuperman 
71447ebcc0bSYossi Kuperman 	alen = crypto_aead_authsize(aead);
71547ebcc0bSYossi Kuperman 	hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead);
71647ebcc0bSYossi Kuperman 	elen = skb->len - hlen;
71747ebcc0bSYossi Kuperman 
71847ebcc0bSYossi Kuperman 	if (skb_copy_bits(skb, skb->len - alen - 2, nexthdr, 2))
71947ebcc0bSYossi Kuperman 		BUG();
72047ebcc0bSYossi Kuperman 
72147ebcc0bSYossi Kuperman 	ret = -EINVAL;
72247ebcc0bSYossi Kuperman 	padlen = nexthdr[0];
72347ebcc0bSYossi Kuperman 	if (padlen + 2 + alen >= elen) {
72447ebcc0bSYossi Kuperman 		net_dbg_ratelimited("ipsec esp packet is garbage padlen=%d, elen=%d\n",
72547ebcc0bSYossi Kuperman 				    padlen + 2, elen - alen);
72647ebcc0bSYossi Kuperman 		goto out;
72747ebcc0bSYossi Kuperman 	}
72847ebcc0bSYossi Kuperman 
72947ebcc0bSYossi Kuperman 	trimlen = alen + padlen + 2;
73047ebcc0bSYossi Kuperman 	if (skb->ip_summed == CHECKSUM_COMPLETE) {
73147ebcc0bSYossi Kuperman 		csumdiff = skb_checksum(skb, skb->len - trimlen, trimlen, 0);
73247ebcc0bSYossi Kuperman 		skb->csum = csum_block_sub(skb->csum, csumdiff,
73347ebcc0bSYossi Kuperman 					   skb->len - trimlen);
73447ebcc0bSYossi Kuperman 	}
73547ebcc0bSYossi Kuperman 	pskb_trim(skb, skb->len - trimlen);
73647ebcc0bSYossi Kuperman 
73747ebcc0bSYossi Kuperman 	ret = nexthdr[1];
73847ebcc0bSYossi Kuperman 
73947ebcc0bSYossi Kuperman out:
74047ebcc0bSYossi Kuperman 	return ret;
74147ebcc0bSYossi Kuperman }
74247ebcc0bSYossi Kuperman 
743fca11ebdSSteffen Klassert int esp_input_done2(struct sk_buff *skb, int err)
7441da177e4SLinus Torvalds {
745b71d1d42SEric Dumazet 	const struct iphdr *iph;
74638320c70SHerbert Xu 	struct xfrm_state *x = xfrm_input_state(skb);
747d77e38e6SSteffen Klassert 	struct xfrm_offload *xo = xfrm_offload(skb);
7481c5ad13fSMathias Krause 	struct crypto_aead *aead = x->data;
74938320c70SHerbert Xu 	int hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead);
75031a4ab93SHerbert Xu 	int ihl;
7511da177e4SLinus Torvalds 
7521d9bfacdSJiapeng Chong 	if (!xo || !(xo->flags & CRYPTO_DONE))
75338320c70SHerbert Xu 		kfree(ESP_SKB_CB(skb)->tmp);
7540ebea8efSHerbert Xu 
7556b7326c8SHerbert Xu 	if (unlikely(err))
756668dc8afSHerbert Xu 		goto out;
7571da177e4SLinus Torvalds 
75847ebcc0bSYossi Kuperman 	err = esp_remove_trailer(skb);
75947ebcc0bSYossi Kuperman 	if (unlikely(err < 0))
7601da177e4SLinus Torvalds 		goto out;
7611da177e4SLinus Torvalds 
762eddc9ec5SArnaldo Carvalho de Melo 	iph = ip_hdr(skb);
76331a4ab93SHerbert Xu 	ihl = iph->ihl * 4;
76431a4ab93SHerbert Xu 
7651da177e4SLinus Torvalds 	if (x->encap) {
766752c1f4cSHerbert Xu 		struct xfrm_encap_tmpl *encap = x->encap;
767e27cca96SSabrina Dubroca 		struct tcphdr *th = (void *)(skb_network_header(skb) + ihl);
768d56f90a7SArnaldo Carvalho de Melo 		struct udphdr *uh = (void *)(skb_network_header(skb) + ihl);
76925f6802bSSabrina Dubroca 		__be16 source;
77025f6802bSSabrina Dubroca 
77125f6802bSSabrina Dubroca 		switch (x->encap->encap_type) {
772e27cca96SSabrina Dubroca 		case TCP_ENCAP_ESPINTCP:
773e27cca96SSabrina Dubroca 			source = th->source;
774e27cca96SSabrina Dubroca 			break;
77525f6802bSSabrina Dubroca 		case UDP_ENCAP_ESPINUDP:
77625f6802bSSabrina Dubroca 		case UDP_ENCAP_ESPINUDP_NON_IKE:
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
7871da177e4SLinus Torvalds 		 *    advertize 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 
833*fd5dabf7SHerbert Xu static void esp_input_done(void *data, int err)
83438320c70SHerbert Xu {
835*fd5dabf7SHerbert Xu 	struct sk_buff *skb = data;
83638320c70SHerbert Xu 
83738320c70SHerbert Xu 	xfrm_input_resume(skb, esp_input_done2(skb, err));
83838320c70SHerbert Xu }
83938320c70SHerbert Xu 
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 
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 
863*fd5dabf7SHerbert Xu static void esp_input_done_esn(void *data, int err)
8647021b2e1SHerbert Xu {
865*fd5dabf7SHerbert 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  */
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 
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 
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 
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 
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:
113538320c70SHerbert Xu 	kfree(key);
113638320c70SHerbert Xu 
11371a6509d9SHerbert Xu error:
11381a6509d9SHerbert Xu 	return err;
11391a6509d9SHerbert Xu }
11401a6509d9SHerbert Xu 
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;
11801da177e4SLinus Torvalds 		case UDP_ENCAP_ESPINUDP_NON_IKE:
11811da177e4SLinus Torvalds 			x->props.header_len += sizeof(struct udphdr) + 2 * sizeof(u32);
11821da177e4SLinus Torvalds 			break;
1183e27cca96SSabrina Dubroca #ifdef CONFIG_INET_ESPINTCP
1184e27cca96SSabrina Dubroca 		case TCP_ENCAP_ESPINTCP:
1185e27cca96SSabrina Dubroca 			/* only the length field, TCP encap is done by
1186e27cca96SSabrina Dubroca 			 * the socket
1187e27cca96SSabrina Dubroca 			 */
1188e27cca96SSabrina Dubroca 			x->props.header_len += 2;
1189e27cca96SSabrina Dubroca 			break;
1190e27cca96SSabrina Dubroca #endif
11911da177e4SLinus Torvalds 		}
11921da177e4SLinus Torvalds 	}
119338320c70SHerbert Xu 
119438320c70SHerbert Xu 	align = ALIGN(crypto_aead_blocksize(aead), 4);
11951c5ad13fSMathias Krause 	x->props.trailer_len = align + 1 + crypto_aead_authsize(aead);
11961da177e4SLinus Torvalds 
11971da177e4SLinus Torvalds error:
119838320c70SHerbert Xu 	return err;
11991da177e4SLinus Torvalds }
12001da177e4SLinus Torvalds 
1201827789cbSSteffen Klassert static int esp4_rcv_cb(struct sk_buff *skb, int err)
1202827789cbSSteffen Klassert {
1203827789cbSSteffen Klassert 	return 0;
1204827789cbSSteffen Klassert }
1205827789cbSSteffen Klassert 
1206533cb5b0SEric Dumazet static const struct xfrm_type esp_type =
12071da177e4SLinus Torvalds {
12081da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
12091da177e4SLinus Torvalds 	.proto	     	= IPPROTO_ESP,
1210436a0a40SHerbert Xu 	.flags		= XFRM_TYPE_REPLAY_PROT,
12111da177e4SLinus Torvalds 	.init_state	= esp_init_state,
12121da177e4SLinus Torvalds 	.destructor	= esp_destroy,
12131da177e4SLinus Torvalds 	.input		= esp_input,
1214fca11ebdSSteffen Klassert 	.output		= esp_output,
12151da177e4SLinus Torvalds };
12161da177e4SLinus Torvalds 
1217827789cbSSteffen Klassert static struct xfrm4_protocol esp4_protocol = {
12181da177e4SLinus Torvalds 	.handler	=	xfrm4_rcv,
1219827789cbSSteffen Klassert 	.input_handler	=	xfrm_input,
1220827789cbSSteffen Klassert 	.cb_handler	=	esp4_rcv_cb,
12211da177e4SLinus Torvalds 	.err_handler	=	esp4_err,
1222827789cbSSteffen Klassert 	.priority	=	0,
12231da177e4SLinus Torvalds };
12241da177e4SLinus Torvalds 
12251da177e4SLinus Torvalds static int __init esp4_init(void)
12261da177e4SLinus Torvalds {
12271da177e4SLinus Torvalds 	if (xfrm_register_type(&esp_type, AF_INET) < 0) {
1228058bd4d2SJoe Perches 		pr_info("%s: can't add xfrm type\n", __func__);
12291da177e4SLinus Torvalds 		return -EAGAIN;
12301da177e4SLinus Torvalds 	}
1231827789cbSSteffen Klassert 	if (xfrm4_protocol_register(&esp4_protocol, IPPROTO_ESP) < 0) {
1232058bd4d2SJoe Perches 		pr_info("%s: can't add protocol\n", __func__);
12331da177e4SLinus Torvalds 		xfrm_unregister_type(&esp_type, AF_INET);
12341da177e4SLinus Torvalds 		return -EAGAIN;
12351da177e4SLinus Torvalds 	}
12361da177e4SLinus Torvalds 	return 0;
12371da177e4SLinus Torvalds }
12381da177e4SLinus Torvalds 
12391da177e4SLinus Torvalds static void __exit esp4_fini(void)
12401da177e4SLinus Torvalds {
1241827789cbSSteffen Klassert 	if (xfrm4_protocol_deregister(&esp4_protocol, IPPROTO_ESP) < 0)
1242058bd4d2SJoe Perches 		pr_info("%s: can't remove protocol\n", __func__);
12434f518e80SFlorian Westphal 	xfrm_unregister_type(&esp_type, AF_INET);
12441da177e4SLinus Torvalds }
12451da177e4SLinus Torvalds 
12461da177e4SLinus Torvalds module_init(esp4_init);
12471da177e4SLinus Torvalds module_exit(esp4_fini);
12481da177e4SLinus Torvalds MODULE_LICENSE("GPL");
1249d3d6dd3aSMasahide NAKAMURA MODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_ESP);
1250