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