xref: /linux/net/ipv4/esp4.c (revision aeb48a42)
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 #include <linux/skbuff_ref.h>
24cac2661cSSteffen Klassert 
25cac2661cSSteffen Klassert #include <linux/highmem.h>
2638320c70SHerbert Xu 
2738320c70SHerbert Xu struct esp_skb_cb {
2838320c70SHerbert Xu 	struct xfrm_skb_cb xfrm;
2938320c70SHerbert Xu 	void *tmp;
3038320c70SHerbert Xu };
31962fcef3SHerbert Xu 
32962fcef3SHerbert Xu struct esp_output_extra {
33962fcef3SHerbert Xu 	__be32 seqhi;
34962fcef3SHerbert Xu 	u32 esphoff;
35962fcef3SHerbert Xu };
3638320c70SHerbert 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.
46962fcef3SHerbert Xu  */
esp_alloc_tmp(struct crypto_aead * aead,int nfrags,int extralen)4738320c70SHerbert Xu static void *esp_alloc_tmp(struct crypto_aead *aead, int nfrags, int extralen)
4838320c70SHerbert Xu {
4938320c70SHerbert Xu 	unsigned int len;
50962fcef3SHerbert Xu 
510dc49e9bSSteffen Klassert 	len = extralen;
520dc49e9bSSteffen Klassert 
530dc49e9bSSteffen Klassert 	len += crypto_aead_ivsize(aead);
5438320c70SHerbert Xu 
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 	}
607021b2e1SHerbert Xu 
6138320c70SHerbert 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 }
68962fcef3SHerbert Xu 
esp_tmp_extra(void * tmp)690dc49e9bSSteffen Klassert static inline void *esp_tmp_extra(void *tmp)
70962fcef3SHerbert Xu {
710dc49e9bSSteffen Klassert 	return PTR_ALIGN(tmp, __alignof__(struct esp_output_extra));
72962fcef3SHerbert Xu }
73962fcef3SHerbert Xu 
esp_tmp_iv(struct crypto_aead * aead,void * tmp,int extralen)7438320c70SHerbert Xu static inline u8 *esp_tmp_iv(struct crypto_aead *aead, void *tmp, int extralen)
7538320c70SHerbert Xu {
76962fcef3SHerbert Xu 	return crypto_aead_ivsize(aead) ?
77962fcef3SHerbert Xu 	       PTR_ALIGN((u8 *)tmp + extralen,
7838320c70SHerbert 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 }
98c3198822SDragos Tatulea 
esp_ssg_unref(struct xfrm_state * x,void * tmp,struct sk_buff * skb)99cac2661cSSteffen Klassert 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 
107f8fdadefSCorey Minyard 	if (x->props.flags & XFRM_STATE_ESN)
108cac2661cSSteffen Klassert 		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)
117*4a96a4e8SAlexander Lobakin 		for (sg = sg_next(req->src); sg; sg = sg_next(sg))
118cac2661cSSteffen Klassert 			skb_page_unref(sg_page(sg), skb->pp_recycle);
119cac2661cSSteffen Klassert }
120e27cca96SSabrina Dubroca 
121e27cca96SSabrina Dubroca #ifdef CONFIG_INET_ESPINTCP
122e27cca96SSabrina Dubroca struct esp_tcp_sk {
123e27cca96SSabrina Dubroca 	struct sock *sk;
124e27cca96SSabrina Dubroca 	struct rcu_head rcu;
125e27cca96SSabrina Dubroca };
126e27cca96SSabrina Dubroca 
esp_free_tcp_sk(struct rcu_head * head)127e27cca96SSabrina Dubroca static void esp_free_tcp_sk(struct rcu_head *head)
128e27cca96SSabrina Dubroca {
129e27cca96SSabrina Dubroca 	struct esp_tcp_sk *esk = container_of(head, struct esp_tcp_sk, rcu);
130e27cca96SSabrina Dubroca 
131e27cca96SSabrina Dubroca 	sock_put(esk->sk);
132e27cca96SSabrina Dubroca 	kfree(esk);
133e27cca96SSabrina Dubroca }
134e27cca96SSabrina Dubroca 
esp_find_tcp_sk(struct xfrm_state * x)135e27cca96SSabrina Dubroca static struct sock *esp_find_tcp_sk(struct xfrm_state *x)
136e27cca96SSabrina Dubroca {
1374461568aSKuniyuki Iwashima 	struct xfrm_encap_tmpl *encap = x->encap;
138e27cca96SSabrina Dubroca 	struct net *net = xs_net(x);
139e27cca96SSabrina Dubroca 	struct esp_tcp_sk *esk;
140e27cca96SSabrina Dubroca 	__be16 sport, dport;
141e27cca96SSabrina Dubroca 	struct sock *nsk;
142e27cca96SSabrina Dubroca 	struct sock *sk;
143e27cca96SSabrina Dubroca 
144e27cca96SSabrina Dubroca 	sk = rcu_dereference(x->encap_sk);
145e27cca96SSabrina Dubroca 	if (sk && sk->sk_state == TCP_ESTABLISHED)
146e27cca96SSabrina Dubroca 		return sk;
147e27cca96SSabrina Dubroca 
148e27cca96SSabrina Dubroca 	spin_lock_bh(&x->lock);
149e27cca96SSabrina Dubroca 	sport = encap->encap_sport;
150e27cca96SSabrina Dubroca 	dport = encap->encap_dport;
151e27cca96SSabrina Dubroca 	nsk = rcu_dereference_protected(x->encap_sk,
152e27cca96SSabrina Dubroca 					lockdep_is_held(&x->lock));
153e27cca96SSabrina Dubroca 	if (sk && sk == nsk) {
154e27cca96SSabrina Dubroca 		esk = kmalloc(sizeof(*esk), GFP_ATOMIC);
155e27cca96SSabrina Dubroca 		if (!esk) {
156e27cca96SSabrina Dubroca 			spin_unlock_bh(&x->lock);
157e27cca96SSabrina Dubroca 			return ERR_PTR(-ENOMEM);
158e27cca96SSabrina Dubroca 		}
159e27cca96SSabrina Dubroca 		RCU_INIT_POINTER(x->encap_sk, NULL);
160e27cca96SSabrina Dubroca 		esk->sk = sk;
161e27cca96SSabrina Dubroca 		call_rcu(&esk->rcu, esp_free_tcp_sk);
162e27cca96SSabrina Dubroca 	}
163e27cca96SSabrina Dubroca 	spin_unlock_bh(&x->lock);
1644461568aSKuniyuki Iwashima 
165e27cca96SSabrina Dubroca 	sk = inet_lookup_established(net, net->ipv4.tcp_death_row.hashinfo, x->id.daddr.a4,
166e27cca96SSabrina Dubroca 				     dport, x->props.saddr.a4, sport, 0);
167e27cca96SSabrina Dubroca 	if (!sk)
168e27cca96SSabrina Dubroca 		return ERR_PTR(-ENOENT);
169e27cca96SSabrina Dubroca 
170e27cca96SSabrina Dubroca 	if (!tcp_is_ulp_esp(sk)) {
171e27cca96SSabrina Dubroca 		sock_put(sk);
172e27cca96SSabrina Dubroca 		return ERR_PTR(-EINVAL);
173e27cca96SSabrina Dubroca 	}
174e27cca96SSabrina Dubroca 
175e27cca96SSabrina Dubroca 	spin_lock_bh(&x->lock);
176e27cca96SSabrina Dubroca 	nsk = rcu_dereference_protected(x->encap_sk,
177e27cca96SSabrina Dubroca 					lockdep_is_held(&x->lock));
178e27cca96SSabrina Dubroca 	if (encap->encap_sport != sport ||
179e27cca96SSabrina Dubroca 	    encap->encap_dport != dport) {
180e27cca96SSabrina Dubroca 		sock_put(sk);
181e27cca96SSabrina Dubroca 		sk = nsk ?: ERR_PTR(-EREMCHG);
182e27cca96SSabrina Dubroca 	} else if (sk == nsk) {
183e27cca96SSabrina Dubroca 		sock_put(sk);
184e27cca96SSabrina Dubroca 	} else {
185e27cca96SSabrina Dubroca 		rcu_assign_pointer(x->encap_sk, sk);
186e27cca96SSabrina Dubroca 	}
187e27cca96SSabrina Dubroca 	spin_unlock_bh(&x->lock);
188e27cca96SSabrina Dubroca 
189e27cca96SSabrina Dubroca 	return sk;
190e27cca96SSabrina Dubroca }
191e27cca96SSabrina Dubroca 
esp_output_tcp_finish(struct xfrm_state * x,struct sk_buff * skb)192e27cca96SSabrina Dubroca static int esp_output_tcp_finish(struct xfrm_state *x, struct sk_buff *skb)
193e27cca96SSabrina Dubroca {
194e27cca96SSabrina Dubroca 	struct sock *sk;
195e27cca96SSabrina Dubroca 	int err;
196e27cca96SSabrina Dubroca 
197e27cca96SSabrina Dubroca 	rcu_read_lock();
198e27cca96SSabrina Dubroca 
199e27cca96SSabrina Dubroca 	sk = esp_find_tcp_sk(x);
200e27cca96SSabrina Dubroca 	err = PTR_ERR_OR_ZERO(sk);
201e27cca96SSabrina Dubroca 	if (err)
202e27cca96SSabrina Dubroca 		goto out;
203e27cca96SSabrina Dubroca 
204e27cca96SSabrina Dubroca 	bh_lock_sock(sk);
205e27cca96SSabrina Dubroca 	if (sock_owned_by_user(sk))
206e27cca96SSabrina Dubroca 		err = espintcp_queue_out(sk, skb);
207e27cca96SSabrina Dubroca 	else
208e27cca96SSabrina Dubroca 		err = espintcp_push_skb(sk, skb);
209e27cca96SSabrina Dubroca 	bh_unlock_sock(sk);
210e27cca96SSabrina Dubroca 
211e27cca96SSabrina Dubroca out:
212e27cca96SSabrina Dubroca 	rcu_read_unlock();
213e27cca96SSabrina Dubroca 	return err;
214e27cca96SSabrina Dubroca }
215e27cca96SSabrina Dubroca 
esp_output_tcp_encap_cb(struct net * net,struct sock * sk,struct sk_buff * skb)216e27cca96SSabrina Dubroca static int esp_output_tcp_encap_cb(struct net *net, struct sock *sk,
217e27cca96SSabrina Dubroca 				   struct sk_buff *skb)
218e27cca96SSabrina Dubroca {
219e27cca96SSabrina Dubroca 	struct dst_entry *dst = skb_dst(skb);
220e27cca96SSabrina Dubroca 	struct xfrm_state *x = dst->xfrm;
221e27cca96SSabrina Dubroca 
222e27cca96SSabrina Dubroca 	return esp_output_tcp_finish(x, skb);
223e27cca96SSabrina Dubroca }
224e27cca96SSabrina Dubroca 
esp_output_tail_tcp(struct xfrm_state * x,struct sk_buff * skb)225e27cca96SSabrina Dubroca static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)
226e27cca96SSabrina Dubroca {
227e27cca96SSabrina Dubroca 	int err;
228e27cca96SSabrina Dubroca 
229e27cca96SSabrina Dubroca 	local_bh_disable();
230e27cca96SSabrina Dubroca 	err = xfrm_trans_queue_net(xs_net(x), skb, esp_output_tcp_encap_cb);
231e27cca96SSabrina Dubroca 	local_bh_enable();
232e27cca96SSabrina Dubroca 
233e27cca96SSabrina Dubroca 	/* EINPROGRESS just happens to do the right thing.  It
234e27cca96SSabrina Dubroca 	 * actually means that the skb has been consumed and
235e27cca96SSabrina Dubroca 	 * isn't coming back.
236e27cca96SSabrina Dubroca 	 */
237e27cca96SSabrina Dubroca 	return err ?: -EINPROGRESS;
238e27cca96SSabrina Dubroca }
239e27cca96SSabrina Dubroca #else
esp_output_tail_tcp(struct xfrm_state * x,struct sk_buff * skb)240e27cca96SSabrina Dubroca static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb)
241e27cca96SSabrina Dubroca {
242e27cca96SSabrina Dubroca 	kfree_skb(skb);
243e27cca96SSabrina Dubroca 
244e27cca96SSabrina Dubroca 	return -EOPNOTSUPP;
245e27cca96SSabrina Dubroca }
246e27cca96SSabrina Dubroca #endif
247fd5dabf7SHerbert Xu 
esp_output_done(void * data,int err)24838320c70SHerbert Xu static void esp_output_done(void *data, int err)
249fd5dabf7SHerbert Xu {
250f53c7239SSteffen Klassert 	struct sk_buff *skb = data;
251cac2661cSSteffen Klassert 	struct xfrm_offload *xo = xfrm_offload(skb);
252f53c7239SSteffen Klassert 	void *tmp;
253f53c7239SSteffen Klassert 	struct xfrm_state *x;
2542294be0fSFlorian Westphal 
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];
259f53c7239SSteffen Klassert 	} else {
2602294be0fSFlorian Westphal 		x = skb_dst(skb)->xfrm;
26138320c70SHerbert Xu 	}
262cac2661cSSteffen Klassert 
263c3198822SDragos Tatulea 	tmp = ESP_SKB_CB(skb)->tmp;
264cac2661cSSteffen Klassert 	esp_ssg_unref(x, tmp, skb);
265f53c7239SSteffen 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);
277e27cca96SSabrina Dubroca 	} else {
278e27cca96SSabrina Dubroca 		if (!err &&
279e27cca96SSabrina Dubroca 		    x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP)
280e27cca96SSabrina Dubroca 			esp_output_tail_tcp(x, skb);
2819ab1265dSEvan Nimmo 		else
28238320c70SHerbert Xu 			xfrm_output_resume(skb->sk, skb, err);
283f53c7239SSteffen Klassert 	}
28438320c70SHerbert Xu }
2857021b2e1SHerbert 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);
290962fcef3SHerbert Xu 	void *tmp = ESP_SKB_CB(skb)->tmp;
2917021b2e1SHerbert 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)
298962fcef3SHerbert 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 -
3037021b2e1SHerbert Xu 				sizeof(__be32));
3047021b2e1SHerbert Xu }
305cac2661cSSteffen Klassert 
esp_output_set_extra(struct sk_buff * skb,struct xfrm_state * x,struct ip_esp_hdr * esph,struct esp_output_extra * extra)306fca11ebdSSteffen Klassert static struct ip_esp_hdr *esp_output_set_extra(struct sk_buff *skb,
307cac2661cSSteffen Klassert 					       struct xfrm_state *x,
308cac2661cSSteffen Klassert 					       struct ip_esp_hdr *esph,
309cac2661cSSteffen Klassert 					       struct esp_output_extra *extra)
310cac2661cSSteffen Klassert {
311cbd801b3SLu Wei 	/* For ESN we move the header forward by 4 bytes to
312cac2661cSSteffen Klassert 	 * accommodate the high bits.  We will move it back after
313cac2661cSSteffen Klassert 	 * encryption.
314cac2661cSSteffen Klassert 	 */
3157862b405SSteffen 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;
323cac2661cSSteffen 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);
3277862b405SSteffen Klassert 		extra->seqhi = esph->spi;
328cac2661cSSteffen 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 }
335fd5dabf7SHerbert Xu 
esp_output_done_esn(void * data,int err)3367021b2e1SHerbert Xu static void esp_output_done_esn(void *data, int err)
337fd5dabf7SHerbert Xu {
3387021b2e1SHerbert Xu 	struct sk_buff *skb = data;
3397021b2e1SHerbert Xu 
34014d3109cSHerbert Xu 	esp_output_restore_header(skb);
3417021b2e1SHerbert Xu 	esp_output_done(data, err);
3427021b2e1SHerbert Xu }
343eecd227aSSabrina Dubroca 
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,
3481da177e4SLinus Torvalds 					       __be16 dport)
3491da177e4SLinus Torvalds {
3508dfb4ebaSSabrina Dubroca 	struct udphdr *uh;
35138320c70SHerbert Xu 	unsigned int len;
352eecd227aSSabrina Dubroca 
353e27cca96SSabrina Dubroca 	len = skb->len + esp->tailen - skb_transport_offset(skb);
354eecd227aSSabrina 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 	return (struct ip_esp_hdr *)(uh + 1);
366eecd227aSSabrina Dubroca }
367e27cca96SSabrina Dubroca 
368e27cca96SSabrina Dubroca #ifdef CONFIG_INET_ESPINTCP
esp_output_tcp_encap(struct xfrm_state * x,struct sk_buff * skb,struct esp_info * esp)369e27cca96SSabrina Dubroca static struct ip_esp_hdr *esp_output_tcp_encap(struct xfrm_state *x,
370e27cca96SSabrina Dubroca 						    struct sk_buff *skb,
371e27cca96SSabrina Dubroca 						    struct esp_info *esp)
372e27cca96SSabrina Dubroca {
373e27cca96SSabrina Dubroca 	__be16 *lenp = (void *)esp->esph;
374e27cca96SSabrina Dubroca 	struct ip_esp_hdr *esph;
375e27cca96SSabrina Dubroca 	unsigned int len;
376e27cca96SSabrina Dubroca 	struct sock *sk;
377e27cca96SSabrina Dubroca 
378e27cca96SSabrina Dubroca 	len = skb->len + esp->tailen - skb_transport_offset(skb);
379e27cca96SSabrina Dubroca 	if (len > IP_MAX_MTU)
380e27cca96SSabrina Dubroca 		return ERR_PTR(-EMSGSIZE);
381e27cca96SSabrina Dubroca 
382e27cca96SSabrina Dubroca 	rcu_read_lock();
383e27cca96SSabrina Dubroca 	sk = esp_find_tcp_sk(x);
384e27cca96SSabrina Dubroca 	rcu_read_unlock();
385e27cca96SSabrina Dubroca 
386e27cca96SSabrina Dubroca 	if (IS_ERR(sk))
387e27cca96SSabrina Dubroca 		return ERR_CAST(sk);
388e27cca96SSabrina Dubroca 
389e27cca96SSabrina Dubroca 	*lenp = htons(len);
390e27cca96SSabrina Dubroca 	esph = (struct ip_esp_hdr *)(lenp + 1);
391e27cca96SSabrina Dubroca 
392e27cca96SSabrina Dubroca 	return esph;
393e27cca96SSabrina Dubroca }
394e27cca96SSabrina Dubroca #else
esp_output_tcp_encap(struct xfrm_state * x,struct sk_buff * skb,struct esp_info * esp)395e27cca96SSabrina Dubroca static struct ip_esp_hdr *esp_output_tcp_encap(struct xfrm_state *x,
396e27cca96SSabrina Dubroca 						    struct sk_buff *skb,
397e27cca96SSabrina Dubroca 						    struct esp_info *esp)
398e27cca96SSabrina Dubroca {
399e27cca96SSabrina Dubroca 	return ERR_PTR(-EOPNOTSUPP);
400e27cca96SSabrina Dubroca }
401e27cca96SSabrina Dubroca #endif
402eecd227aSSabrina Dubroca 
esp_output_encap(struct xfrm_state * x,struct sk_buff * skb,struct esp_info * esp)403eecd227aSSabrina Dubroca static int esp_output_encap(struct xfrm_state *x, struct sk_buff *skb,
404eecd227aSSabrina Dubroca 			    struct esp_info *esp)
405eecd227aSSabrina Dubroca {
406eecd227aSSabrina Dubroca 	struct xfrm_encap_tmpl *encap = x->encap;
407eecd227aSSabrina Dubroca 	struct ip_esp_hdr *esph;
408eecd227aSSabrina Dubroca 	__be16 sport, dport;
409eecd227aSSabrina Dubroca 	int encap_type;
41038320c70SHerbert Xu 
41138320c70SHerbert Xu 	spin_lock_bh(&x->lock);
41238320c70SHerbert Xu 	sport = encap->encap_sport;
41338320c70SHerbert Xu 	dport = encap->encap_dport;
41438320c70SHerbert Xu 	encap_type = encap->encap_type;
4151da177e4SLinus Torvalds 	spin_unlock_bh(&x->lock);
41638320c70SHerbert Xu 
4171da177e4SLinus Torvalds 	switch (encap_type) {
4181da177e4SLinus Torvalds 	default:
419eecd227aSSabrina Dubroca 	case UDP_ENCAP_ESPINUDP:
4201da177e4SLinus Torvalds 		esph = esp_output_udp_encap(skb, encap_type, esp, sport, dport);
421e27cca96SSabrina Dubroca 		break;
422e27cca96SSabrina Dubroca 	case TCP_ENCAP_ESPINTCP:
423e27cca96SSabrina Dubroca 		esph = esp_output_tcp_encap(x, skb, esp);
4241da177e4SLinus Torvalds 		break;
4251da177e4SLinus Torvalds 	}
426eecd227aSSabrina Dubroca 
427eecd227aSSabrina Dubroca 	if (IS_ERR(esph))
428eecd227aSSabrina Dubroca 		return PTR_ERR(esph);
429fca11ebdSSteffen Klassert 
4308dfb4ebaSSabrina Dubroca 	esp->esph = esph;
4318dfb4ebaSSabrina Dubroca 
43237fedd3aSHerbert Xu 	return 0;
4331da177e4SLinus Torvalds }
434fca11ebdSSteffen Klassert 
esp_output_head(struct xfrm_state * x,struct sk_buff * skb,struct esp_info * esp)435fca11ebdSSteffen Klassert int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *esp)
436fca11ebdSSteffen Klassert {
437fca11ebdSSteffen Klassert 	u8 *tail;
4380e78a873SSteffen Klassert 	int nfrags;
439fca11ebdSSteffen Klassert 	int esph_offset;
440fca11ebdSSteffen Klassert 	struct page *page;
441fca11ebdSSteffen Klassert 	struct sk_buff *trailer;
442fca11ebdSSteffen Klassert 	int tailen = esp->tailen;
443e27cca96SSabrina Dubroca 
4448dfb4ebaSSabrina Dubroca 	/* this is non-NULL only with TCP/UDP Encapsulation */
445eecd227aSSabrina Dubroca 	if (x->encap) {
4468dfb4ebaSSabrina Dubroca 		int err = esp_output_encap(x, skb, esp);
4478dfb4ebaSSabrina Dubroca 
4488dfb4ebaSSabrina Dubroca 		if (err < 0)
4498dfb4ebaSSabrina Dubroca 			return err;
450fca11ebdSSteffen Klassert 	}
4515bd8baabSSabrina Dubroca 
4525bd8baabSSabrina Dubroca 	if (ALIGN(tailen, L1_CACHE_BYTES) > PAGE_SIZE ||
453ebe48d36SSteffen Klassert 	    ALIGN(skb->data_len, L1_CACHE_BYTES) > PAGE_SIZE)
454ebe48d36SSteffen Klassert 		goto cow;
455cac2661cSSteffen Klassert 
45654ffd790SSteffen Klassert 	if (!skb_cloned(skb)) {
457cac2661cSSteffen Klassert 		if (tailen <= skb_tailroom(skb)) {
458cac2661cSSteffen Klassert 			nfrags = 1;
459cac2661cSSteffen Klassert 			trailer = skb;
4601da177e4SLinus Torvalds 			tail = skb_tail_pointer(trailer);
461cac2661cSSteffen Klassert 
462cac2661cSSteffen Klassert 			goto skip_cow;
463cac2661cSSteffen Klassert 		} else if ((skb_shinfo(skb)->nr_frags < MAX_SKB_FRAGS)
464cac2661cSSteffen Klassert 			   && !skb_has_frag_list(skb)) {
465cac2661cSSteffen Klassert 			int allocsize;
466cac2661cSSteffen Klassert 			struct sock *sk = skb->sk;
4677021b2e1SHerbert Xu 			struct page_frag *pfrag = &x->xfrag;
468fca11ebdSSteffen Klassert 
469fca11ebdSSteffen Klassert 			esp->inplace = false;
470cac2661cSSteffen Klassert 
471cac2661cSSteffen Klassert 			allocsize = ALIGN(tailen, L1_CACHE_BYTES);
472cac2661cSSteffen Klassert 
473cac2661cSSteffen Klassert 			spin_lock_bh(&x->lock);
474cac2661cSSteffen Klassert 
475cac2661cSSteffen Klassert 			if (unlikely(!skb_page_frag_refill(allocsize, pfrag, GFP_ATOMIC))) {
476cac2661cSSteffen Klassert 				spin_unlock_bh(&x->lock);
4777021b2e1SHerbert Xu 				goto cow;
4787021b2e1SHerbert Xu 			}
479cac2661cSSteffen Klassert 
480cac2661cSSteffen Klassert 			page = pfrag->page;
481cac2661cSSteffen Klassert 			get_page(page);
4829bd6b629SWillem de Bruijn 
483cac2661cSSteffen Klassert 			tail = page_address(page) + pfrag->offset;
484fca11ebdSSteffen Klassert 
485cac2661cSSteffen Klassert 			esp_output_fill_trailer(tail, esp->tfclen, esp->plen, esp->proto);
486cac2661cSSteffen Klassert 
487cac2661cSSteffen Klassert 			nfrags = skb_shinfo(skb)->nr_frags;
488cac2661cSSteffen Klassert 
489cac2661cSSteffen Klassert 			__skb_fill_page_desc(skb, nfrags, page, pfrag->offset,
490cac2661cSSteffen Klassert 					     tailen);
491cac2661cSSteffen Klassert 			skb_shinfo(skb)->nr_frags = ++nfrags;
492cac2661cSSteffen Klassert 
49336ff0dd3SSteffen Klassert 			pfrag->offset = pfrag->offset + allocsize;
49436ff0dd3SSteffen Klassert 
49536ff0dd3SSteffen Klassert 			spin_unlock_bh(&x->lock);
496cac2661cSSteffen Klassert 
497cac2661cSSteffen Klassert 			nfrags++;
498ede57d58SRichard Gobert 
49909db5124SMartin Willi 			skb_len_add(skb, tailen);
50014afee4bSReshetova, Elena 			if (sk && sk_fullsock(sk))
501cac2661cSSteffen Klassert 				refcount_add(tailen, &sk->sk_wmem_alloc);
502fca11ebdSSteffen Klassert 
503fca11ebdSSteffen Klassert 			goto out;
504fca11ebdSSteffen Klassert 		}
505cac2661cSSteffen Klassert 	}
506fca11ebdSSteffen Klassert 
5070e78a873SSteffen Klassert cow:
5080e78a873SSteffen Klassert 	esph_offset = (unsigned char *)esp->esph - skb_transport_header(skb);
509fca11ebdSSteffen Klassert 
510fca11ebdSSteffen Klassert 	nfrags = skb_cow_data(skb, tailen, &trailer);
511fca11ebdSSteffen Klassert 	if (nfrags < 0)
512fca11ebdSSteffen Klassert 		goto out;
5130e78a873SSteffen Klassert 	tail = skb_tail_pointer(trailer);
5147021b2e1SHerbert Xu 	esp->esph = (struct ip_esp_hdr *)(skb_transport_header(skb) + esph_offset);
515fca11ebdSSteffen Klassert 
516fca11ebdSSteffen Klassert skip_cow:
517fca11ebdSSteffen Klassert 	esp_output_fill_trailer(tail, esp->tfclen, esp->plen, esp->proto);
518fca11ebdSSteffen Klassert 	pskb_put(skb, trailer, tailen);
519fca11ebdSSteffen Klassert 
520fca11ebdSSteffen Klassert out:
521fca11ebdSSteffen Klassert 	return nfrags;
522fca11ebdSSteffen Klassert }
523fca11ebdSSteffen Klassert EXPORT_SYMBOL_GPL(esp_output_head);
524fca11ebdSSteffen Klassert 
esp_output_tail(struct xfrm_state * x,struct sk_buff * skb,struct esp_info * esp)525fca11ebdSSteffen Klassert int esp_output_tail(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *esp)
526fca11ebdSSteffen Klassert {
527fca11ebdSSteffen Klassert 	u8 *iv;
528fca11ebdSSteffen Klassert 	int alen;
529fca11ebdSSteffen Klassert 	void *tmp;
530fca11ebdSSteffen Klassert 	int ivlen;
531fca11ebdSSteffen Klassert 	int assoclen;
532fca11ebdSSteffen Klassert 	int extralen;
533fca11ebdSSteffen Klassert 	struct page *page;
534fca11ebdSSteffen Klassert 	struct ip_esp_hdr *esph;
535fca11ebdSSteffen Klassert 	struct crypto_aead *aead;
536fca11ebdSSteffen Klassert 	struct aead_request *req;
537fca11ebdSSteffen Klassert 	struct scatterlist *sg, *dsg;
538fca11ebdSSteffen Klassert 	struct esp_output_extra *extra;
539fca11ebdSSteffen Klassert 	int err = -ENOMEM;
540fca11ebdSSteffen Klassert 
541fca11ebdSSteffen Klassert 	assoclen = sizeof(struct ip_esp_hdr);
542fca11ebdSSteffen Klassert 	extralen = 0;
543fca11ebdSSteffen Klassert 
544fca11ebdSSteffen Klassert 	if (x->props.flags & XFRM_STATE_ESN) {
545fca11ebdSSteffen Klassert 		extralen += sizeof(*extra);
546fca11ebdSSteffen Klassert 		assoclen += sizeof(__be32);
547fca11ebdSSteffen Klassert 	}
548fca11ebdSSteffen Klassert 
549fca11ebdSSteffen Klassert 	aead = x->data;
550fca11ebdSSteffen Klassert 	alen = crypto_aead_authsize(aead);
551fca11ebdSSteffen Klassert 	ivlen = crypto_aead_ivsize(aead);
552fca11ebdSSteffen Klassert 
553e892d2d4SSteffen Klassert 	tmp = esp_alloc_tmp(aead, esp->nfrags + 2, extralen);
554cac2661cSSteffen Klassert 	if (!tmp)
555cac2661cSSteffen Klassert 		goto error;
556cac2661cSSteffen Klassert 
557cac2661cSSteffen Klassert 	extra = esp_tmp_extra(tmp);
558cac2661cSSteffen Klassert 	iv = esp_tmp_iv(aead, tmp, extralen);
559cac2661cSSteffen Klassert 	req = esp_tmp_req(aead, iv);
560cac2661cSSteffen Klassert 	sg = esp_req_sg(aead, req);
561fca11ebdSSteffen Klassert 
562fca11ebdSSteffen Klassert 	if (esp->inplace)
563fca11ebdSSteffen Klassert 		dsg = sg;
564fca11ebdSSteffen Klassert 	else
565cac2661cSSteffen Klassert 		dsg = &sg[esp->nfrags];
566fca11ebdSSteffen Klassert 
567fca11ebdSSteffen Klassert 	esph = esp_output_set_extra(skb, x, esp->esph, extra);
568fca11ebdSSteffen Klassert 	esp->esph = esph;
569fca11ebdSSteffen Klassert 
5703f297707SJason A. Donenfeld 	sg_init_table(sg, esp->nfrags);
5717021b2e1SHerbert Xu 	err = skb_to_sgvec(skb, sg,
572fca11ebdSSteffen Klassert 		           (unsigned char *)esph - skb->data,
5733f297707SJason A. Donenfeld 		           assoclen + ivlen + esp->clen + alen);
574e6194923SSteffen Klassert 	if (unlikely(err < 0))
575fca11ebdSSteffen Klassert 		goto error_free;
576fca11ebdSSteffen Klassert 
577fca11ebdSSteffen Klassert 	if (!esp->inplace) {
578fca11ebdSSteffen Klassert 		int allocsize;
5790dc49e9bSSteffen Klassert 		struct page_frag *pfrag = &x->xfrag;
580cac2661cSSteffen Klassert 
581cac2661cSSteffen Klassert 		allocsize = ALIGN(skb->data_len, L1_CACHE_BYTES);
582fca11ebdSSteffen Klassert 
583cac2661cSSteffen Klassert 		spin_lock_bh(&x->lock);
584cac2661cSSteffen Klassert 		if (unlikely(!skb_page_frag_refill(allocsize, pfrag, GFP_ATOMIC))) {
585e6194923SSteffen Klassert 			spin_unlock_bh(&x->lock);
586cac2661cSSteffen Klassert 			goto error_free;
587cac2661cSSteffen Klassert 		}
588cac2661cSSteffen Klassert 
589cac2661cSSteffen Klassert 		skb_shinfo(skb)->nr_frags = 1;
590cac2661cSSteffen Klassert 
591cac2661cSSteffen Klassert 		page = pfrag->page;
592cac2661cSSteffen Klassert 		get_page(page);
593cac2661cSSteffen Klassert 		/* replace page frags in skb with new page */
594cac2661cSSteffen Klassert 		__skb_fill_page_desc(skb, 0, page, pfrag->offset, skb->data_len);
595fca11ebdSSteffen Klassert 		pfrag->offset = pfrag->offset + allocsize;
596cac2661cSSteffen Klassert 		spin_unlock_bh(&x->lock);
597cac2661cSSteffen Klassert 
5983f297707SJason A. Donenfeld 		sg_init_table(dsg, skb_shinfo(skb)->nr_frags + 1);
599cac2661cSSteffen Klassert 		err = skb_to_sgvec(skb, dsg,
600fca11ebdSSteffen Klassert 			           (unsigned char *)esph - skb->data,
6013f297707SJason A. Donenfeld 			           assoclen + ivlen + esp->clen + alen);
602e6194923SSteffen Klassert 		if (unlikely(err < 0))
603cac2661cSSteffen Klassert 			goto error_free;
604cac2661cSSteffen Klassert 	}
605cac2661cSSteffen Klassert 
606cac2661cSSteffen Klassert 	if ((x->props.flags & XFRM_STATE_ESN))
607cac2661cSSteffen Klassert 		aead_request_set_callback(req, 0, esp_output_done_esn, skb);
608cac2661cSSteffen Klassert 	else
609cac2661cSSteffen Klassert 		aead_request_set_callback(req, 0, esp_output_done, skb);
610fca11ebdSSteffen Klassert 
6117021b2e1SHerbert Xu 	aead_request_set_crypt(req, sg, dsg, ivlen + esp->clen, iv);
6121da177e4SLinus Torvalds 	aead_request_set_ad(req, assoclen);
6137021b2e1SHerbert Xu 
614fca11ebdSSteffen Klassert 	memset(iv, 0, ivlen);
6157021b2e1SHerbert Xu 	memcpy(iv + ivlen - min(ivlen, 8), (u8 *)&esp->seqno + 8 - min(ivlen, 8),
6166b7326c8SHerbert Xu 	       min(ivlen, 8));
61738320c70SHerbert Xu 
6187021b2e1SHerbert Xu 	ESP_SKB_CB(skb)->tmp = tmp;
6197021b2e1SHerbert Xu 	err = crypto_aead_encrypt(req);
6207021b2e1SHerbert Xu 
6217021b2e1SHerbert Xu 	switch (err) {
62238320c70SHerbert Xu 	case -EINPROGRESS:
6231da177e4SLinus Torvalds 		goto error;
624068c2e70SGilad Ben-Yossef 
62538320c70SHerbert Xu 	case -ENOSPC:
6267021b2e1SHerbert Xu 		err = NET_XMIT_DROP;
6277021b2e1SHerbert Xu 		break;
6287021b2e1SHerbert Xu 
6297021b2e1SHerbert Xu 	case 0:
6307021b2e1SHerbert Xu 		if ((x->props.flags & XFRM_STATE_ESN))
6317021b2e1SHerbert Xu 			esp_output_restore_header(skb);
6321da177e4SLinus Torvalds 	}
633cac2661cSSteffen Klassert 
634c3198822SDragos Tatulea 	if (sg != dsg)
635b7c6538cSHerbert Xu 		esp_ssg_unref(x, tmp, skb);
636e27cca96SSabrina Dubroca 
637e27cca96SSabrina Dubroca 	if (!err && x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP)
638e27cca96SSabrina Dubroca 		err = esp_output_tail_tcp(x, skb);
639e6194923SSteffen Klassert 
640e6194923SSteffen Klassert error_free:
6411da177e4SLinus Torvalds 	kfree(tmp);
6421da177e4SLinus Torvalds error:
6431da177e4SLinus Torvalds 	return err;
644fca11ebdSSteffen Klassert }
6451da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(esp_output_tail);
646fca11ebdSSteffen Klassert 
esp_output(struct xfrm_state * x,struct sk_buff * skb)647fca11ebdSSteffen Klassert static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
648fca11ebdSSteffen Klassert {
649fca11ebdSSteffen Klassert 	int alen;
650fca11ebdSSteffen Klassert 	int blksize;
651fca11ebdSSteffen Klassert 	struct ip_esp_hdr *esph;
652fca11ebdSSteffen Klassert 	struct crypto_aead *aead;
653fca11ebdSSteffen Klassert 	struct esp_info esp;
654fca11ebdSSteffen Klassert 
655fca11ebdSSteffen Klassert 	esp.inplace = true;
656fca11ebdSSteffen Klassert 
657fca11ebdSSteffen Klassert 	esp.proto = *skb_mac_header(skb);
658fca11ebdSSteffen Klassert 	*skb_mac_header(skb) = IPPROTO_ESP;
659fca11ebdSSteffen Klassert 
660fca11ebdSSteffen Klassert 	/* skb is pure payload to encrypt */
661fca11ebdSSteffen Klassert 
662fca11ebdSSteffen Klassert 	aead = x->data;
663fca11ebdSSteffen Klassert 	alen = crypto_aead_authsize(aead);
664fca11ebdSSteffen Klassert 
665fca11ebdSSteffen Klassert 	esp.tfclen = 0;
666fca11ebdSSteffen Klassert 	if (x->tfcpad) {
667fca11ebdSSteffen Klassert 		struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb);
668fca11ebdSSteffen Klassert 		u32 padto;
669a6d95c5aSJiri Bohac 
670fca11ebdSSteffen Klassert 		padto = min(x->tfcpad, xfrm_state_mtu(x, dst->child_mtu_cached));
671fca11ebdSSteffen Klassert 		if (skb->len < padto)
672fca11ebdSSteffen Klassert 			esp.tfclen = padto - skb->len;
673fca11ebdSSteffen Klassert 	}
674fca11ebdSSteffen Klassert 	blksize = ALIGN(crypto_aead_blocksize(aead), 4);
675fca11ebdSSteffen Klassert 	esp.clen = ALIGN(skb->len + 2 + esp.tfclen, blksize);
676fca11ebdSSteffen Klassert 	esp.plen = esp.clen - skb->len - esp.tfclen;
677fca11ebdSSteffen Klassert 	esp.tailen = esp.tfclen + esp.plen + alen;
678fca11ebdSSteffen Klassert 
679fca11ebdSSteffen Klassert 	esp.esph = ip_esp_hdr(skb);
680fca11ebdSSteffen Klassert 
681fca11ebdSSteffen Klassert 	esp.nfrags = esp_output_head(x, skb, &esp);
682fca11ebdSSteffen Klassert 	if (esp.nfrags < 0)
683fca11ebdSSteffen Klassert 		return esp.nfrags;
684fca11ebdSSteffen Klassert 
685fca11ebdSSteffen Klassert 	esph = esp.esph;
686fca11ebdSSteffen Klassert 	esph->spi = x->id.spi;
687fca11ebdSSteffen Klassert 
688fca11ebdSSteffen Klassert 	esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low);
689fca11ebdSSteffen Klassert 	esp.seqno = cpu_to_be64(XFRM_SKB_CB(skb)->seq.output.low +
690fca11ebdSSteffen Klassert 				 ((u64)XFRM_SKB_CB(skb)->seq.output.hi << 32));
691fca11ebdSSteffen Klassert 
692fca11ebdSSteffen Klassert 	skb_push(skb, -skb_network_offset(skb));
693fca11ebdSSteffen Klassert 
694fca11ebdSSteffen Klassert 	return esp_output_tail(x, skb, &esp);
695fca11ebdSSteffen Klassert }
69647ebcc0bSYossi Kuperman 
esp_remove_trailer(struct sk_buff * skb)69747ebcc0bSYossi Kuperman static inline int esp_remove_trailer(struct sk_buff *skb)
69847ebcc0bSYossi Kuperman {
69947ebcc0bSYossi Kuperman 	struct xfrm_state *x = xfrm_input_state(skb);
70047ebcc0bSYossi Kuperman 	struct crypto_aead *aead = x->data;
70147ebcc0bSYossi Kuperman 	int alen, hlen, elen;
70247ebcc0bSYossi Kuperman 	int padlen, trimlen;
70347ebcc0bSYossi Kuperman 	__wsum csumdiff;
70447ebcc0bSYossi Kuperman 	u8 nexthdr[2];
70547ebcc0bSYossi Kuperman 	int ret;
70647ebcc0bSYossi Kuperman 
70747ebcc0bSYossi Kuperman 	alen = crypto_aead_authsize(aead);
70847ebcc0bSYossi Kuperman 	hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead);
70947ebcc0bSYossi Kuperman 	elen = skb->len - hlen;
71047ebcc0bSYossi Kuperman 
71147ebcc0bSYossi Kuperman 	if (skb_copy_bits(skb, skb->len - alen - 2, nexthdr, 2))
71247ebcc0bSYossi Kuperman 		BUG();
71347ebcc0bSYossi Kuperman 
71447ebcc0bSYossi Kuperman 	ret = -EINVAL;
71547ebcc0bSYossi Kuperman 	padlen = nexthdr[0];
71647ebcc0bSYossi Kuperman 	if (padlen + 2 + alen >= elen) {
71747ebcc0bSYossi Kuperman 		net_dbg_ratelimited("ipsec esp packet is garbage padlen=%d, elen=%d\n",
71847ebcc0bSYossi Kuperman 				    padlen + 2, elen - alen);
71947ebcc0bSYossi Kuperman 		goto out;
72047ebcc0bSYossi Kuperman 	}
72147ebcc0bSYossi Kuperman 
72247ebcc0bSYossi Kuperman 	trimlen = alen + padlen + 2;
72347ebcc0bSYossi Kuperman 	if (skb->ip_summed == CHECKSUM_COMPLETE) {
72447ebcc0bSYossi Kuperman 		csumdiff = skb_checksum(skb, skb->len - trimlen, trimlen, 0);
72547ebcc0bSYossi Kuperman 		skb->csum = csum_block_sub(skb->csum, csumdiff,
72647ebcc0bSYossi Kuperman 					   skb->len - trimlen);
727513f61e2SMa Ke 	}
728513f61e2SMa Ke 	ret = pskb_trim(skb, skb->len - trimlen);
729513f61e2SMa Ke 	if (unlikely(ret))
73047ebcc0bSYossi Kuperman 		return ret;
73147ebcc0bSYossi Kuperman 
73247ebcc0bSYossi Kuperman 	ret = nexthdr[1];
73347ebcc0bSYossi Kuperman 
73447ebcc0bSYossi Kuperman out:
73547ebcc0bSYossi Kuperman 	return ret;
73647ebcc0bSYossi Kuperman }
737fca11ebdSSteffen Klassert 
esp_input_done2(struct sk_buff * skb,int err)7381da177e4SLinus Torvalds int esp_input_done2(struct sk_buff *skb, int err)
739b71d1d42SEric Dumazet {
74038320c70SHerbert Xu 	const struct iphdr *iph;
741d77e38e6SSteffen Klassert 	struct xfrm_state *x = xfrm_input_state(skb);
7421c5ad13fSMathias Krause 	struct xfrm_offload *xo = xfrm_offload(skb);
74338320c70SHerbert Xu 	struct crypto_aead *aead = x->data;
74431a4ab93SHerbert Xu 	int hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead);
7451da177e4SLinus Torvalds 	int ihl;
7461d9bfacdSJiapeng Chong 
74738320c70SHerbert Xu 	if (!xo || !(xo->flags & CRYPTO_DONE))
7480ebea8efSHerbert Xu 		kfree(ESP_SKB_CB(skb)->tmp);
7496b7326c8SHerbert Xu 
750668dc8afSHerbert Xu 	if (unlikely(err))
7511da177e4SLinus Torvalds 		goto out;
75247ebcc0bSYossi Kuperman 
75347ebcc0bSYossi Kuperman 	err = esp_remove_trailer(skb);
7541da177e4SLinus Torvalds 	if (unlikely(err < 0))
7551da177e4SLinus Torvalds 		goto out;
756eddc9ec5SArnaldo Carvalho de Melo 
75731a4ab93SHerbert Xu 	iph = ip_hdr(skb);
75831a4ab93SHerbert Xu 	ihl = iph->ihl * 4;
7591da177e4SLinus Torvalds 
760752c1f4cSHerbert Xu 	if (x->encap) {
761e27cca96SSabrina Dubroca 		struct xfrm_encap_tmpl *encap = x->encap;
762d56f90a7SArnaldo Carvalho de Melo 		struct tcphdr *th = (void *)(skb_network_header(skb) + ihl);
76325f6802bSSabrina Dubroca 		struct udphdr *uh = (void *)(skb_network_header(skb) + ihl);
76425f6802bSSabrina Dubroca 		__be16 source;
76525f6802bSSabrina Dubroca 
766e27cca96SSabrina Dubroca 		switch (x->encap->encap_type) {
767e27cca96SSabrina Dubroca 		case TCP_ENCAP_ESPINTCP:
768e27cca96SSabrina Dubroca 			source = th->source;
76925f6802bSSabrina Dubroca 			break;
77025f6802bSSabrina Dubroca 		case UDP_ENCAP_ESPINUDP:
77125f6802bSSabrina Dubroca 			source = uh->source;
77225f6802bSSabrina Dubroca 			break;
77325f6802bSSabrina Dubroca 		default:
77425f6802bSSabrina Dubroca 			WARN_ON_ONCE(1);
77525f6802bSSabrina Dubroca 			err = -EINVAL;
77625f6802bSSabrina Dubroca 			goto out;
777752c1f4cSHerbert Xu 		}
7781da177e4SLinus Torvalds 
7791da177e4SLinus Torvalds 		/*
780197f9fbaSDeming Wang 		 * 1) if the NAT-T peer's IP or port changed then
7811da177e4SLinus Torvalds 		 *    advertise the change to the keying daemon.
7821da177e4SLinus Torvalds 		 *    This is an inbound SA, so just compare
7831da177e4SLinus Torvalds 		 *    SRC ports.
784752c1f4cSHerbert Xu 		 */
78525f6802bSSabrina Dubroca 		if (iph->saddr != x->props.saddr.a4 ||
7861da177e4SLinus Torvalds 		    source != encap->encap_sport) {
7871da177e4SLinus Torvalds 			xfrm_address_t ipaddr;
788752c1f4cSHerbert Xu 
78925f6802bSSabrina Dubroca 			ipaddr.a4 = iph->saddr;
7901da177e4SLinus Torvalds 			km_new_mapping(x, &ipaddr, source);
7911da177e4SLinus Torvalds 
7921da177e4SLinus Torvalds 			/* XXX: perhaps add an extra
7931da177e4SLinus Torvalds 			 * policy check here, to see
7941da177e4SLinus Torvalds 			 * if we should allow or
7951da177e4SLinus Torvalds 			 * reject a packet from a
7961da177e4SLinus Torvalds 			 * different source
7971da177e4SLinus Torvalds 			 * address/port.
7981da177e4SLinus Torvalds 			 */
7991da177e4SLinus Torvalds 		}
8001da177e4SLinus Torvalds 
8011da177e4SLinus Torvalds 		/*
8021da177e4SLinus Torvalds 		 * 2) ignore UDP/TCP checksums in case
8031da177e4SLinus Torvalds 		 *    of NAT-T in Transport Mode, or
804752c1f4cSHerbert Xu 		 *    perform other post-processing fixes
8051da177e4SLinus Torvalds 		 *    as per draft-ietf-ipsec-udp-encaps-06,
8061da177e4SLinus Torvalds 		 *    section 3.1.2
8078bd17075SHerbert Xu 		 */
8081da177e4SLinus Torvalds 		if (x->props.mode == XFRM_MODE_TRANSPORT)
809752c1f4cSHerbert Xu 			skb->ip_summed = CHECKSUM_UNNECESSARY;
8101da177e4SLinus Torvalds 	}
811ec9567a9SIlan Tayari 
8127143dfacSLi RongQing 	skb_pull_rcsum(skb, hlen);
8137143dfacSLi RongQing 	if (x->props.mode == XFRM_MODE_TUNNEL)
8147143dfacSLi RongQing 		skb_reset_transport_header(skb);
815967b05f6SArnaldo Carvalho de Melo 	else
816752c1f4cSHerbert Xu 		skb_set_transport_header(skb, -ihl);
81738320c70SHerbert Xu 
81838320c70SHerbert Xu 	/* RFC4303: Drop dummy packets without any error */
81938320c70SHerbert Xu 	if (err == IPPROTO_NONE)
82038320c70SHerbert Xu 		err = -EINVAL;
82138320c70SHerbert Xu 
82238320c70SHerbert Xu out:
82338320c70SHerbert Xu 	return err;
824fca11ebdSSteffen Klassert }
82538320c70SHerbert Xu EXPORT_SYMBOL_GPL(esp_input_done2);
826fd5dabf7SHerbert Xu 
esp_input_done(void * data,int err)82738320c70SHerbert Xu static void esp_input_done(void *data, int err)
828fd5dabf7SHerbert Xu {
82938320c70SHerbert Xu 	struct sk_buff *skb = data;
83038320c70SHerbert Xu 
83138320c70SHerbert Xu 	xfrm_input_resume(skb, esp_input_done2(skb, err));
83238320c70SHerbert Xu }
8337021b2e1SHerbert Xu 
esp_input_restore_header(struct sk_buff * skb)8347021b2e1SHerbert Xu static void esp_input_restore_header(struct sk_buff *skb)
8357021b2e1SHerbert Xu {
8367021b2e1SHerbert Xu 	esp_restore_header(skb, 0);
8377021b2e1SHerbert Xu 	__skb_pull(skb, 4);
8387021b2e1SHerbert Xu }
839cac2661cSSteffen Klassert 
esp_input_set_header(struct sk_buff * skb,__be32 * seqhi)840cac2661cSSteffen Klassert static void esp_input_set_header(struct sk_buff *skb, __be32 *seqhi)
841cac2661cSSteffen Klassert {
84260aa8046SColin Ian King 	struct xfrm_state *x = xfrm_input_state(skb);
843cac2661cSSteffen Klassert 	struct ip_esp_hdr *esph;
844cac2661cSSteffen Klassert 
845cbd801b3SLu Wei 	/* For ESN we move the header forward by 4 bytes to
846cac2661cSSteffen Klassert 	 * accommodate the high bits.  We will move it back after
847cac2661cSSteffen Klassert 	 * decryption.
848cac2661cSSteffen Klassert 	 */
849d58ff351SJohannes Berg 	if ((x->props.flags & XFRM_STATE_ESN)) {
850cac2661cSSteffen Klassert 		esph = skb_push(skb, 4);
851cac2661cSSteffen Klassert 		*seqhi = esph->spi;
852cac2661cSSteffen Klassert 		esph->spi = esph->seq_no;
853cac2661cSSteffen Klassert 		esph->seq_no = XFRM_SKB_CB(skb)->seq.input.hi;
854cac2661cSSteffen Klassert 	}
855cac2661cSSteffen Klassert }
856fd5dabf7SHerbert Xu 
esp_input_done_esn(void * data,int err)8577021b2e1SHerbert Xu static void esp_input_done_esn(void *data, int err)
858fd5dabf7SHerbert Xu {
8597021b2e1SHerbert Xu 	struct sk_buff *skb = data;
8607021b2e1SHerbert Xu 
86114d3109cSHerbert Xu 	esp_input_restore_header(skb);
8627021b2e1SHerbert Xu 	esp_input_done(data, err);
8637021b2e1SHerbert Xu }
86438320c70SHerbert Xu 
86538320c70SHerbert Xu /*
86638320c70SHerbert Xu  * Note: detecting truncated vs. non-truncated authentication data is very
86738320c70SHerbert Xu  * expensive, so we only support truncated data, which is the recommended
86838320c70SHerbert Xu  * and common case.
86938320c70SHerbert Xu  */
esp_input(struct xfrm_state * x,struct sk_buff * skb)87038320c70SHerbert Xu static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
8711c5ad13fSMathias Krause {
87238320c70SHerbert Xu 	struct crypto_aead *aead = x->data;
87338320c70SHerbert Xu 	struct aead_request *req;
8747021b2e1SHerbert Xu 	struct sk_buff *trailer;
8750c05f983SHaishuang Yan 	int ivlen = crypto_aead_ivsize(aead);
87638320c70SHerbert Xu 	int elen = skb->len - sizeof(struct ip_esp_hdr) - ivlen;
8770dc49e9bSSteffen Klassert 	int nfrags;
8780dc49e9bSSteffen Klassert 	int assoclen;
8790dc49e9bSSteffen Klassert 	int seqhilen;
88038320c70SHerbert Xu 	__be32 *seqhi;
88138320c70SHerbert Xu 	void *tmp;
88238320c70SHerbert Xu 	u8 *iv;
88338320c70SHerbert Xu 	struct scatterlist *sg;
88438320c70SHerbert Xu 	int err = -EINVAL;
8850c05f983SHaishuang Yan 
88638320c70SHerbert Xu 	if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr) + ivlen))
88738320c70SHerbert Xu 		goto out;
88838320c70SHerbert Xu 
88938320c70SHerbert Xu 	if (elen <= 0)
89038320c70SHerbert Xu 		goto out;
8910c05f983SHaishuang Yan 
8920dc49e9bSSteffen Klassert 	assoclen = sizeof(struct ip_esp_hdr);
8930dc49e9bSSteffen Klassert 	seqhilen = 0;
8940dc49e9bSSteffen Klassert 
8950dc49e9bSSteffen Klassert 	if (x->props.flags & XFRM_STATE_ESN) {
8960dc49e9bSSteffen Klassert 		seqhilen += sizeof(__be32);
8970dc49e9bSSteffen Klassert 		assoclen += seqhilen;
8980dc49e9bSSteffen Klassert 	}
899cac2661cSSteffen Klassert 
900cac2661cSSteffen Klassert 	if (!skb_cloned(skb)) {
901cac2661cSSteffen Klassert 		if (!skb_is_nonlinear(skb)) {
902cac2661cSSteffen Klassert 			nfrags = 1;
903cac2661cSSteffen Klassert 
904cac2661cSSteffen Klassert 			goto skip_cow;
905cac2661cSSteffen Klassert 		} else if (!skb_has_frag_list(skb)) {
906cac2661cSSteffen Klassert 			nfrags = skb_shinfo(skb)->nr_frags;
907cac2661cSSteffen Klassert 			nfrags++;
908cac2661cSSteffen Klassert 
909cac2661cSSteffen Klassert 			goto skip_cow;
910cac2661cSSteffen Klassert 		}
911cac2661cSSteffen Klassert 	}
912cac2661cSSteffen Klassert 
913cac2661cSSteffen Klassert 	err = skb_cow_data(skb, 0, &trailer);
914cac2661cSSteffen Klassert 	if (err < 0)
915cac2661cSSteffen Klassert 		goto out;
916cac2661cSSteffen Klassert 
917cac2661cSSteffen Klassert 	nfrags = err;
918cac2661cSSteffen Klassert 
91938320c70SHerbert Xu skip_cow:
9207021b2e1SHerbert Xu 	err = -ENOMEM;
92138320c70SHerbert Xu 	tmp = esp_alloc_tmp(aead, nfrags, seqhilen);
92238320c70SHerbert Xu 	if (!tmp)
92338320c70SHerbert Xu 		goto out;
92438320c70SHerbert Xu 
925962fcef3SHerbert Xu 	ESP_SKB_CB(skb)->tmp = tmp;
9260dc49e9bSSteffen Klassert 	seqhi = esp_tmp_extra(tmp);
92738320c70SHerbert Xu 	iv = esp_tmp_iv(aead, tmp, seqhilen);
9287021b2e1SHerbert Xu 	req = esp_tmp_req(aead, iv);
92938320c70SHerbert Xu 	sg = esp_req_sg(aead, req);
930cac2661cSSteffen Klassert 
93138320c70SHerbert Xu 	esp_input_set_header(skb, seqhi);
93238320c70SHerbert Xu 
9333f297707SJason A. Donenfeld 	sg_init_table(sg, nfrags);
934e6194923SSteffen Klassert 	err = skb_to_sgvec(skb, sg, 0, skb->len);
935e6194923SSteffen Klassert 	if (unlikely(err < 0)) {
9363f297707SJason A. Donenfeld 		kfree(tmp);
937e6194923SSteffen Klassert 		goto out;
9380dc49e9bSSteffen Klassert 	}
939cac2661cSSteffen Klassert 
940cac2661cSSteffen Klassert 	skb->ip_summed = CHECKSUM_NONE;
941cac2661cSSteffen Klassert 
942cac2661cSSteffen Klassert 	if ((x->props.flags & XFRM_STATE_ESN))
943cac2661cSSteffen Klassert 		aead_request_set_callback(req, 0, esp_input_done_esn, skb);
944cac2661cSSteffen Klassert 	else
945cac2661cSSteffen Klassert 		aead_request_set_callback(req, 0, esp_input_done, skb);
9467021b2e1SHerbert Xu 
9477021b2e1SHerbert Xu 	aead_request_set_crypt(req, sg, sg, elen + ivlen, iv);
94838320c70SHerbert Xu 	aead_request_set_ad(req, assoclen);
94938320c70SHerbert Xu 
95038320c70SHerbert Xu 	err = crypto_aead_decrypt(req);
95138320c70SHerbert Xu 	if (err == -EINPROGRESS)
95238320c70SHerbert Xu 		goto out;
9537021b2e1SHerbert Xu 
9547021b2e1SHerbert Xu 	if ((x->props.flags & XFRM_STATE_ESN))
9557021b2e1SHerbert Xu 		esp_input_restore_header(skb);
95638320c70SHerbert Xu 
957752c1f4cSHerbert Xu 	err = esp_input_done2(skb, err);
958752c1f4cSHerbert Xu 
959668dc8afSHerbert Xu out:
9601da177e4SLinus Torvalds 	return err;
9611da177e4SLinus Torvalds }
962827789cbSSteffen Klassert 
esp4_err(struct sk_buff * skb,u32 info)9631da177e4SLinus Torvalds static int esp4_err(struct sk_buff *skb, u32 info)
9644fb236baSAlexey Dobriyan {
965b71d1d42SEric Dumazet 	struct net *net = dev_net(skb->dev);
9661da177e4SLinus Torvalds 	const struct iphdr *iph = (const struct iphdr *)skb->data;
9671da177e4SLinus Torvalds 	struct ip_esp_hdr *esph = (struct ip_esp_hdr *)(skb->data+(iph->ihl<<2));
9681da177e4SLinus Torvalds 	struct xfrm_state *x;
96955be7a9cSDavid S. Miller 
97055be7a9cSDavid S. Miller 	switch (icmp_hdr(skb)->type) {
97155be7a9cSDavid S. Miller 	case ICMP_DEST_UNREACH:
972827789cbSSteffen Klassert 		if (icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
97379121184SGustavo A. R. Silva 			return 0;
97455be7a9cSDavid S. Miller 		break;
97555be7a9cSDavid S. Miller 	case ICMP_REDIRECT:
97655be7a9cSDavid S. Miller 		break;
977827789cbSSteffen Klassert 	default:
97855be7a9cSDavid S. Miller 		return 0;
9791da177e4SLinus Torvalds 	}
980b71d1d42SEric Dumazet 
981b71d1d42SEric Dumazet 	x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
9821da177e4SLinus Torvalds 			      esph->spi, IPPROTO_ESP, AF_INET);
983827789cbSSteffen Klassert 	if (!x)
98455be7a9cSDavid S. Miller 		return 0;
985387aa65aSTimo Teräs 
986d888f396SMaciej Żenczykowski 	if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH)
987387aa65aSTimo Teräs 		ipv4_update_pmtu(skb, net, info, 0, IPPROTO_ESP);
9881042caa7SMaciej Żenczykowski 	else
9891da177e4SLinus Torvalds 		ipv4_redirect(skb, net, 0, IPPROTO_ESP);
990827789cbSSteffen Klassert 	xfrm_state_put(x);
991827789cbSSteffen Klassert 
9921da177e4SLinus Torvalds 	return 0;
9931da177e4SLinus Torvalds }
9941da177e4SLinus Torvalds 
esp_destroy(struct xfrm_state * x)9951da177e4SLinus Torvalds static void esp_destroy(struct xfrm_state *x)
9961c5ad13fSMathias Krause {
9971da177e4SLinus Torvalds 	struct crypto_aead *aead = x->data;
9981c5ad13fSMathias Krause 
9991da177e4SLinus Torvalds 	if (!aead)
10001da177e4SLinus Torvalds 		return;
10011c5ad13fSMathias Krause 
10021da177e4SLinus Torvalds 	crypto_free_aead(aead);
10031da177e4SLinus Torvalds }
100467c44f93SSabrina Dubroca 
esp_init_aead(struct xfrm_state * x,struct netlink_ext_ack * extack)10051da177e4SLinus Torvalds static int esp_init_aead(struct xfrm_state *x, struct netlink_ext_ack *extack)
10067021b2e1SHerbert Xu {
10071a6509d9SHerbert Xu 	char aead_name[CRYPTO_MAX_ALG_NAME];
10081a6509d9SHerbert Xu 	struct crypto_aead *aead;
10091a6509d9SHerbert Xu 	int err;
10107021b2e1SHerbert Xu 
101167c44f93SSabrina Dubroca 	if (snprintf(aead_name, CRYPTO_MAX_ALG_NAME, "%s(%s)",
101267c44f93SSabrina Dubroca 		     x->geniv, x->aead->alg_name) >= CRYPTO_MAX_ALG_NAME) {
101367c44f93SSabrina Dubroca 		NL_SET_ERR_MSG(extack, "Algorithm name is too long");
101467c44f93SSabrina Dubroca 		return -ENAMETOOLONG;
10157021b2e1SHerbert Xu 	}
1016f58869c4SSteffen Klassert 
10171a6509d9SHerbert Xu 	aead = crypto_alloc_aead(aead_name, 0, 0);
10181a6509d9SHerbert Xu 	err = PTR_ERR(aead);
10191a6509d9SHerbert Xu 	if (IS_ERR(aead))
10201a6509d9SHerbert Xu 		goto error;
10211c5ad13fSMathias Krause 
10221a6509d9SHerbert Xu 	x->data = aead;
10231a6509d9SHerbert Xu 
10241a6509d9SHerbert Xu 	err = crypto_aead_setkey(aead, x->aead->alg_key,
10251a6509d9SHerbert Xu 				 (x->aead->alg_key_len + 7) / 8);
10261a6509d9SHerbert Xu 	if (err)
10271a6509d9SHerbert Xu 		goto error;
10281a6509d9SHerbert Xu 
10291a6509d9SHerbert Xu 	err = crypto_aead_setauthsize(aead, x->aead->alg_icv_len / 8);
10301a6509d9SHerbert Xu 	if (err)
10311a6509d9SHerbert Xu 		goto error;
103267c44f93SSabrina Dubroca 
103367c44f93SSabrina Dubroca 	return 0;
10341a6509d9SHerbert Xu 
103567c44f93SSabrina Dubroca error:
10361a6509d9SHerbert Xu 	NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
10371a6509d9SHerbert Xu 	return err;
10381a6509d9SHerbert Xu }
103967c44f93SSabrina Dubroca 
esp_init_authenc(struct xfrm_state * x,struct netlink_ext_ack * extack)104067c44f93SSabrina Dubroca static int esp_init_authenc(struct xfrm_state *x,
10411a6509d9SHerbert Xu 			    struct netlink_ext_ack *extack)
104238320c70SHerbert Xu {
104338320c70SHerbert Xu 	struct crypto_aead *aead;
104438320c70SHerbert Xu 	struct crypto_authenc_key_param *param;
104538320c70SHerbert Xu 	struct rtattr *rta;
104638320c70SHerbert Xu 	char *key;
104738320c70SHerbert Xu 	char *p;
104838320c70SHerbert Xu 	char authenc_name[CRYPTO_MAX_ALG_NAME];
104938320c70SHerbert Xu 	unsigned int keylen;
10501da177e4SLinus Torvalds 	int err;
10511a6509d9SHerbert Xu 
10520dc49e9bSSteffen Klassert 	err = -ENAMETOOLONG;
10530dc49e9bSSteffen Klassert 
10540dc49e9bSSteffen Klassert 	if ((x->props.flags & XFRM_STATE_ESN)) {
10557021b2e1SHerbert Xu 		if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME,
10567021b2e1SHerbert Xu 			     "%s%sauthencesn(%s,%s)%s",
105738320c70SHerbert Xu 			     x->geniv ?: "", x->geniv ? "(" : "",
10587021b2e1SHerbert Xu 			     x->aalg ? x->aalg->alg_name : "digest_null",
105967c44f93SSabrina Dubroca 			     x->ealg->alg_name,
106067c44f93SSabrina Dubroca 			     x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME) {
10611a6509d9SHerbert Xu 			NL_SET_ERR_MSG(extack, "Algorithm name is too long");
106267c44f93SSabrina Dubroca 			goto error;
10630dc49e9bSSteffen Klassert 		}
10640dc49e9bSSteffen Klassert 	} else {
10657021b2e1SHerbert Xu 		if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME,
10667021b2e1SHerbert Xu 			     "%s%sauthenc(%s,%s)%s",
10670dc49e9bSSteffen Klassert 			     x->geniv ?: "", x->geniv ? "(" : "",
10687021b2e1SHerbert Xu 			     x->aalg ? x->aalg->alg_name : "digest_null",
106967c44f93SSabrina Dubroca 			     x->ealg->alg_name,
107067c44f93SSabrina Dubroca 			     x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME) {
10710dc49e9bSSteffen Klassert 			NL_SET_ERR_MSG(extack, "Algorithm name is too long");
10720dc49e9bSSteffen Klassert 			goto error;
107367c44f93SSabrina Dubroca 		}
107438320c70SHerbert Xu 	}
1075f58869c4SSteffen Klassert 
107638320c70SHerbert Xu 	aead = crypto_alloc_aead(authenc_name, 0, 0);
107767c44f93SSabrina Dubroca 	err = PTR_ERR(aead);
107867c44f93SSabrina Dubroca 	if (IS_ERR(aead)) {
107938320c70SHerbert Xu 		NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
108067c44f93SSabrina Dubroca 		goto error;
108138320c70SHerbert Xu 	}
10821c5ad13fSMathias Krause 
108338320c70SHerbert Xu 	x->data = aead;
108438320c70SHerbert Xu 
108538320c70SHerbert Xu 	keylen = (x->aalg ? (x->aalg->alg_key_len + 7) / 8 : 0) +
108638320c70SHerbert Xu 		 (x->ealg->alg_key_len + 7) / 8 + RTA_SPACE(sizeof(*param));
108738320c70SHerbert Xu 	err = -ENOMEM;
108838320c70SHerbert Xu 	key = kmalloc(keylen, GFP_KERNEL);
108938320c70SHerbert Xu 	if (!key)
109038320c70SHerbert Xu 		goto error;
109138320c70SHerbert Xu 
109238320c70SHerbert Xu 	p = key;
109338320c70SHerbert Xu 	rta = (void *)p;
109438320c70SHerbert Xu 	rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM;
109538320c70SHerbert Xu 	rta->rta_len = RTA_LENGTH(sizeof(*param));
109638320c70SHerbert Xu 	param = RTA_DATA(rta);
109738320c70SHerbert Xu 	p += RTA_SPACE(sizeof(*param));
10981da177e4SLinus Torvalds 
10991da177e4SLinus Torvalds 	if (x->aalg) {
11001da177e4SLinus Torvalds 		struct xfrm_algo_desc *aalg_desc;
110138320c70SHerbert Xu 
110238320c70SHerbert Xu 		memcpy(p, x->aalg->alg_key, (x->aalg->alg_key_len + 7) / 8);
11031da177e4SLinus Torvalds 		p += (x->aalg->alg_key_len + 7) / 8;
11041da177e4SLinus Torvalds 
11051da177e4SLinus Torvalds 		aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
11061da177e4SLinus Torvalds 		BUG_ON(!aalg_desc);
110738320c70SHerbert Xu 
11081da177e4SLinus Torvalds 		err = -EINVAL;
110938320c70SHerbert Xu 		if (aalg_desc->uinfo.auth.icv_fullbits / 8 !=
111067c44f93SSabrina Dubroca 		    crypto_aead_authsize(aead)) {
111138320c70SHerbert Xu 			NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
11121da177e4SLinus Torvalds 			goto free_key;
11131da177e4SLinus Torvalds 		}
111438320c70SHerbert Xu 
11158f8a088cSMartin Willi 		err = crypto_aead_setauthsize(
111667c44f93SSabrina Dubroca 			aead, x->aalg->alg_trunc_len / 8);
111767c44f93SSabrina Dubroca 		if (err) {
111838320c70SHerbert Xu 			NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations");
11191da177e4SLinus Torvalds 			goto free_key;
112067c44f93SSabrina Dubroca 		}
11214b7137ffSHerbert Xu 	}
112238320c70SHerbert Xu 
112338320c70SHerbert Xu 	param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8);
112438320c70SHerbert Xu 	memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8);
112538320c70SHerbert Xu 
112638320c70SHerbert Xu 	err = crypto_aead_setkey(aead, key, keylen);
112738320c70SHerbert Xu 
1128daa75144SWang Ming free_key:
112938320c70SHerbert Xu 	kfree_sensitive(key);
11301a6509d9SHerbert Xu 
11311a6509d9SHerbert Xu error:
11321a6509d9SHerbert Xu 	return err;
11331a6509d9SHerbert Xu }
1134e1e10b44SSabrina Dubroca 
esp_init_state(struct xfrm_state * x,struct netlink_ext_ack * extack)11351a6509d9SHerbert Xu static int esp_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack)
11361a6509d9SHerbert Xu {
11371a6509d9SHerbert Xu 	struct crypto_aead *aead;
11381a6509d9SHerbert Xu 	u32 align;
11391a6509d9SHerbert Xu 	int err;
11401c5ad13fSMathias Krause 
11411a6509d9SHerbert Xu 	x->data = NULL;
114267c44f93SSabrina Dubroca 
114367c44f93SSabrina Dubroca 	if (x->aead) {
114467c44f93SSabrina Dubroca 		err = esp_init_aead(x, extack);
114567c44f93SSabrina Dubroca 	} else if (x->ealg) {
114667c44f93SSabrina Dubroca 		err = esp_init_authenc(x, extack);
114767c44f93SSabrina Dubroca 	} else {
114867c44f93SSabrina Dubroca 		NL_SET_ERR_MSG(extack, "ESP: AEAD or CRYPT must be provided");
114967c44f93SSabrina Dubroca 		err = -EINVAL;
11501a6509d9SHerbert Xu 	}
115138320c70SHerbert Xu 
11521da177e4SLinus Torvalds 	if (err)
115338320c70SHerbert Xu 		goto error;
11541c5ad13fSMathias Krause 
11551a6509d9SHerbert Xu 	aead = x->data;
115638320c70SHerbert Xu 
115738320c70SHerbert Xu 	x->props.header_len = sizeof(struct ip_esp_hdr) +
11587e49e6deSMasahide NAKAMURA 			      crypto_aead_ivsize(aead);
11591da177e4SLinus Torvalds 	if (x->props.mode == XFRM_MODE_TUNNEL)
1160eb49e630SJoakim Koskela 		x->props.header_len += sizeof(struct iphdr);
1161ac758e3cSPatrick McHardy 	else if (x->props.mode == XFRM_MODE_BEET && x->sel.family != AF_INET6)
11621da177e4SLinus Torvalds 		x->props.header_len += IPV4_BEET_PHMAXLEN;
11631da177e4SLinus Torvalds 	if (x->encap) {
11641da177e4SLinus Torvalds 		struct xfrm_encap_tmpl *encap = x->encap;
11651da177e4SLinus Torvalds 
11661da177e4SLinus Torvalds 		switch (encap->encap_type) {
116767c44f93SSabrina Dubroca 		default:
1168bcfd09f7SHerbert Xu 			NL_SET_ERR_MSG(extack, "Unsupported encapsulation type for ESP");
11691da177e4SLinus Torvalds 			err = -EINVAL;
11701da177e4SLinus Torvalds 			goto error;
11711da177e4SLinus Torvalds 		case UDP_ENCAP_ESPINUDP:
11721da177e4SLinus Torvalds 			x->props.header_len += sizeof(struct udphdr);
1173e27cca96SSabrina Dubroca 			break;
1174e27cca96SSabrina Dubroca #ifdef CONFIG_INET_ESPINTCP
1175e27cca96SSabrina Dubroca 		case TCP_ENCAP_ESPINTCP:
1176e27cca96SSabrina Dubroca 			/* only the length field, TCP encap is done by
1177e27cca96SSabrina Dubroca 			 * the socket
1178e27cca96SSabrina Dubroca 			 */
1179e27cca96SSabrina Dubroca 			x->props.header_len += 2;
1180e27cca96SSabrina Dubroca 			break;
11811da177e4SLinus Torvalds #endif
11821da177e4SLinus Torvalds 		}
118338320c70SHerbert Xu 	}
118438320c70SHerbert Xu 
11851c5ad13fSMathias Krause 	align = ALIGN(crypto_aead_blocksize(aead), 4);
11861da177e4SLinus Torvalds 	x->props.trailer_len = align + 1 + crypto_aead_authsize(aead);
11871da177e4SLinus Torvalds 
118838320c70SHerbert Xu error:
11891da177e4SLinus Torvalds 	return err;
11901da177e4SLinus Torvalds }
1191827789cbSSteffen Klassert 
esp4_rcv_cb(struct sk_buff * skb,int err)1192827789cbSSteffen Klassert static int esp4_rcv_cb(struct sk_buff *skb, int err)
1193827789cbSSteffen Klassert {
1194827789cbSSteffen Klassert 	return 0;
1195827789cbSSteffen Klassert }
1196533cb5b0SEric Dumazet 
11971da177e4SLinus Torvalds static const struct xfrm_type esp_type =
11981da177e4SLinus Torvalds {
11991da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
1200436a0a40SHerbert Xu 	.proto	     	= IPPROTO_ESP,
12011da177e4SLinus Torvalds 	.flags		= XFRM_TYPE_REPLAY_PROT,
12021da177e4SLinus Torvalds 	.init_state	= esp_init_state,
12031da177e4SLinus Torvalds 	.destructor	= esp_destroy,
1204fca11ebdSSteffen Klassert 	.input		= esp_input,
12051da177e4SLinus Torvalds 	.output		= esp_output,
12061da177e4SLinus Torvalds };
1207827789cbSSteffen Klassert 
12081da177e4SLinus Torvalds static struct xfrm4_protocol esp4_protocol = {
1209827789cbSSteffen Klassert 	.handler	=	xfrm4_rcv,
1210827789cbSSteffen Klassert 	.input_handler	=	xfrm_input,
12111da177e4SLinus Torvalds 	.cb_handler	=	esp4_rcv_cb,
1212827789cbSSteffen Klassert 	.err_handler	=	esp4_err,
12131da177e4SLinus Torvalds 	.priority	=	0,
12141da177e4SLinus Torvalds };
12151da177e4SLinus Torvalds 
esp4_init(void)12161da177e4SLinus Torvalds static int __init esp4_init(void)
12171da177e4SLinus Torvalds {
1218058bd4d2SJoe Perches 	if (xfrm_register_type(&esp_type, AF_INET) < 0) {
12191da177e4SLinus Torvalds 		pr_info("%s: can't add xfrm type\n", __func__);
12201da177e4SLinus Torvalds 		return -EAGAIN;
1221827789cbSSteffen Klassert 	}
1222058bd4d2SJoe Perches 	if (xfrm4_protocol_register(&esp4_protocol, IPPROTO_ESP) < 0) {
12231da177e4SLinus Torvalds 		pr_info("%s: can't add protocol\n", __func__);
12241da177e4SLinus Torvalds 		xfrm_unregister_type(&esp_type, AF_INET);
12251da177e4SLinus Torvalds 		return -EAGAIN;
12261da177e4SLinus Torvalds 	}
12271da177e4SLinus Torvalds 	return 0;
12281da177e4SLinus Torvalds }
12291da177e4SLinus Torvalds 
esp4_fini(void)12301da177e4SLinus Torvalds static void __exit esp4_fini(void)
1231827789cbSSteffen Klassert {
1232058bd4d2SJoe Perches 	if (xfrm4_protocol_deregister(&esp4_protocol, IPPROTO_ESP) < 0)
12334f518e80SFlorian Westphal 		pr_info("%s: can't remove protocol\n", __func__);
12341da177e4SLinus Torvalds 	xfrm_unregister_type(&esp_type, AF_INET);
12351da177e4SLinus Torvalds }
12361da177e4SLinus Torvalds 
12371da177e4SLinus Torvalds module_init(esp4_init);
1238b058a5d2SBreno Leitao module_exit(esp4_fini);
12391da177e4SLinus Torvalds MODULE_DESCRIPTION("IPv4 ESP transformation library");
1240d3d6dd3aSMasahide NAKAMURA MODULE_LICENSE("GPL");
1241 MODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_ESP);
1242