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 */ 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 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 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 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 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 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)) 118959fa5c1SMina Almasry skb_page_unref(sg_page(sg), skb->pp_recycle); 119cac2661cSSteffen Klassert } 120cac2661cSSteffen Klassert 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 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 135e27cca96SSabrina Dubroca static struct sock *esp_find_tcp_sk(struct xfrm_state *x) 136e27cca96SSabrina Dubroca { 137e27cca96SSabrina Dubroca struct xfrm_encap_tmpl *encap = x->encap; 1384461568aSKuniyuki Iwashima 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); 164e27cca96SSabrina Dubroca 1654461568aSKuniyuki Iwashima 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 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 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 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 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 247e27cca96SSabrina Dubroca 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. */ 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 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 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 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 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; 352*447bc4b1SMike 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 364*447bc4b1SMike Yu /* For IPv4 ESP with UDP encapsulation, if xo is not null, the skb is in the crypto offload 365*447bc4b1SMike Yu * data path, which means that esp_output_udp_encap is called outside of the XFRM stack. 366*447bc4b1SMike Yu * In this case, the mac header doesn't point to the IPv4 protocol field, so don't set it. 367*447bc4b1SMike Yu */ 368*447bc4b1SMike 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 375e27cca96SSabrina Dubroca static struct ip_esp_hdr *esp_output_tcp_encap(struct xfrm_state *x, 376e27cca96SSabrina Dubroca struct sk_buff *skb, 377e27cca96SSabrina Dubroca struct esp_info *esp) 378e27cca96SSabrina Dubroca { 379e27cca96SSabrina Dubroca __be16 *lenp = (void *)esp->esph; 380e27cca96SSabrina Dubroca struct ip_esp_hdr *esph; 381e27cca96SSabrina Dubroca unsigned int len; 382e27cca96SSabrina Dubroca struct sock *sk; 383e27cca96SSabrina Dubroca 384e27cca96SSabrina Dubroca len = skb->len + esp->tailen - skb_transport_offset(skb); 385e27cca96SSabrina Dubroca if (len > IP_MAX_MTU) 386e27cca96SSabrina Dubroca return ERR_PTR(-EMSGSIZE); 387e27cca96SSabrina Dubroca 388e27cca96SSabrina Dubroca rcu_read_lock(); 389e27cca96SSabrina Dubroca sk = esp_find_tcp_sk(x); 390e27cca96SSabrina Dubroca rcu_read_unlock(); 391e27cca96SSabrina Dubroca 392e27cca96SSabrina Dubroca if (IS_ERR(sk)) 393e27cca96SSabrina Dubroca return ERR_CAST(sk); 394e27cca96SSabrina Dubroca 395e27cca96SSabrina Dubroca *lenp = htons(len); 396e27cca96SSabrina Dubroca esph = (struct ip_esp_hdr *)(lenp + 1); 397e27cca96SSabrina Dubroca 398e27cca96SSabrina Dubroca return esph; 399e27cca96SSabrina Dubroca } 400e27cca96SSabrina Dubroca #else 401e27cca96SSabrina Dubroca static struct ip_esp_hdr *esp_output_tcp_encap(struct xfrm_state *x, 402e27cca96SSabrina Dubroca struct sk_buff *skb, 403e27cca96SSabrina Dubroca struct esp_info *esp) 404e27cca96SSabrina Dubroca { 405e27cca96SSabrina Dubroca return ERR_PTR(-EOPNOTSUPP); 406e27cca96SSabrina Dubroca } 407e27cca96SSabrina Dubroca #endif 408e27cca96SSabrina Dubroca 409eecd227aSSabrina Dubroca static int esp_output_encap(struct xfrm_state *x, struct sk_buff *skb, 410eecd227aSSabrina Dubroca struct esp_info *esp) 411eecd227aSSabrina Dubroca { 412eecd227aSSabrina Dubroca struct xfrm_encap_tmpl *encap = x->encap; 413eecd227aSSabrina Dubroca struct ip_esp_hdr *esph; 414eecd227aSSabrina Dubroca __be16 sport, dport; 415eecd227aSSabrina Dubroca int encap_type; 416eecd227aSSabrina Dubroca 41738320c70SHerbert Xu spin_lock_bh(&x->lock); 41838320c70SHerbert Xu sport = encap->encap_sport; 41938320c70SHerbert Xu dport = encap->encap_dport; 42038320c70SHerbert Xu encap_type = encap->encap_type; 42138320c70SHerbert Xu spin_unlock_bh(&x->lock); 4221da177e4SLinus Torvalds 42338320c70SHerbert Xu switch (encap_type) { 4241da177e4SLinus Torvalds default: 4251da177e4SLinus Torvalds case UDP_ENCAP_ESPINUDP: 426eecd227aSSabrina Dubroca esph = esp_output_udp_encap(skb, encap_type, esp, sport, dport); 4271da177e4SLinus Torvalds break; 428e27cca96SSabrina Dubroca case TCP_ENCAP_ESPINTCP: 429e27cca96SSabrina Dubroca esph = esp_output_tcp_encap(x, skb, esp); 430e27cca96SSabrina Dubroca break; 4311da177e4SLinus Torvalds } 4321da177e4SLinus Torvalds 433eecd227aSSabrina Dubroca if (IS_ERR(esph)) 434eecd227aSSabrina Dubroca return PTR_ERR(esph); 435eecd227aSSabrina Dubroca 436fca11ebdSSteffen Klassert esp->esph = esph; 4378dfb4ebaSSabrina Dubroca 4388dfb4ebaSSabrina Dubroca return 0; 43937fedd3aSHerbert Xu } 4401da177e4SLinus Torvalds 441fca11ebdSSteffen Klassert int esp_output_head(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *esp) 442fca11ebdSSteffen Klassert { 443fca11ebdSSteffen Klassert u8 *tail; 444fca11ebdSSteffen Klassert int nfrags; 4450e78a873SSteffen Klassert int esph_offset; 446fca11ebdSSteffen Klassert struct page *page; 447fca11ebdSSteffen Klassert struct sk_buff *trailer; 448fca11ebdSSteffen Klassert int tailen = esp->tailen; 449fca11ebdSSteffen Klassert 450e27cca96SSabrina Dubroca /* this is non-NULL only with TCP/UDP Encapsulation */ 4518dfb4ebaSSabrina Dubroca if (x->encap) { 452eecd227aSSabrina Dubroca int err = esp_output_encap(x, skb, esp); 4538dfb4ebaSSabrina Dubroca 4548dfb4ebaSSabrina Dubroca if (err < 0) 4558dfb4ebaSSabrina Dubroca return err; 4568dfb4ebaSSabrina Dubroca } 457fca11ebdSSteffen Klassert 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 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 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 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 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 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 8407021b2e1SHerbert Xu static void esp_input_restore_header(struct sk_buff *skb) 8417021b2e1SHerbert Xu { 8427021b2e1SHerbert Xu esp_restore_header(skb, 0); 8437021b2e1SHerbert Xu __skb_pull(skb, 4); 8447021b2e1SHerbert Xu } 8457021b2e1SHerbert Xu 846cac2661cSSteffen Klassert static void esp_input_set_header(struct sk_buff *skb, __be32 *seqhi) 847cac2661cSSteffen Klassert { 848cac2661cSSteffen Klassert struct xfrm_state *x = xfrm_input_state(skb); 84960aa8046SColin Ian King struct ip_esp_hdr *esph; 850cac2661cSSteffen Klassert 851cac2661cSSteffen Klassert /* For ESN we move the header forward by 4 bytes to 852cbd801b3SLu Wei * accommodate the high bits. We will move it back after 853cac2661cSSteffen Klassert * decryption. 854cac2661cSSteffen Klassert */ 855cac2661cSSteffen Klassert if ((x->props.flags & XFRM_STATE_ESN)) { 856d58ff351SJohannes Berg esph = skb_push(skb, 4); 857cac2661cSSteffen Klassert *seqhi = esph->spi; 858cac2661cSSteffen Klassert esph->spi = esph->seq_no; 859cac2661cSSteffen Klassert esph->seq_no = XFRM_SKB_CB(skb)->seq.input.hi; 860cac2661cSSteffen Klassert } 861cac2661cSSteffen Klassert } 862cac2661cSSteffen Klassert 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 */ 87638320c70SHerbert Xu static int esp_input(struct xfrm_state *x, struct sk_buff *skb) 87738320c70SHerbert Xu { 8781c5ad13fSMathias Krause struct crypto_aead *aead = x->data; 87938320c70SHerbert Xu struct aead_request *req; 88038320c70SHerbert Xu struct sk_buff *trailer; 8817021b2e1SHerbert Xu int ivlen = crypto_aead_ivsize(aead); 8820c05f983SHaishuang Yan int elen = skb->len - sizeof(struct ip_esp_hdr) - ivlen; 88338320c70SHerbert Xu int nfrags; 8840dc49e9bSSteffen Klassert int assoclen; 8850dc49e9bSSteffen Klassert int seqhilen; 8860dc49e9bSSteffen Klassert __be32 *seqhi; 88738320c70SHerbert Xu void *tmp; 88838320c70SHerbert Xu u8 *iv; 88938320c70SHerbert Xu struct scatterlist *sg; 89038320c70SHerbert Xu int err = -EINVAL; 89138320c70SHerbert Xu 8920c05f983SHaishuang Yan if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr) + ivlen)) 89338320c70SHerbert Xu goto out; 89438320c70SHerbert Xu 89538320c70SHerbert Xu if (elen <= 0) 89638320c70SHerbert Xu goto out; 89738320c70SHerbert Xu 8980c05f983SHaishuang Yan assoclen = sizeof(struct ip_esp_hdr); 8990dc49e9bSSteffen Klassert seqhilen = 0; 9000dc49e9bSSteffen Klassert 9010dc49e9bSSteffen Klassert if (x->props.flags & XFRM_STATE_ESN) { 9020dc49e9bSSteffen Klassert seqhilen += sizeof(__be32); 9030dc49e9bSSteffen Klassert assoclen += seqhilen; 9040dc49e9bSSteffen Klassert } 9050dc49e9bSSteffen Klassert 906cac2661cSSteffen Klassert if (!skb_cloned(skb)) { 907cac2661cSSteffen Klassert if (!skb_is_nonlinear(skb)) { 908cac2661cSSteffen Klassert nfrags = 1; 909cac2661cSSteffen Klassert 910cac2661cSSteffen Klassert goto skip_cow; 911cac2661cSSteffen Klassert } else if (!skb_has_frag_list(skb)) { 912cac2661cSSteffen Klassert nfrags = skb_shinfo(skb)->nr_frags; 913cac2661cSSteffen Klassert nfrags++; 914cac2661cSSteffen Klassert 915cac2661cSSteffen Klassert goto skip_cow; 916cac2661cSSteffen Klassert } 917cac2661cSSteffen Klassert } 918cac2661cSSteffen Klassert 919cac2661cSSteffen Klassert err = skb_cow_data(skb, 0, &trailer); 920cac2661cSSteffen Klassert if (err < 0) 921cac2661cSSteffen Klassert goto out; 922cac2661cSSteffen Klassert 923cac2661cSSteffen Klassert nfrags = err; 924cac2661cSSteffen Klassert 925cac2661cSSteffen Klassert skip_cow: 92638320c70SHerbert Xu err = -ENOMEM; 9277021b2e1SHerbert Xu tmp = esp_alloc_tmp(aead, nfrags, seqhilen); 92838320c70SHerbert Xu if (!tmp) 92938320c70SHerbert Xu goto out; 93038320c70SHerbert Xu 93138320c70SHerbert Xu ESP_SKB_CB(skb)->tmp = tmp; 932962fcef3SHerbert Xu seqhi = esp_tmp_extra(tmp); 9330dc49e9bSSteffen Klassert iv = esp_tmp_iv(aead, tmp, seqhilen); 93438320c70SHerbert Xu req = esp_tmp_req(aead, iv); 9357021b2e1SHerbert Xu sg = esp_req_sg(aead, req); 93638320c70SHerbert Xu 937cac2661cSSteffen Klassert esp_input_set_header(skb, seqhi); 93838320c70SHerbert Xu 93938320c70SHerbert Xu sg_init_table(sg, nfrags); 9403f297707SJason A. Donenfeld err = skb_to_sgvec(skb, sg, 0, skb->len); 941e6194923SSteffen Klassert if (unlikely(err < 0)) { 942e6194923SSteffen Klassert kfree(tmp); 9433f297707SJason A. Donenfeld goto out; 944e6194923SSteffen Klassert } 9450dc49e9bSSteffen Klassert 946cac2661cSSteffen Klassert skb->ip_summed = CHECKSUM_NONE; 947cac2661cSSteffen Klassert 948cac2661cSSteffen Klassert if ((x->props.flags & XFRM_STATE_ESN)) 949cac2661cSSteffen Klassert aead_request_set_callback(req, 0, esp_input_done_esn, skb); 950cac2661cSSteffen Klassert else 951cac2661cSSteffen Klassert aead_request_set_callback(req, 0, esp_input_done, skb); 952cac2661cSSteffen Klassert 9537021b2e1SHerbert Xu aead_request_set_crypt(req, sg, sg, elen + ivlen, iv); 9547021b2e1SHerbert Xu aead_request_set_ad(req, assoclen); 95538320c70SHerbert Xu 95638320c70SHerbert Xu err = crypto_aead_decrypt(req); 95738320c70SHerbert Xu if (err == -EINPROGRESS) 95838320c70SHerbert Xu goto out; 95938320c70SHerbert Xu 9607021b2e1SHerbert Xu if ((x->props.flags & XFRM_STATE_ESN)) 9617021b2e1SHerbert Xu esp_input_restore_header(skb); 9627021b2e1SHerbert Xu 96338320c70SHerbert Xu err = esp_input_done2(skb, err); 964752c1f4cSHerbert Xu 965752c1f4cSHerbert Xu out: 966668dc8afSHerbert Xu return err; 9671da177e4SLinus Torvalds } 9681da177e4SLinus Torvalds 969827789cbSSteffen Klassert static int esp4_err(struct sk_buff *skb, u32 info) 9701da177e4SLinus Torvalds { 9714fb236baSAlexey Dobriyan struct net *net = dev_net(skb->dev); 972b71d1d42SEric Dumazet const struct iphdr *iph = (const struct iphdr *)skb->data; 9731da177e4SLinus Torvalds struct ip_esp_hdr *esph = (struct ip_esp_hdr *)(skb->data+(iph->ihl<<2)); 9741da177e4SLinus Torvalds struct xfrm_state *x; 9751da177e4SLinus Torvalds 97655be7a9cSDavid S. Miller switch (icmp_hdr(skb)->type) { 97755be7a9cSDavid S. Miller case ICMP_DEST_UNREACH: 97855be7a9cSDavid S. Miller if (icmp_hdr(skb)->code != ICMP_FRAG_NEEDED) 979827789cbSSteffen Klassert return 0; 98079121184SGustavo A. R. Silva break; 98155be7a9cSDavid S. Miller case ICMP_REDIRECT: 98255be7a9cSDavid S. Miller break; 98355be7a9cSDavid S. Miller default: 984827789cbSSteffen Klassert return 0; 98555be7a9cSDavid S. Miller } 9861da177e4SLinus Torvalds 987b71d1d42SEric Dumazet x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr, 988b71d1d42SEric Dumazet esph->spi, IPPROTO_ESP, AF_INET); 9891da177e4SLinus Torvalds if (!x) 990827789cbSSteffen Klassert return 0; 99155be7a9cSDavid S. Miller 992387aa65aSTimo Teräs if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) 993d888f396SMaciej Żenczykowski ipv4_update_pmtu(skb, net, info, 0, IPPROTO_ESP); 994387aa65aSTimo Teräs else 9951042caa7SMaciej Żenczykowski ipv4_redirect(skb, net, 0, IPPROTO_ESP); 9961da177e4SLinus Torvalds xfrm_state_put(x); 997827789cbSSteffen Klassert 998827789cbSSteffen Klassert return 0; 9991da177e4SLinus Torvalds } 10001da177e4SLinus Torvalds 10011da177e4SLinus Torvalds static void esp_destroy(struct xfrm_state *x) 10021da177e4SLinus Torvalds { 10031c5ad13fSMathias Krause struct crypto_aead *aead = x->data; 10041da177e4SLinus Torvalds 10051c5ad13fSMathias Krause if (!aead) 10061da177e4SLinus Torvalds return; 10071da177e4SLinus Torvalds 10081c5ad13fSMathias Krause crypto_free_aead(aead); 10091da177e4SLinus Torvalds } 10101da177e4SLinus Torvalds 101167c44f93SSabrina Dubroca static int esp_init_aead(struct xfrm_state *x, struct netlink_ext_ack *extack) 10121da177e4SLinus Torvalds { 10137021b2e1SHerbert Xu char aead_name[CRYPTO_MAX_ALG_NAME]; 10141a6509d9SHerbert Xu struct crypto_aead *aead; 10151a6509d9SHerbert Xu int err; 10161a6509d9SHerbert Xu 10177021b2e1SHerbert Xu if (snprintf(aead_name, CRYPTO_MAX_ALG_NAME, "%s(%s)", 101867c44f93SSabrina Dubroca x->geniv, x->aead->alg_name) >= CRYPTO_MAX_ALG_NAME) { 101967c44f93SSabrina Dubroca NL_SET_ERR_MSG(extack, "Algorithm name is too long"); 102067c44f93SSabrina Dubroca return -ENAMETOOLONG; 102167c44f93SSabrina Dubroca } 10227021b2e1SHerbert Xu 1023f58869c4SSteffen Klassert aead = crypto_alloc_aead(aead_name, 0, 0); 10241a6509d9SHerbert Xu err = PTR_ERR(aead); 10251a6509d9SHerbert Xu if (IS_ERR(aead)) 10261a6509d9SHerbert Xu goto error; 10271a6509d9SHerbert Xu 10281c5ad13fSMathias Krause x->data = aead; 10291a6509d9SHerbert Xu 10301a6509d9SHerbert Xu err = crypto_aead_setkey(aead, x->aead->alg_key, 10311a6509d9SHerbert Xu (x->aead->alg_key_len + 7) / 8); 10321a6509d9SHerbert Xu if (err) 10331a6509d9SHerbert Xu goto error; 10341a6509d9SHerbert Xu 10351a6509d9SHerbert Xu err = crypto_aead_setauthsize(aead, x->aead->alg_icv_len / 8); 10361a6509d9SHerbert Xu if (err) 10371a6509d9SHerbert Xu goto error; 10381a6509d9SHerbert Xu 103967c44f93SSabrina Dubroca return 0; 104067c44f93SSabrina Dubroca 10411a6509d9SHerbert Xu error: 104267c44f93SSabrina Dubroca NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations"); 10431a6509d9SHerbert Xu return err; 10441a6509d9SHerbert Xu } 10451a6509d9SHerbert Xu 104667c44f93SSabrina Dubroca static int esp_init_authenc(struct xfrm_state *x, 104767c44f93SSabrina Dubroca struct netlink_ext_ack *extack) 10481a6509d9SHerbert Xu { 104938320c70SHerbert Xu struct crypto_aead *aead; 105038320c70SHerbert Xu struct crypto_authenc_key_param *param; 105138320c70SHerbert Xu struct rtattr *rta; 105238320c70SHerbert Xu char *key; 105338320c70SHerbert Xu char *p; 105438320c70SHerbert Xu char authenc_name[CRYPTO_MAX_ALG_NAME]; 105538320c70SHerbert Xu unsigned int keylen; 105638320c70SHerbert Xu int err; 10571da177e4SLinus Torvalds 10581a6509d9SHerbert Xu err = -ENAMETOOLONG; 10590dc49e9bSSteffen Klassert 10600dc49e9bSSteffen Klassert if ((x->props.flags & XFRM_STATE_ESN)) { 10610dc49e9bSSteffen Klassert if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, 10627021b2e1SHerbert Xu "%s%sauthencesn(%s,%s)%s", 10637021b2e1SHerbert Xu x->geniv ?: "", x->geniv ? "(" : "", 106438320c70SHerbert Xu x->aalg ? x->aalg->alg_name : "digest_null", 10657021b2e1SHerbert Xu x->ealg->alg_name, 106667c44f93SSabrina Dubroca x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME) { 106767c44f93SSabrina Dubroca NL_SET_ERR_MSG(extack, "Algorithm name is too long"); 10681a6509d9SHerbert Xu goto error; 106967c44f93SSabrina Dubroca } 10700dc49e9bSSteffen Klassert } else { 10710dc49e9bSSteffen Klassert if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, 10727021b2e1SHerbert Xu "%s%sauthenc(%s,%s)%s", 10737021b2e1SHerbert Xu x->geniv ?: "", x->geniv ? "(" : "", 10740dc49e9bSSteffen Klassert x->aalg ? x->aalg->alg_name : "digest_null", 10757021b2e1SHerbert Xu x->ealg->alg_name, 107667c44f93SSabrina Dubroca x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME) { 107767c44f93SSabrina Dubroca NL_SET_ERR_MSG(extack, "Algorithm name is too long"); 10780dc49e9bSSteffen Klassert goto error; 10790dc49e9bSSteffen Klassert } 108067c44f93SSabrina Dubroca } 108138320c70SHerbert Xu 1082f58869c4SSteffen Klassert aead = crypto_alloc_aead(authenc_name, 0, 0); 108338320c70SHerbert Xu err = PTR_ERR(aead); 108467c44f93SSabrina Dubroca if (IS_ERR(aead)) { 108567c44f93SSabrina Dubroca NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations"); 108638320c70SHerbert Xu goto error; 108767c44f93SSabrina Dubroca } 108838320c70SHerbert Xu 10891c5ad13fSMathias Krause x->data = aead; 109038320c70SHerbert Xu 109138320c70SHerbert Xu keylen = (x->aalg ? (x->aalg->alg_key_len + 7) / 8 : 0) + 109238320c70SHerbert Xu (x->ealg->alg_key_len + 7) / 8 + RTA_SPACE(sizeof(*param)); 109338320c70SHerbert Xu err = -ENOMEM; 109438320c70SHerbert Xu key = kmalloc(keylen, GFP_KERNEL); 109538320c70SHerbert Xu if (!key) 109638320c70SHerbert Xu goto error; 109738320c70SHerbert Xu 109838320c70SHerbert Xu p = key; 109938320c70SHerbert Xu rta = (void *)p; 110038320c70SHerbert Xu rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM; 110138320c70SHerbert Xu rta->rta_len = RTA_LENGTH(sizeof(*param)); 110238320c70SHerbert Xu param = RTA_DATA(rta); 110338320c70SHerbert Xu p += RTA_SPACE(sizeof(*param)); 110438320c70SHerbert Xu 11051da177e4SLinus Torvalds if (x->aalg) { 11061da177e4SLinus Torvalds struct xfrm_algo_desc *aalg_desc; 11071da177e4SLinus Torvalds 110838320c70SHerbert Xu memcpy(p, x->aalg->alg_key, (x->aalg->alg_key_len + 7) / 8); 110938320c70SHerbert Xu p += (x->aalg->alg_key_len + 7) / 8; 11101da177e4SLinus Torvalds 11111da177e4SLinus Torvalds aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0); 11121da177e4SLinus Torvalds BUG_ON(!aalg_desc); 11131da177e4SLinus Torvalds 111438320c70SHerbert Xu err = -EINVAL; 11151da177e4SLinus Torvalds if (aalg_desc->uinfo.auth.icv_fullbits / 8 != 111638320c70SHerbert Xu crypto_aead_authsize(aead)) { 111767c44f93SSabrina Dubroca NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations"); 111838320c70SHerbert Xu goto free_key; 11191da177e4SLinus Torvalds } 11201da177e4SLinus Torvalds 112138320c70SHerbert Xu err = crypto_aead_setauthsize( 11228f8a088cSMartin Willi aead, x->aalg->alg_trunc_len / 8); 112367c44f93SSabrina Dubroca if (err) { 112467c44f93SSabrina Dubroca NL_SET_ERR_MSG(extack, "Kernel was unable to initialize cryptographic operations"); 112538320c70SHerbert Xu goto free_key; 11261da177e4SLinus Torvalds } 112767c44f93SSabrina Dubroca } 11284b7137ffSHerbert Xu 112938320c70SHerbert Xu param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8); 113038320c70SHerbert Xu memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8); 113138320c70SHerbert Xu 113238320c70SHerbert Xu err = crypto_aead_setkey(aead, key, keylen); 113338320c70SHerbert Xu 113438320c70SHerbert Xu free_key: 1135daa75144SWang Ming kfree_sensitive(key); 113638320c70SHerbert Xu 11371a6509d9SHerbert Xu error: 11381a6509d9SHerbert Xu return err; 11391a6509d9SHerbert Xu } 11401a6509d9SHerbert Xu 1141e1e10b44SSabrina Dubroca static int esp_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack) 11421a6509d9SHerbert Xu { 11431a6509d9SHerbert Xu struct crypto_aead *aead; 11441a6509d9SHerbert Xu u32 align; 11451a6509d9SHerbert Xu int err; 11461a6509d9SHerbert Xu 11471c5ad13fSMathias Krause x->data = NULL; 11481a6509d9SHerbert Xu 114967c44f93SSabrina Dubroca if (x->aead) { 115067c44f93SSabrina Dubroca err = esp_init_aead(x, extack); 115167c44f93SSabrina Dubroca } else if (x->ealg) { 115267c44f93SSabrina Dubroca err = esp_init_authenc(x, extack); 115367c44f93SSabrina Dubroca } else { 115467c44f93SSabrina Dubroca NL_SET_ERR_MSG(extack, "ESP: AEAD or CRYPT must be provided"); 115567c44f93SSabrina Dubroca err = -EINVAL; 115667c44f93SSabrina Dubroca } 11571a6509d9SHerbert Xu 115838320c70SHerbert Xu if (err) 11591da177e4SLinus Torvalds goto error; 116038320c70SHerbert Xu 11611c5ad13fSMathias Krause aead = x->data; 11621a6509d9SHerbert Xu 116338320c70SHerbert Xu x->props.header_len = sizeof(struct ip_esp_hdr) + 116438320c70SHerbert Xu crypto_aead_ivsize(aead); 11657e49e6deSMasahide NAKAMURA if (x->props.mode == XFRM_MODE_TUNNEL) 11661da177e4SLinus Torvalds x->props.header_len += sizeof(struct iphdr); 1167eb49e630SJoakim Koskela else if (x->props.mode == XFRM_MODE_BEET && x->sel.family != AF_INET6) 1168ac758e3cSPatrick McHardy x->props.header_len += IPV4_BEET_PHMAXLEN; 11691da177e4SLinus Torvalds if (x->encap) { 11701da177e4SLinus Torvalds struct xfrm_encap_tmpl *encap = x->encap; 11711da177e4SLinus Torvalds 11721da177e4SLinus Torvalds switch (encap->encap_type) { 11731da177e4SLinus Torvalds default: 117467c44f93SSabrina Dubroca NL_SET_ERR_MSG(extack, "Unsupported encapsulation type for ESP"); 1175bcfd09f7SHerbert Xu err = -EINVAL; 11761da177e4SLinus Torvalds goto error; 11771da177e4SLinus Torvalds case UDP_ENCAP_ESPINUDP: 11781da177e4SLinus Torvalds x->props.header_len += sizeof(struct udphdr); 11791da177e4SLinus Torvalds break; 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 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 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 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