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