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; 137e27cca96SSabrina Dubroca struct esp_tcp_sk *esk; 138e27cca96SSabrina Dubroca __be16 sport, dport; 139e27cca96SSabrina Dubroca struct sock *nsk; 140e27cca96SSabrina Dubroca struct sock *sk; 141e27cca96SSabrina Dubroca 142e27cca96SSabrina Dubroca sk = rcu_dereference(x->encap_sk); 143e27cca96SSabrina Dubroca if (sk && sk->sk_state == TCP_ESTABLISHED) 144e27cca96SSabrina Dubroca return sk; 145e27cca96SSabrina Dubroca 146e27cca96SSabrina Dubroca spin_lock_bh(&x->lock); 147e27cca96SSabrina Dubroca sport = encap->encap_sport; 148e27cca96SSabrina Dubroca dport = encap->encap_dport; 149e27cca96SSabrina Dubroca nsk = rcu_dereference_protected(x->encap_sk, 150e27cca96SSabrina Dubroca lockdep_is_held(&x->lock)); 151e27cca96SSabrina Dubroca if (sk && sk == nsk) { 152e27cca96SSabrina Dubroca esk = kmalloc(sizeof(*esk), GFP_ATOMIC); 153e27cca96SSabrina Dubroca if (!esk) { 154e27cca96SSabrina Dubroca spin_unlock_bh(&x->lock); 155e27cca96SSabrina Dubroca return ERR_PTR(-ENOMEM); 156e27cca96SSabrina Dubroca } 157e27cca96SSabrina Dubroca RCU_INIT_POINTER(x->encap_sk, NULL); 158e27cca96SSabrina Dubroca esk->sk = sk; 159e27cca96SSabrina Dubroca call_rcu(&esk->rcu, esp_free_tcp_sk); 160e27cca96SSabrina Dubroca } 161e27cca96SSabrina Dubroca spin_unlock_bh(&x->lock); 162e27cca96SSabrina Dubroca 163e27cca96SSabrina Dubroca sk = inet_lookup_established(xs_net(x), &tcp_hashinfo, x->id.daddr.a4, 164e27cca96SSabrina Dubroca dport, x->props.saddr.a4, sport, 0); 165e27cca96SSabrina Dubroca if (!sk) 166e27cca96SSabrina Dubroca return ERR_PTR(-ENOENT); 167e27cca96SSabrina Dubroca 168e27cca96SSabrina Dubroca if (!tcp_is_ulp_esp(sk)) { 169e27cca96SSabrina Dubroca sock_put(sk); 170e27cca96SSabrina Dubroca return ERR_PTR(-EINVAL); 171e27cca96SSabrina Dubroca } 172e27cca96SSabrina Dubroca 173e27cca96SSabrina Dubroca spin_lock_bh(&x->lock); 174e27cca96SSabrina Dubroca nsk = rcu_dereference_protected(x->encap_sk, 175e27cca96SSabrina Dubroca lockdep_is_held(&x->lock)); 176e27cca96SSabrina Dubroca if (encap->encap_sport != sport || 177e27cca96SSabrina Dubroca encap->encap_dport != dport) { 178e27cca96SSabrina Dubroca sock_put(sk); 179e27cca96SSabrina Dubroca sk = nsk ?: ERR_PTR(-EREMCHG); 180e27cca96SSabrina Dubroca } else if (sk == nsk) { 181e27cca96SSabrina Dubroca sock_put(sk); 182e27cca96SSabrina Dubroca } else { 183e27cca96SSabrina Dubroca rcu_assign_pointer(x->encap_sk, sk); 184e27cca96SSabrina Dubroca } 185e27cca96SSabrina Dubroca spin_unlock_bh(&x->lock); 186e27cca96SSabrina Dubroca 187e27cca96SSabrina Dubroca return sk; 188e27cca96SSabrina Dubroca } 189e27cca96SSabrina Dubroca 190e27cca96SSabrina Dubroca static int esp_output_tcp_finish(struct xfrm_state *x, struct sk_buff *skb) 191e27cca96SSabrina Dubroca { 192e27cca96SSabrina Dubroca struct sock *sk; 193e27cca96SSabrina Dubroca int err; 194e27cca96SSabrina Dubroca 195e27cca96SSabrina Dubroca rcu_read_lock(); 196e27cca96SSabrina Dubroca 197e27cca96SSabrina Dubroca sk = esp_find_tcp_sk(x); 198e27cca96SSabrina Dubroca err = PTR_ERR_OR_ZERO(sk); 199e27cca96SSabrina Dubroca if (err) 200e27cca96SSabrina Dubroca goto out; 201e27cca96SSabrina Dubroca 202e27cca96SSabrina Dubroca bh_lock_sock(sk); 203e27cca96SSabrina Dubroca if (sock_owned_by_user(sk)) 204e27cca96SSabrina Dubroca err = espintcp_queue_out(sk, skb); 205e27cca96SSabrina Dubroca else 206e27cca96SSabrina Dubroca err = espintcp_push_skb(sk, skb); 207e27cca96SSabrina Dubroca bh_unlock_sock(sk); 208e27cca96SSabrina Dubroca 209e27cca96SSabrina Dubroca out: 210e27cca96SSabrina Dubroca rcu_read_unlock(); 211e27cca96SSabrina Dubroca return err; 212e27cca96SSabrina Dubroca } 213e27cca96SSabrina Dubroca 214e27cca96SSabrina Dubroca static int esp_output_tcp_encap_cb(struct net *net, struct sock *sk, 215e27cca96SSabrina Dubroca struct sk_buff *skb) 216e27cca96SSabrina Dubroca { 217e27cca96SSabrina Dubroca struct dst_entry *dst = skb_dst(skb); 218e27cca96SSabrina Dubroca struct xfrm_state *x = dst->xfrm; 219e27cca96SSabrina Dubroca 220e27cca96SSabrina Dubroca return esp_output_tcp_finish(x, skb); 221e27cca96SSabrina Dubroca } 222e27cca96SSabrina Dubroca 223e27cca96SSabrina Dubroca static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb) 224e27cca96SSabrina Dubroca { 225e27cca96SSabrina Dubroca int err; 226e27cca96SSabrina Dubroca 227e27cca96SSabrina Dubroca local_bh_disable(); 228e27cca96SSabrina Dubroca err = xfrm_trans_queue_net(xs_net(x), skb, esp_output_tcp_encap_cb); 229e27cca96SSabrina Dubroca local_bh_enable(); 230e27cca96SSabrina Dubroca 231e27cca96SSabrina Dubroca /* EINPROGRESS just happens to do the right thing. It 232e27cca96SSabrina Dubroca * actually means that the skb has been consumed and 233e27cca96SSabrina Dubroca * isn't coming back. 234e27cca96SSabrina Dubroca */ 235e27cca96SSabrina Dubroca return err ?: -EINPROGRESS; 236e27cca96SSabrina Dubroca } 237e27cca96SSabrina Dubroca #else 238e27cca96SSabrina Dubroca static int esp_output_tail_tcp(struct xfrm_state *x, struct sk_buff *skb) 239e27cca96SSabrina Dubroca { 240e27cca96SSabrina Dubroca kfree_skb(skb); 241e27cca96SSabrina Dubroca 242e27cca96SSabrina Dubroca return -EOPNOTSUPP; 243e27cca96SSabrina Dubroca } 244e27cca96SSabrina Dubroca #endif 245e27cca96SSabrina Dubroca 24638320c70SHerbert Xu static void esp_output_done(struct crypto_async_request *base, int err) 24738320c70SHerbert Xu { 24838320c70SHerbert Xu struct sk_buff *skb = base->data; 249f53c7239SSteffen Klassert struct xfrm_offload *xo = xfrm_offload(skb); 250cac2661cSSteffen Klassert void *tmp; 251f53c7239SSteffen Klassert struct xfrm_state *x; 252f53c7239SSteffen Klassert 2532294be0fSFlorian Westphal if (xo && (xo->flags & XFRM_DEV_RESUME)) { 2542294be0fSFlorian Westphal struct sec_path *sp = skb_sec_path(skb); 2552294be0fSFlorian Westphal 2562294be0fSFlorian Westphal x = sp->xvec[sp->len - 1]; 2572294be0fSFlorian Westphal } else { 258f53c7239SSteffen Klassert x = skb_dst(skb)->xfrm; 2592294be0fSFlorian Westphal } 26038320c70SHerbert Xu 261cac2661cSSteffen Klassert tmp = ESP_SKB_CB(skb)->tmp; 262cac2661cSSteffen Klassert esp_ssg_unref(x, tmp); 263cac2661cSSteffen Klassert kfree(tmp); 264f53c7239SSteffen Klassert 265f53c7239SSteffen Klassert if (xo && (xo->flags & XFRM_DEV_RESUME)) { 266f53c7239SSteffen Klassert if (err) { 267f53c7239SSteffen Klassert XFRM_INC_STATS(xs_net(x), LINUX_MIB_XFRMOUTSTATEPROTOERROR); 268f53c7239SSteffen Klassert kfree_skb(skb); 269f53c7239SSteffen Klassert return; 270f53c7239SSteffen Klassert } 271f53c7239SSteffen Klassert 272f53c7239SSteffen Klassert skb_push(skb, skb->data - skb_mac_header(skb)); 273f53c7239SSteffen Klassert secpath_reset(skb); 274f53c7239SSteffen Klassert xfrm_dev_resume(skb); 275f53c7239SSteffen Klassert } else { 276e27cca96SSabrina Dubroca if (!err && 277e27cca96SSabrina Dubroca x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP) 278e27cca96SSabrina Dubroca esp_output_tail_tcp(x, skb); 279e27cca96SSabrina Dubroca else 2809ab1265dSEvan Nimmo xfrm_output_resume(skb->sk, skb, err); 28138320c70SHerbert Xu } 282f53c7239SSteffen Klassert } 28338320c70SHerbert Xu 2847021b2e1SHerbert Xu /* Move ESP header back into place. */ 2857021b2e1SHerbert Xu static void esp_restore_header(struct sk_buff *skb, unsigned int offset) 2867021b2e1SHerbert Xu { 2877021b2e1SHerbert Xu struct ip_esp_hdr *esph = (void *)(skb->data + offset); 2887021b2e1SHerbert Xu void *tmp = ESP_SKB_CB(skb)->tmp; 289962fcef3SHerbert Xu __be32 *seqhi = esp_tmp_extra(tmp); 2907021b2e1SHerbert Xu 2917021b2e1SHerbert Xu esph->seq_no = esph->spi; 2927021b2e1SHerbert Xu esph->spi = *seqhi; 2937021b2e1SHerbert Xu } 2947021b2e1SHerbert Xu 2957021b2e1SHerbert Xu static void esp_output_restore_header(struct sk_buff *skb) 2967021b2e1SHerbert Xu { 297962fcef3SHerbert Xu void *tmp = ESP_SKB_CB(skb)->tmp; 298962fcef3SHerbert Xu struct esp_output_extra *extra = esp_tmp_extra(tmp); 299962fcef3SHerbert Xu 300962fcef3SHerbert Xu esp_restore_header(skb, skb_transport_offset(skb) + extra->esphoff - 301962fcef3SHerbert Xu sizeof(__be32)); 3027021b2e1SHerbert Xu } 3037021b2e1SHerbert Xu 304cac2661cSSteffen Klassert static struct ip_esp_hdr *esp_output_set_extra(struct sk_buff *skb, 305fca11ebdSSteffen Klassert struct xfrm_state *x, 306cac2661cSSteffen Klassert struct ip_esp_hdr *esph, 307cac2661cSSteffen Klassert struct esp_output_extra *extra) 308cac2661cSSteffen Klassert { 309cac2661cSSteffen Klassert /* For ESN we move the header forward by 4 bytes to 310cbd801b3SLu Wei * accommodate the high bits. We will move it back after 311cac2661cSSteffen Klassert * encryption. 312cac2661cSSteffen Klassert */ 313cac2661cSSteffen Klassert if ((x->props.flags & XFRM_STATE_ESN)) { 3147862b405SSteffen Klassert __u32 seqhi; 3157862b405SSteffen Klassert struct xfrm_offload *xo = xfrm_offload(skb); 3167862b405SSteffen Klassert 3177862b405SSteffen Klassert if (xo) 3187862b405SSteffen Klassert seqhi = xo->seq.hi; 3197862b405SSteffen Klassert else 3207862b405SSteffen Klassert seqhi = XFRM_SKB_CB(skb)->seq.output.hi; 3217862b405SSteffen Klassert 322cac2661cSSteffen Klassert extra->esphoff = (unsigned char *)esph - 323cac2661cSSteffen Klassert skb_transport_header(skb); 324cac2661cSSteffen Klassert esph = (struct ip_esp_hdr *)((unsigned char *)esph - 4); 325cac2661cSSteffen Klassert extra->seqhi = esph->spi; 3267862b405SSteffen Klassert esph->seq_no = htonl(seqhi); 327cac2661cSSteffen Klassert } 328cac2661cSSteffen Klassert 329cac2661cSSteffen Klassert esph->spi = x->id.spi; 330cac2661cSSteffen Klassert 331cac2661cSSteffen Klassert return esph; 332cac2661cSSteffen Klassert } 333cac2661cSSteffen Klassert 3347021b2e1SHerbert Xu static void esp_output_done_esn(struct crypto_async_request *base, int err) 3357021b2e1SHerbert Xu { 3367021b2e1SHerbert Xu struct sk_buff *skb = base->data; 3377021b2e1SHerbert Xu 3387021b2e1SHerbert Xu esp_output_restore_header(skb); 3397021b2e1SHerbert Xu esp_output_done(base, err); 3407021b2e1SHerbert Xu } 3417021b2e1SHerbert Xu 342eecd227aSSabrina Dubroca static struct ip_esp_hdr *esp_output_udp_encap(struct sk_buff *skb, 343eecd227aSSabrina Dubroca int encap_type, 344eecd227aSSabrina Dubroca struct esp_info *esp, 345eecd227aSSabrina Dubroca __be16 sport, 346eecd227aSSabrina Dubroca __be16 dport) 3471da177e4SLinus Torvalds { 3481da177e4SLinus Torvalds struct udphdr *uh; 349d5a0a1e3SAl Viro __be32 *udpdata32; 3508dfb4ebaSSabrina Dubroca unsigned int len; 35138320c70SHerbert Xu 352eecd227aSSabrina Dubroca len = skb->len + esp->tailen - skb_transport_offset(skb); 353e27cca96SSabrina Dubroca if (len + sizeof(struct iphdr) > IP_MAX_MTU) 354eecd227aSSabrina Dubroca return ERR_PTR(-EMSGSIZE); 355eecd227aSSabrina Dubroca 356eecd227aSSabrina Dubroca uh = (struct udphdr *)esp->esph; 357eecd227aSSabrina Dubroca uh->source = sport; 358eecd227aSSabrina Dubroca uh->dest = dport; 359eecd227aSSabrina Dubroca uh->len = htons(len); 360eecd227aSSabrina Dubroca uh->check = 0; 361eecd227aSSabrina Dubroca 362eecd227aSSabrina Dubroca *skb_mac_header(skb) = IPPROTO_UDP; 363eecd227aSSabrina Dubroca 364eecd227aSSabrina Dubroca if (encap_type == UDP_ENCAP_ESPINUDP_NON_IKE) { 365eecd227aSSabrina Dubroca udpdata32 = (__be32 *)(uh + 1); 366eecd227aSSabrina Dubroca udpdata32[0] = udpdata32[1] = 0; 367eecd227aSSabrina Dubroca return (struct ip_esp_hdr *)(udpdata32 + 2); 368eecd227aSSabrina Dubroca } 369eecd227aSSabrina Dubroca 370eecd227aSSabrina Dubroca return (struct ip_esp_hdr *)(uh + 1); 371eecd227aSSabrina Dubroca } 372eecd227aSSabrina Dubroca 373e27cca96SSabrina Dubroca #ifdef CONFIG_INET_ESPINTCP 374e27cca96SSabrina Dubroca static struct ip_esp_hdr *esp_output_tcp_encap(struct xfrm_state *x, 375e27cca96SSabrina Dubroca struct sk_buff *skb, 376e27cca96SSabrina Dubroca struct esp_info *esp) 377e27cca96SSabrina Dubroca { 378e27cca96SSabrina Dubroca __be16 *lenp = (void *)esp->esph; 379e27cca96SSabrina Dubroca struct ip_esp_hdr *esph; 380e27cca96SSabrina Dubroca unsigned int len; 381e27cca96SSabrina Dubroca struct sock *sk; 382e27cca96SSabrina Dubroca 383e27cca96SSabrina Dubroca len = skb->len + esp->tailen - skb_transport_offset(skb); 384e27cca96SSabrina Dubroca if (len > IP_MAX_MTU) 385e27cca96SSabrina Dubroca return ERR_PTR(-EMSGSIZE); 386e27cca96SSabrina Dubroca 387e27cca96SSabrina Dubroca rcu_read_lock(); 388e27cca96SSabrina Dubroca sk = esp_find_tcp_sk(x); 389e27cca96SSabrina Dubroca rcu_read_unlock(); 390e27cca96SSabrina Dubroca 391e27cca96SSabrina Dubroca if (IS_ERR(sk)) 392e27cca96SSabrina Dubroca return ERR_CAST(sk); 393e27cca96SSabrina Dubroca 394e27cca96SSabrina Dubroca *lenp = htons(len); 395e27cca96SSabrina Dubroca esph = (struct ip_esp_hdr *)(lenp + 1); 396e27cca96SSabrina Dubroca 397e27cca96SSabrina Dubroca return esph; 398e27cca96SSabrina Dubroca } 399e27cca96SSabrina Dubroca #else 400e27cca96SSabrina Dubroca static struct ip_esp_hdr *esp_output_tcp_encap(struct xfrm_state *x, 401e27cca96SSabrina Dubroca struct sk_buff *skb, 402e27cca96SSabrina Dubroca struct esp_info *esp) 403e27cca96SSabrina Dubroca { 404e27cca96SSabrina Dubroca return ERR_PTR(-EOPNOTSUPP); 405e27cca96SSabrina Dubroca } 406e27cca96SSabrina Dubroca #endif 407e27cca96SSabrina Dubroca 408eecd227aSSabrina Dubroca static int esp_output_encap(struct xfrm_state *x, struct sk_buff *skb, 409eecd227aSSabrina Dubroca struct esp_info *esp) 410eecd227aSSabrina Dubroca { 411eecd227aSSabrina Dubroca struct xfrm_encap_tmpl *encap = x->encap; 412eecd227aSSabrina Dubroca struct ip_esp_hdr *esph; 413eecd227aSSabrina Dubroca __be16 sport, dport; 414eecd227aSSabrina Dubroca int encap_type; 415eecd227aSSabrina Dubroca 41638320c70SHerbert Xu spin_lock_bh(&x->lock); 41738320c70SHerbert Xu sport = encap->encap_sport; 41838320c70SHerbert Xu dport = encap->encap_dport; 41938320c70SHerbert Xu encap_type = encap->encap_type; 42038320c70SHerbert Xu spin_unlock_bh(&x->lock); 4211da177e4SLinus Torvalds 42238320c70SHerbert Xu switch (encap_type) { 4231da177e4SLinus Torvalds default: 4241da177e4SLinus Torvalds case UDP_ENCAP_ESPINUDP: 4251da177e4SLinus Torvalds case UDP_ENCAP_ESPINUDP_NON_IKE: 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 458cac2661cSSteffen Klassert if (!skb_cloned(skb)) { 45954ffd790SSteffen Klassert if (tailen <= skb_tailroom(skb)) { 460cac2661cSSteffen Klassert nfrags = 1; 461cac2661cSSteffen Klassert trailer = skb; 462cac2661cSSteffen Klassert tail = skb_tail_pointer(trailer); 4631da177e4SLinus Torvalds 464cac2661cSSteffen Klassert goto skip_cow; 465cac2661cSSteffen Klassert } else if ((skb_shinfo(skb)->nr_frags < MAX_SKB_FRAGS) 466cac2661cSSteffen Klassert && !skb_has_frag_list(skb)) { 467cac2661cSSteffen Klassert int allocsize; 468cac2661cSSteffen Klassert struct sock *sk = skb->sk; 469cac2661cSSteffen Klassert struct page_frag *pfrag = &x->xfrag; 4707021b2e1SHerbert Xu 471fca11ebdSSteffen Klassert esp->inplace = false; 472fca11ebdSSteffen Klassert 473cac2661cSSteffen Klassert allocsize = ALIGN(tailen, L1_CACHE_BYTES); 474cac2661cSSteffen Klassert 475cac2661cSSteffen Klassert spin_lock_bh(&x->lock); 476cac2661cSSteffen Klassert 477cac2661cSSteffen Klassert if (unlikely(!skb_page_frag_refill(allocsize, pfrag, GFP_ATOMIC))) { 478cac2661cSSteffen Klassert spin_unlock_bh(&x->lock); 479cac2661cSSteffen Klassert goto cow; 4807021b2e1SHerbert Xu } 4817021b2e1SHerbert Xu 482cac2661cSSteffen Klassert page = pfrag->page; 483cac2661cSSteffen Klassert get_page(page); 484cac2661cSSteffen Klassert 4859bd6b629SWillem de Bruijn tail = page_address(page) + pfrag->offset; 486cac2661cSSteffen Klassert 487fca11ebdSSteffen Klassert esp_output_fill_trailer(tail, esp->tfclen, esp->plen, esp->proto); 488cac2661cSSteffen Klassert 489cac2661cSSteffen Klassert nfrags = skb_shinfo(skb)->nr_frags; 490cac2661cSSteffen Klassert 491cac2661cSSteffen Klassert __skb_fill_page_desc(skb, nfrags, page, pfrag->offset, 492cac2661cSSteffen Klassert tailen); 493cac2661cSSteffen Klassert skb_shinfo(skb)->nr_frags = ++nfrags; 494cac2661cSSteffen Klassert 495cac2661cSSteffen Klassert pfrag->offset = pfrag->offset + allocsize; 49636ff0dd3SSteffen Klassert 49736ff0dd3SSteffen Klassert spin_unlock_bh(&x->lock); 49836ff0dd3SSteffen Klassert 499cac2661cSSteffen Klassert nfrags++; 500cac2661cSSteffen Klassert 501cac2661cSSteffen Klassert skb->len += tailen; 502cac2661cSSteffen Klassert skb->data_len += tailen; 503cac2661cSSteffen Klassert skb->truesize += tailen; 50409db5124SMartin Willi if (sk && sk_fullsock(sk)) 50514afee4bSReshetova, Elena refcount_add(tailen, &sk->sk_wmem_alloc); 506cac2661cSSteffen Klassert 507fca11ebdSSteffen Klassert goto out; 508fca11ebdSSteffen Klassert } 509fca11ebdSSteffen Klassert } 510cac2661cSSteffen Klassert 511fca11ebdSSteffen Klassert cow: 5120e78a873SSteffen Klassert esph_offset = (unsigned char *)esp->esph - skb_transport_header(skb); 5130e78a873SSteffen Klassert 514fca11ebdSSteffen Klassert nfrags = skb_cow_data(skb, tailen, &trailer); 515fca11ebdSSteffen Klassert if (nfrags < 0) 516fca11ebdSSteffen Klassert goto out; 517fca11ebdSSteffen Klassert tail = skb_tail_pointer(trailer); 5180e78a873SSteffen Klassert esp->esph = (struct ip_esp_hdr *)(skb_transport_header(skb) + esph_offset); 5197021b2e1SHerbert Xu 520fca11ebdSSteffen Klassert skip_cow: 521fca11ebdSSteffen Klassert esp_output_fill_trailer(tail, esp->tfclen, esp->plen, esp->proto); 522fca11ebdSSteffen Klassert pskb_put(skb, trailer, tailen); 523fca11ebdSSteffen Klassert 524fca11ebdSSteffen Klassert out: 525fca11ebdSSteffen Klassert return nfrags; 526fca11ebdSSteffen Klassert } 527fca11ebdSSteffen Klassert EXPORT_SYMBOL_GPL(esp_output_head); 528fca11ebdSSteffen Klassert 529fca11ebdSSteffen Klassert int esp_output_tail(struct xfrm_state *x, struct sk_buff *skb, struct esp_info *esp) 530fca11ebdSSteffen Klassert { 531fca11ebdSSteffen Klassert u8 *iv; 532fca11ebdSSteffen Klassert int alen; 533fca11ebdSSteffen Klassert void *tmp; 534fca11ebdSSteffen Klassert int ivlen; 535fca11ebdSSteffen Klassert int assoclen; 536fca11ebdSSteffen Klassert int extralen; 537fca11ebdSSteffen Klassert struct page *page; 538fca11ebdSSteffen Klassert struct ip_esp_hdr *esph; 539fca11ebdSSteffen Klassert struct crypto_aead *aead; 540fca11ebdSSteffen Klassert struct aead_request *req; 541fca11ebdSSteffen Klassert struct scatterlist *sg, *dsg; 542fca11ebdSSteffen Klassert struct esp_output_extra *extra; 543fca11ebdSSteffen Klassert int err = -ENOMEM; 544fca11ebdSSteffen Klassert 545fca11ebdSSteffen Klassert assoclen = sizeof(struct ip_esp_hdr); 546fca11ebdSSteffen Klassert extralen = 0; 547fca11ebdSSteffen Klassert 548fca11ebdSSteffen Klassert if (x->props.flags & XFRM_STATE_ESN) { 549fca11ebdSSteffen Klassert extralen += sizeof(*extra); 550fca11ebdSSteffen Klassert assoclen += sizeof(__be32); 551fca11ebdSSteffen Klassert } 552fca11ebdSSteffen Klassert 553fca11ebdSSteffen Klassert aead = x->data; 554fca11ebdSSteffen Klassert alen = crypto_aead_authsize(aead); 555fca11ebdSSteffen Klassert ivlen = crypto_aead_ivsize(aead); 556fca11ebdSSteffen Klassert 557fca11ebdSSteffen Klassert tmp = esp_alloc_tmp(aead, esp->nfrags + 2, extralen); 558e892d2d4SSteffen Klassert if (!tmp) 559cac2661cSSteffen Klassert goto error; 560cac2661cSSteffen Klassert 561cac2661cSSteffen Klassert extra = esp_tmp_extra(tmp); 562cac2661cSSteffen Klassert iv = esp_tmp_iv(aead, tmp, extralen); 563cac2661cSSteffen Klassert req = esp_tmp_req(aead, iv); 564cac2661cSSteffen Klassert sg = esp_req_sg(aead, req); 565cac2661cSSteffen Klassert 566fca11ebdSSteffen Klassert if (esp->inplace) 567fca11ebdSSteffen Klassert dsg = sg; 568fca11ebdSSteffen Klassert else 569fca11ebdSSteffen Klassert dsg = &sg[esp->nfrags]; 570cac2661cSSteffen Klassert 571fca11ebdSSteffen Klassert esph = esp_output_set_extra(skb, x, esp->esph, extra); 572fca11ebdSSteffen Klassert esp->esph = esph; 573fca11ebdSSteffen Klassert 574fca11ebdSSteffen Klassert sg_init_table(sg, esp->nfrags); 5753f297707SJason A. Donenfeld err = skb_to_sgvec(skb, sg, 5767021b2e1SHerbert Xu (unsigned char *)esph - skb->data, 577fca11ebdSSteffen Klassert assoclen + ivlen + esp->clen + alen); 5783f297707SJason A. Donenfeld if (unlikely(err < 0)) 579e6194923SSteffen Klassert goto error_free; 580fca11ebdSSteffen Klassert 581fca11ebdSSteffen Klassert if (!esp->inplace) { 582fca11ebdSSteffen Klassert int allocsize; 583fca11ebdSSteffen Klassert struct page_frag *pfrag = &x->xfrag; 5840dc49e9bSSteffen Klassert 585cac2661cSSteffen Klassert allocsize = ALIGN(skb->data_len, L1_CACHE_BYTES); 586cac2661cSSteffen Klassert 587fca11ebdSSteffen Klassert spin_lock_bh(&x->lock); 588cac2661cSSteffen Klassert if (unlikely(!skb_page_frag_refill(allocsize, pfrag, GFP_ATOMIC))) { 589cac2661cSSteffen Klassert spin_unlock_bh(&x->lock); 590e6194923SSteffen Klassert goto error_free; 591cac2661cSSteffen Klassert } 592cac2661cSSteffen Klassert 593cac2661cSSteffen Klassert skb_shinfo(skb)->nr_frags = 1; 594cac2661cSSteffen Klassert 595cac2661cSSteffen Klassert page = pfrag->page; 596cac2661cSSteffen Klassert get_page(page); 597cac2661cSSteffen Klassert /* replace page frags in skb with new page */ 598cac2661cSSteffen Klassert __skb_fill_page_desc(skb, 0, page, pfrag->offset, skb->data_len); 599cac2661cSSteffen Klassert pfrag->offset = pfrag->offset + allocsize; 600fca11ebdSSteffen Klassert spin_unlock_bh(&x->lock); 601cac2661cSSteffen Klassert 602cac2661cSSteffen Klassert sg_init_table(dsg, skb_shinfo(skb)->nr_frags + 1); 6033f297707SJason A. Donenfeld err = skb_to_sgvec(skb, dsg, 604cac2661cSSteffen Klassert (unsigned char *)esph - skb->data, 605fca11ebdSSteffen Klassert assoclen + ivlen + esp->clen + alen); 6063f297707SJason A. Donenfeld if (unlikely(err < 0)) 607e6194923SSteffen Klassert goto error_free; 608cac2661cSSteffen Klassert } 609cac2661cSSteffen Klassert 610cac2661cSSteffen Klassert if ((x->props.flags & XFRM_STATE_ESN)) 611cac2661cSSteffen Klassert aead_request_set_callback(req, 0, esp_output_done_esn, skb); 612cac2661cSSteffen Klassert else 613cac2661cSSteffen Klassert aead_request_set_callback(req, 0, esp_output_done, skb); 614cac2661cSSteffen Klassert 615fca11ebdSSteffen Klassert aead_request_set_crypt(req, sg, dsg, ivlen + esp->clen, iv); 6167021b2e1SHerbert Xu aead_request_set_ad(req, assoclen); 6171da177e4SLinus Torvalds 6187021b2e1SHerbert Xu memset(iv, 0, ivlen); 619fca11ebdSSteffen Klassert memcpy(iv + ivlen - min(ivlen, 8), (u8 *)&esp->seqno + 8 - min(ivlen, 8), 6207021b2e1SHerbert Xu min(ivlen, 8)); 6216b7326c8SHerbert Xu 62238320c70SHerbert Xu ESP_SKB_CB(skb)->tmp = tmp; 6237021b2e1SHerbert Xu err = crypto_aead_encrypt(req); 6247021b2e1SHerbert Xu 6257021b2e1SHerbert Xu switch (err) { 6267021b2e1SHerbert Xu case -EINPROGRESS: 62738320c70SHerbert Xu goto error; 6281da177e4SLinus Torvalds 629068c2e70SGilad Ben-Yossef case -ENOSPC: 63038320c70SHerbert Xu err = NET_XMIT_DROP; 6317021b2e1SHerbert Xu break; 6327021b2e1SHerbert Xu 6337021b2e1SHerbert Xu case 0: 6347021b2e1SHerbert Xu if ((x->props.flags & XFRM_STATE_ESN)) 6357021b2e1SHerbert Xu esp_output_restore_header(skb); 6367021b2e1SHerbert Xu } 6371da177e4SLinus Torvalds 638cac2661cSSteffen Klassert if (sg != dsg) 639cac2661cSSteffen Klassert esp_ssg_unref(x, tmp); 640b7c6538cSHerbert Xu 641e27cca96SSabrina Dubroca if (!err && x->encap && x->encap->encap_type == TCP_ENCAP_ESPINTCP) 642e27cca96SSabrina Dubroca err = esp_output_tail_tcp(x, skb); 643e27cca96SSabrina Dubroca 644e6194923SSteffen Klassert error_free: 645e6194923SSteffen Klassert kfree(tmp); 6461da177e4SLinus Torvalds error: 6471da177e4SLinus Torvalds return err; 6481da177e4SLinus Torvalds } 649fca11ebdSSteffen Klassert EXPORT_SYMBOL_GPL(esp_output_tail); 6501da177e4SLinus Torvalds 651fca11ebdSSteffen Klassert static int esp_output(struct xfrm_state *x, struct sk_buff *skb) 652fca11ebdSSteffen Klassert { 653fca11ebdSSteffen Klassert int alen; 654fca11ebdSSteffen Klassert int blksize; 655fca11ebdSSteffen Klassert struct ip_esp_hdr *esph; 656fca11ebdSSteffen Klassert struct crypto_aead *aead; 657fca11ebdSSteffen Klassert struct esp_info esp; 658fca11ebdSSteffen Klassert 659fca11ebdSSteffen Klassert esp.inplace = true; 660fca11ebdSSteffen Klassert 661fca11ebdSSteffen Klassert esp.proto = *skb_mac_header(skb); 662fca11ebdSSteffen Klassert *skb_mac_header(skb) = IPPROTO_ESP; 663fca11ebdSSteffen Klassert 664fca11ebdSSteffen Klassert /* skb is pure payload to encrypt */ 665fca11ebdSSteffen Klassert 666fca11ebdSSteffen Klassert aead = x->data; 667fca11ebdSSteffen Klassert alen = crypto_aead_authsize(aead); 668fca11ebdSSteffen Klassert 669fca11ebdSSteffen Klassert esp.tfclen = 0; 670fca11ebdSSteffen Klassert if (x->tfcpad) { 671fca11ebdSSteffen Klassert struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb); 672fca11ebdSSteffen Klassert u32 padto; 673fca11ebdSSteffen Klassert 674*a6d95c5aSJiri Bohac padto = min(x->tfcpad, xfrm_state_mtu(x, dst->child_mtu_cached)); 675fca11ebdSSteffen Klassert if (skb->len < padto) 676fca11ebdSSteffen Klassert esp.tfclen = padto - skb->len; 677fca11ebdSSteffen Klassert } 678fca11ebdSSteffen Klassert blksize = ALIGN(crypto_aead_blocksize(aead), 4); 679fca11ebdSSteffen Klassert esp.clen = ALIGN(skb->len + 2 + esp.tfclen, blksize); 680fca11ebdSSteffen Klassert esp.plen = esp.clen - skb->len - esp.tfclen; 681fca11ebdSSteffen Klassert esp.tailen = esp.tfclen + esp.plen + alen; 682fca11ebdSSteffen Klassert 683fca11ebdSSteffen Klassert esp.esph = ip_esp_hdr(skb); 684fca11ebdSSteffen Klassert 685fca11ebdSSteffen Klassert esp.nfrags = esp_output_head(x, skb, &esp); 686fca11ebdSSteffen Klassert if (esp.nfrags < 0) 687fca11ebdSSteffen Klassert return esp.nfrags; 688fca11ebdSSteffen Klassert 689fca11ebdSSteffen Klassert esph = esp.esph; 690fca11ebdSSteffen Klassert esph->spi = x->id.spi; 691fca11ebdSSteffen Klassert 692fca11ebdSSteffen Klassert esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low); 693fca11ebdSSteffen Klassert esp.seqno = cpu_to_be64(XFRM_SKB_CB(skb)->seq.output.low + 694fca11ebdSSteffen Klassert ((u64)XFRM_SKB_CB(skb)->seq.output.hi << 32)); 695fca11ebdSSteffen Klassert 696fca11ebdSSteffen Klassert skb_push(skb, -skb_network_offset(skb)); 697fca11ebdSSteffen Klassert 698fca11ebdSSteffen Klassert return esp_output_tail(x, skb, &esp); 699fca11ebdSSteffen Klassert } 700fca11ebdSSteffen Klassert 70147ebcc0bSYossi Kuperman static inline int esp_remove_trailer(struct sk_buff *skb) 70247ebcc0bSYossi Kuperman { 70347ebcc0bSYossi Kuperman struct xfrm_state *x = xfrm_input_state(skb); 70447ebcc0bSYossi Kuperman struct xfrm_offload *xo = xfrm_offload(skb); 70547ebcc0bSYossi Kuperman struct crypto_aead *aead = x->data; 70647ebcc0bSYossi Kuperman int alen, hlen, elen; 70747ebcc0bSYossi Kuperman int padlen, trimlen; 70847ebcc0bSYossi Kuperman __wsum csumdiff; 70947ebcc0bSYossi Kuperman u8 nexthdr[2]; 71047ebcc0bSYossi Kuperman int ret; 71147ebcc0bSYossi Kuperman 71247ebcc0bSYossi Kuperman alen = crypto_aead_authsize(aead); 71347ebcc0bSYossi Kuperman hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead); 71447ebcc0bSYossi Kuperman elen = skb->len - hlen; 71547ebcc0bSYossi Kuperman 71647ebcc0bSYossi Kuperman if (xo && (xo->flags & XFRM_ESP_NO_TRAILER)) { 71747ebcc0bSYossi Kuperman ret = xo->proto; 71847ebcc0bSYossi Kuperman goto out; 71947ebcc0bSYossi Kuperman } 72047ebcc0bSYossi Kuperman 72147ebcc0bSYossi Kuperman if (skb_copy_bits(skb, skb->len - alen - 2, nexthdr, 2)) 72247ebcc0bSYossi Kuperman BUG(); 72347ebcc0bSYossi Kuperman 72447ebcc0bSYossi Kuperman ret = -EINVAL; 72547ebcc0bSYossi Kuperman padlen = nexthdr[0]; 72647ebcc0bSYossi Kuperman if (padlen + 2 + alen >= elen) { 72747ebcc0bSYossi Kuperman net_dbg_ratelimited("ipsec esp packet is garbage padlen=%d, elen=%d\n", 72847ebcc0bSYossi Kuperman padlen + 2, elen - alen); 72947ebcc0bSYossi Kuperman goto out; 73047ebcc0bSYossi Kuperman } 73147ebcc0bSYossi Kuperman 73247ebcc0bSYossi Kuperman trimlen = alen + padlen + 2; 73347ebcc0bSYossi Kuperman if (skb->ip_summed == CHECKSUM_COMPLETE) { 73447ebcc0bSYossi Kuperman csumdiff = skb_checksum(skb, skb->len - trimlen, trimlen, 0); 73547ebcc0bSYossi Kuperman skb->csum = csum_block_sub(skb->csum, csumdiff, 73647ebcc0bSYossi Kuperman skb->len - trimlen); 73747ebcc0bSYossi Kuperman } 73847ebcc0bSYossi Kuperman pskb_trim(skb, skb->len - trimlen); 73947ebcc0bSYossi Kuperman 74047ebcc0bSYossi Kuperman ret = nexthdr[1]; 74147ebcc0bSYossi Kuperman 74247ebcc0bSYossi Kuperman out: 74347ebcc0bSYossi Kuperman return ret; 74447ebcc0bSYossi Kuperman } 74547ebcc0bSYossi Kuperman 746fca11ebdSSteffen Klassert int esp_input_done2(struct sk_buff *skb, int err) 7471da177e4SLinus Torvalds { 748b71d1d42SEric Dumazet const struct iphdr *iph; 74938320c70SHerbert Xu struct xfrm_state *x = xfrm_input_state(skb); 750d77e38e6SSteffen Klassert struct xfrm_offload *xo = xfrm_offload(skb); 7511c5ad13fSMathias Krause struct crypto_aead *aead = x->data; 75238320c70SHerbert Xu int hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead); 75331a4ab93SHerbert Xu int ihl; 7541da177e4SLinus Torvalds 7551d9bfacdSJiapeng Chong if (!xo || !(xo->flags & CRYPTO_DONE)) 75638320c70SHerbert Xu kfree(ESP_SKB_CB(skb)->tmp); 7570ebea8efSHerbert Xu 7586b7326c8SHerbert Xu if (unlikely(err)) 759668dc8afSHerbert Xu goto out; 7601da177e4SLinus Torvalds 76147ebcc0bSYossi Kuperman err = esp_remove_trailer(skb); 76247ebcc0bSYossi Kuperman if (unlikely(err < 0)) 7631da177e4SLinus Torvalds goto out; 7641da177e4SLinus Torvalds 765eddc9ec5SArnaldo Carvalho de Melo iph = ip_hdr(skb); 76631a4ab93SHerbert Xu ihl = iph->ihl * 4; 76731a4ab93SHerbert Xu 7681da177e4SLinus Torvalds if (x->encap) { 769752c1f4cSHerbert Xu struct xfrm_encap_tmpl *encap = x->encap; 770e27cca96SSabrina Dubroca struct tcphdr *th = (void *)(skb_network_header(skb) + ihl); 771d56f90a7SArnaldo Carvalho de Melo struct udphdr *uh = (void *)(skb_network_header(skb) + ihl); 77225f6802bSSabrina Dubroca __be16 source; 77325f6802bSSabrina Dubroca 77425f6802bSSabrina Dubroca switch (x->encap->encap_type) { 775e27cca96SSabrina Dubroca case TCP_ENCAP_ESPINTCP: 776e27cca96SSabrina Dubroca source = th->source; 777e27cca96SSabrina Dubroca break; 77825f6802bSSabrina Dubroca case UDP_ENCAP_ESPINUDP: 77925f6802bSSabrina Dubroca case UDP_ENCAP_ESPINUDP_NON_IKE: 78025f6802bSSabrina Dubroca source = uh->source; 78125f6802bSSabrina Dubroca break; 78225f6802bSSabrina Dubroca default: 78325f6802bSSabrina Dubroca WARN_ON_ONCE(1); 78425f6802bSSabrina Dubroca err = -EINVAL; 78525f6802bSSabrina Dubroca goto out; 78625f6802bSSabrina Dubroca } 787752c1f4cSHerbert Xu 7881da177e4SLinus Torvalds /* 7891da177e4SLinus Torvalds * 1) if the NAT-T peer's IP or port changed then 7901da177e4SLinus Torvalds * advertize the change to the keying daemon. 7911da177e4SLinus Torvalds * This is an inbound SA, so just compare 7921da177e4SLinus Torvalds * SRC ports. 7931da177e4SLinus Torvalds */ 794752c1f4cSHerbert Xu if (iph->saddr != x->props.saddr.a4 || 79525f6802bSSabrina Dubroca source != encap->encap_sport) { 7961da177e4SLinus Torvalds xfrm_address_t ipaddr; 7971da177e4SLinus Torvalds 798752c1f4cSHerbert Xu ipaddr.a4 = iph->saddr; 79925f6802bSSabrina Dubroca km_new_mapping(x, &ipaddr, source); 8001da177e4SLinus Torvalds 8011da177e4SLinus Torvalds /* XXX: perhaps add an extra 8021da177e4SLinus Torvalds * policy check here, to see 8031da177e4SLinus Torvalds * if we should allow or 8041da177e4SLinus Torvalds * reject a packet from a 8051da177e4SLinus Torvalds * different source 8061da177e4SLinus Torvalds * address/port. 8071da177e4SLinus Torvalds */ 8081da177e4SLinus Torvalds } 8091da177e4SLinus Torvalds 8101da177e4SLinus Torvalds /* 8111da177e4SLinus Torvalds * 2) ignore UDP/TCP checksums in case 8121da177e4SLinus Torvalds * of NAT-T in Transport Mode, or 8131da177e4SLinus Torvalds * perform other post-processing fixes 814752c1f4cSHerbert Xu * as per draft-ietf-ipsec-udp-encaps-06, 8151da177e4SLinus Torvalds * section 3.1.2 8161da177e4SLinus Torvalds */ 8178bd17075SHerbert Xu if (x->props.mode == XFRM_MODE_TRANSPORT) 8181da177e4SLinus Torvalds skb->ip_summed = CHECKSUM_UNNECESSARY; 819752c1f4cSHerbert Xu } 8201da177e4SLinus Torvalds 821ec9567a9SIlan Tayari skb_pull_rcsum(skb, hlen); 8227143dfacSLi RongQing if (x->props.mode == XFRM_MODE_TUNNEL) 8237143dfacSLi RongQing skb_reset_transport_header(skb); 8247143dfacSLi RongQing else 825967b05f6SArnaldo Carvalho de Melo skb_set_transport_header(skb, -ihl); 826752c1f4cSHerbert Xu 82738320c70SHerbert Xu /* RFC4303: Drop dummy packets without any error */ 82838320c70SHerbert Xu if (err == IPPROTO_NONE) 82938320c70SHerbert Xu err = -EINVAL; 83038320c70SHerbert Xu 83138320c70SHerbert Xu out: 83238320c70SHerbert Xu return err; 83338320c70SHerbert Xu } 834fca11ebdSSteffen Klassert EXPORT_SYMBOL_GPL(esp_input_done2); 83538320c70SHerbert Xu 83638320c70SHerbert Xu static void esp_input_done(struct crypto_async_request *base, int err) 83738320c70SHerbert Xu { 83838320c70SHerbert Xu struct sk_buff *skb = base->data; 83938320c70SHerbert Xu 84038320c70SHerbert Xu xfrm_input_resume(skb, esp_input_done2(skb, err)); 84138320c70SHerbert Xu } 84238320c70SHerbert Xu 8437021b2e1SHerbert Xu static void esp_input_restore_header(struct sk_buff *skb) 8447021b2e1SHerbert Xu { 8457021b2e1SHerbert Xu esp_restore_header(skb, 0); 8467021b2e1SHerbert Xu __skb_pull(skb, 4); 8477021b2e1SHerbert Xu } 8487021b2e1SHerbert Xu 849cac2661cSSteffen Klassert static void esp_input_set_header(struct sk_buff *skb, __be32 *seqhi) 850cac2661cSSteffen Klassert { 851cac2661cSSteffen Klassert struct xfrm_state *x = xfrm_input_state(skb); 85260aa8046SColin Ian King struct ip_esp_hdr *esph; 853cac2661cSSteffen Klassert 854cac2661cSSteffen Klassert /* For ESN we move the header forward by 4 bytes to 855cbd801b3SLu Wei * accommodate the high bits. We will move it back after 856cac2661cSSteffen Klassert * decryption. 857cac2661cSSteffen Klassert */ 858cac2661cSSteffen Klassert if ((x->props.flags & XFRM_STATE_ESN)) { 859d58ff351SJohannes Berg esph = skb_push(skb, 4); 860cac2661cSSteffen Klassert *seqhi = esph->spi; 861cac2661cSSteffen Klassert esph->spi = esph->seq_no; 862cac2661cSSteffen Klassert esph->seq_no = XFRM_SKB_CB(skb)->seq.input.hi; 863cac2661cSSteffen Klassert } 864cac2661cSSteffen Klassert } 865cac2661cSSteffen Klassert 8667021b2e1SHerbert Xu static void esp_input_done_esn(struct crypto_async_request *base, int err) 8677021b2e1SHerbert Xu { 8687021b2e1SHerbert Xu struct sk_buff *skb = base->data; 8697021b2e1SHerbert Xu 8707021b2e1SHerbert Xu esp_input_restore_header(skb); 8717021b2e1SHerbert Xu esp_input_done(base, err); 8727021b2e1SHerbert Xu } 8737021b2e1SHerbert Xu 87438320c70SHerbert Xu /* 87538320c70SHerbert Xu * Note: detecting truncated vs. non-truncated authentication data is very 87638320c70SHerbert Xu * expensive, so we only support truncated data, which is the recommended 87738320c70SHerbert Xu * and common case. 87838320c70SHerbert Xu */ 87938320c70SHerbert Xu static int esp_input(struct xfrm_state *x, struct sk_buff *skb) 88038320c70SHerbert Xu { 8811c5ad13fSMathias Krause struct crypto_aead *aead = x->data; 88238320c70SHerbert Xu struct aead_request *req; 88338320c70SHerbert Xu struct sk_buff *trailer; 8847021b2e1SHerbert Xu int ivlen = crypto_aead_ivsize(aead); 8850c05f983SHaishuang Yan int elen = skb->len - sizeof(struct ip_esp_hdr) - ivlen; 88638320c70SHerbert Xu int nfrags; 8870dc49e9bSSteffen Klassert int assoclen; 8880dc49e9bSSteffen Klassert int seqhilen; 8890dc49e9bSSteffen Klassert __be32 *seqhi; 89038320c70SHerbert Xu void *tmp; 89138320c70SHerbert Xu u8 *iv; 89238320c70SHerbert Xu struct scatterlist *sg; 89338320c70SHerbert Xu int err = -EINVAL; 89438320c70SHerbert Xu 8950c05f983SHaishuang Yan if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr) + ivlen)) 89638320c70SHerbert Xu goto out; 89738320c70SHerbert Xu 89838320c70SHerbert Xu if (elen <= 0) 89938320c70SHerbert Xu goto out; 90038320c70SHerbert Xu 9010c05f983SHaishuang Yan assoclen = sizeof(struct ip_esp_hdr); 9020dc49e9bSSteffen Klassert seqhilen = 0; 9030dc49e9bSSteffen Klassert 9040dc49e9bSSteffen Klassert if (x->props.flags & XFRM_STATE_ESN) { 9050dc49e9bSSteffen Klassert seqhilen += sizeof(__be32); 9060dc49e9bSSteffen Klassert assoclen += seqhilen; 9070dc49e9bSSteffen Klassert } 9080dc49e9bSSteffen Klassert 909cac2661cSSteffen Klassert if (!skb_cloned(skb)) { 910cac2661cSSteffen Klassert if (!skb_is_nonlinear(skb)) { 911cac2661cSSteffen Klassert nfrags = 1; 912cac2661cSSteffen Klassert 913cac2661cSSteffen Klassert goto skip_cow; 914cac2661cSSteffen Klassert } else if (!skb_has_frag_list(skb)) { 915cac2661cSSteffen Klassert nfrags = skb_shinfo(skb)->nr_frags; 916cac2661cSSteffen Klassert nfrags++; 917cac2661cSSteffen Klassert 918cac2661cSSteffen Klassert goto skip_cow; 919cac2661cSSteffen Klassert } 920cac2661cSSteffen Klassert } 921cac2661cSSteffen Klassert 922cac2661cSSteffen Klassert err = skb_cow_data(skb, 0, &trailer); 923cac2661cSSteffen Klassert if (err < 0) 924cac2661cSSteffen Klassert goto out; 925cac2661cSSteffen Klassert 926cac2661cSSteffen Klassert nfrags = err; 927cac2661cSSteffen Klassert 928cac2661cSSteffen Klassert skip_cow: 92938320c70SHerbert Xu err = -ENOMEM; 9307021b2e1SHerbert Xu tmp = esp_alloc_tmp(aead, nfrags, seqhilen); 93138320c70SHerbert Xu if (!tmp) 93238320c70SHerbert Xu goto out; 93338320c70SHerbert Xu 93438320c70SHerbert Xu ESP_SKB_CB(skb)->tmp = tmp; 935962fcef3SHerbert Xu seqhi = esp_tmp_extra(tmp); 9360dc49e9bSSteffen Klassert iv = esp_tmp_iv(aead, tmp, seqhilen); 93738320c70SHerbert Xu req = esp_tmp_req(aead, iv); 9387021b2e1SHerbert Xu sg = esp_req_sg(aead, req); 93938320c70SHerbert Xu 940cac2661cSSteffen Klassert esp_input_set_header(skb, seqhi); 94138320c70SHerbert Xu 94238320c70SHerbert Xu sg_init_table(sg, nfrags); 9433f297707SJason A. Donenfeld err = skb_to_sgvec(skb, sg, 0, skb->len); 944e6194923SSteffen Klassert if (unlikely(err < 0)) { 945e6194923SSteffen Klassert kfree(tmp); 9463f297707SJason A. Donenfeld goto out; 947e6194923SSteffen Klassert } 9480dc49e9bSSteffen Klassert 949cac2661cSSteffen Klassert skb->ip_summed = CHECKSUM_NONE; 950cac2661cSSteffen Klassert 951cac2661cSSteffen Klassert if ((x->props.flags & XFRM_STATE_ESN)) 952cac2661cSSteffen Klassert aead_request_set_callback(req, 0, esp_input_done_esn, skb); 953cac2661cSSteffen Klassert else 954cac2661cSSteffen Klassert aead_request_set_callback(req, 0, esp_input_done, skb); 955cac2661cSSteffen Klassert 9567021b2e1SHerbert Xu aead_request_set_crypt(req, sg, sg, elen + ivlen, iv); 9577021b2e1SHerbert Xu aead_request_set_ad(req, assoclen); 95838320c70SHerbert Xu 95938320c70SHerbert Xu err = crypto_aead_decrypt(req); 96038320c70SHerbert Xu if (err == -EINPROGRESS) 96138320c70SHerbert Xu goto out; 96238320c70SHerbert Xu 9637021b2e1SHerbert Xu if ((x->props.flags & XFRM_STATE_ESN)) 9647021b2e1SHerbert Xu esp_input_restore_header(skb); 9657021b2e1SHerbert Xu 96638320c70SHerbert Xu err = esp_input_done2(skb, err); 967752c1f4cSHerbert Xu 968752c1f4cSHerbert Xu out: 969668dc8afSHerbert Xu return err; 9701da177e4SLinus Torvalds } 9711da177e4SLinus Torvalds 972827789cbSSteffen Klassert static int esp4_err(struct sk_buff *skb, u32 info) 9731da177e4SLinus Torvalds { 9744fb236baSAlexey Dobriyan struct net *net = dev_net(skb->dev); 975b71d1d42SEric Dumazet const struct iphdr *iph = (const struct iphdr *)skb->data; 9761da177e4SLinus Torvalds struct ip_esp_hdr *esph = (struct ip_esp_hdr *)(skb->data+(iph->ihl<<2)); 9771da177e4SLinus Torvalds struct xfrm_state *x; 9781da177e4SLinus Torvalds 97955be7a9cSDavid S. Miller switch (icmp_hdr(skb)->type) { 98055be7a9cSDavid S. Miller case ICMP_DEST_UNREACH: 98155be7a9cSDavid S. Miller if (icmp_hdr(skb)->code != ICMP_FRAG_NEEDED) 982827789cbSSteffen Klassert return 0; 98379121184SGustavo A. R. Silva break; 98455be7a9cSDavid S. Miller case ICMP_REDIRECT: 98555be7a9cSDavid S. Miller break; 98655be7a9cSDavid S. Miller default: 987827789cbSSteffen Klassert return 0; 98855be7a9cSDavid S. Miller } 9891da177e4SLinus Torvalds 990b71d1d42SEric Dumazet x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr, 991b71d1d42SEric Dumazet esph->spi, IPPROTO_ESP, AF_INET); 9921da177e4SLinus Torvalds if (!x) 993827789cbSSteffen Klassert return 0; 99455be7a9cSDavid S. Miller 995387aa65aSTimo Teräs if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH) 996d888f396SMaciej Żenczykowski ipv4_update_pmtu(skb, net, info, 0, IPPROTO_ESP); 997387aa65aSTimo Teräs else 9981042caa7SMaciej Żenczykowski ipv4_redirect(skb, net, 0, IPPROTO_ESP); 9991da177e4SLinus Torvalds xfrm_state_put(x); 1000827789cbSSteffen Klassert 1001827789cbSSteffen Klassert return 0; 10021da177e4SLinus Torvalds } 10031da177e4SLinus Torvalds 10041da177e4SLinus Torvalds static void esp_destroy(struct xfrm_state *x) 10051da177e4SLinus Torvalds { 10061c5ad13fSMathias Krause struct crypto_aead *aead = x->data; 10071da177e4SLinus Torvalds 10081c5ad13fSMathias Krause if (!aead) 10091da177e4SLinus Torvalds return; 10101da177e4SLinus Torvalds 10111c5ad13fSMathias Krause crypto_free_aead(aead); 10121da177e4SLinus Torvalds } 10131da177e4SLinus Torvalds 10141a6509d9SHerbert Xu static int esp_init_aead(struct xfrm_state *x) 10151da177e4SLinus Torvalds { 10167021b2e1SHerbert Xu char aead_name[CRYPTO_MAX_ALG_NAME]; 10171a6509d9SHerbert Xu struct crypto_aead *aead; 10181a6509d9SHerbert Xu int err; 10191a6509d9SHerbert Xu 10207021b2e1SHerbert Xu err = -ENAMETOOLONG; 10217021b2e1SHerbert Xu if (snprintf(aead_name, CRYPTO_MAX_ALG_NAME, "%s(%s)", 10227021b2e1SHerbert Xu x->geniv, x->aead->alg_name) >= CRYPTO_MAX_ALG_NAME) 10237021b2e1SHerbert Xu goto error; 10247021b2e1SHerbert Xu 1025f58869c4SSteffen Klassert aead = crypto_alloc_aead(aead_name, 0, 0); 10261a6509d9SHerbert Xu err = PTR_ERR(aead); 10271a6509d9SHerbert Xu if (IS_ERR(aead)) 10281a6509d9SHerbert Xu goto error; 10291a6509d9SHerbert Xu 10301c5ad13fSMathias Krause x->data = aead; 10311a6509d9SHerbert Xu 10321a6509d9SHerbert Xu err = crypto_aead_setkey(aead, x->aead->alg_key, 10331a6509d9SHerbert Xu (x->aead->alg_key_len + 7) / 8); 10341a6509d9SHerbert Xu if (err) 10351a6509d9SHerbert Xu goto error; 10361a6509d9SHerbert Xu 10371a6509d9SHerbert Xu err = crypto_aead_setauthsize(aead, x->aead->alg_icv_len / 8); 10381a6509d9SHerbert Xu if (err) 10391a6509d9SHerbert Xu goto error; 10401a6509d9SHerbert Xu 10411a6509d9SHerbert Xu error: 10421a6509d9SHerbert Xu return err; 10431a6509d9SHerbert Xu } 10441a6509d9SHerbert Xu 10451a6509d9SHerbert Xu static int esp_init_authenc(struct xfrm_state *x) 10461a6509d9SHerbert Xu { 104738320c70SHerbert Xu struct crypto_aead *aead; 104838320c70SHerbert Xu struct crypto_authenc_key_param *param; 104938320c70SHerbert Xu struct rtattr *rta; 105038320c70SHerbert Xu char *key; 105138320c70SHerbert Xu char *p; 105238320c70SHerbert Xu char authenc_name[CRYPTO_MAX_ALG_NAME]; 105338320c70SHerbert Xu unsigned int keylen; 105438320c70SHerbert Xu int err; 10551da177e4SLinus Torvalds 10561a6509d9SHerbert Xu err = -EINVAL; 105751456b29SIan Morris if (!x->ealg) 10581a6509d9SHerbert Xu goto error; 105938320c70SHerbert Xu 10601a6509d9SHerbert Xu err = -ENAMETOOLONG; 10610dc49e9bSSteffen Klassert 10620dc49e9bSSteffen Klassert if ((x->props.flags & XFRM_STATE_ESN)) { 10630dc49e9bSSteffen Klassert if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, 10647021b2e1SHerbert Xu "%s%sauthencesn(%s,%s)%s", 10657021b2e1SHerbert Xu x->geniv ?: "", x->geniv ? "(" : "", 106638320c70SHerbert Xu x->aalg ? x->aalg->alg_name : "digest_null", 10677021b2e1SHerbert Xu x->ealg->alg_name, 10687021b2e1SHerbert Xu x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME) 10691a6509d9SHerbert Xu goto error; 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, 10767021b2e1SHerbert Xu x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME) 10770dc49e9bSSteffen Klassert goto error; 10780dc49e9bSSteffen Klassert } 107938320c70SHerbert Xu 1080f58869c4SSteffen Klassert aead = crypto_alloc_aead(authenc_name, 0, 0); 108138320c70SHerbert Xu err = PTR_ERR(aead); 108238320c70SHerbert Xu if (IS_ERR(aead)) 108338320c70SHerbert Xu goto error; 108438320c70SHerbert Xu 10851c5ad13fSMathias Krause x->data = aead; 108638320c70SHerbert Xu 108738320c70SHerbert Xu keylen = (x->aalg ? (x->aalg->alg_key_len + 7) / 8 : 0) + 108838320c70SHerbert Xu (x->ealg->alg_key_len + 7) / 8 + RTA_SPACE(sizeof(*param)); 108938320c70SHerbert Xu err = -ENOMEM; 109038320c70SHerbert Xu key = kmalloc(keylen, GFP_KERNEL); 109138320c70SHerbert Xu if (!key) 109238320c70SHerbert Xu goto error; 109338320c70SHerbert Xu 109438320c70SHerbert Xu p = key; 109538320c70SHerbert Xu rta = (void *)p; 109638320c70SHerbert Xu rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM; 109738320c70SHerbert Xu rta->rta_len = RTA_LENGTH(sizeof(*param)); 109838320c70SHerbert Xu param = RTA_DATA(rta); 109938320c70SHerbert Xu p += RTA_SPACE(sizeof(*param)); 110038320c70SHerbert Xu 11011da177e4SLinus Torvalds if (x->aalg) { 11021da177e4SLinus Torvalds struct xfrm_algo_desc *aalg_desc; 11031da177e4SLinus Torvalds 110438320c70SHerbert Xu memcpy(p, x->aalg->alg_key, (x->aalg->alg_key_len + 7) / 8); 110538320c70SHerbert Xu p += (x->aalg->alg_key_len + 7) / 8; 11061da177e4SLinus Torvalds 11071da177e4SLinus Torvalds aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0); 11081da177e4SLinus Torvalds BUG_ON(!aalg_desc); 11091da177e4SLinus Torvalds 111038320c70SHerbert Xu err = -EINVAL; 11111da177e4SLinus Torvalds if (aalg_desc->uinfo.auth.icv_fullbits / 8 != 111238320c70SHerbert Xu crypto_aead_authsize(aead)) { 111345083497SJoe Perches pr_info("ESP: %s digestsize %u != %hu\n", 11141da177e4SLinus Torvalds x->aalg->alg_name, 111538320c70SHerbert Xu crypto_aead_authsize(aead), 111664ce2073SPatrick McHardy aalg_desc->uinfo.auth.icv_fullbits / 8); 111738320c70SHerbert Xu goto free_key; 11181da177e4SLinus Torvalds } 11191da177e4SLinus Torvalds 112038320c70SHerbert Xu err = crypto_aead_setauthsize( 11218f8a088cSMartin Willi aead, x->aalg->alg_trunc_len / 8); 112238320c70SHerbert Xu if (err) 112338320c70SHerbert Xu goto free_key; 11241da177e4SLinus Torvalds } 11254b7137ffSHerbert Xu 112638320c70SHerbert Xu param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8); 112738320c70SHerbert Xu memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8); 112838320c70SHerbert Xu 112938320c70SHerbert Xu err = crypto_aead_setkey(aead, key, keylen); 113038320c70SHerbert Xu 113138320c70SHerbert Xu free_key: 113238320c70SHerbert Xu kfree(key); 113338320c70SHerbert Xu 11341a6509d9SHerbert Xu error: 11351a6509d9SHerbert Xu return err; 11361a6509d9SHerbert Xu } 11371a6509d9SHerbert Xu 11381a6509d9SHerbert Xu static int esp_init_state(struct xfrm_state *x) 11391a6509d9SHerbert Xu { 11401a6509d9SHerbert Xu struct crypto_aead *aead; 11411a6509d9SHerbert Xu u32 align; 11421a6509d9SHerbert Xu int err; 11431a6509d9SHerbert Xu 11441c5ad13fSMathias Krause x->data = NULL; 11451a6509d9SHerbert Xu 11461a6509d9SHerbert Xu if (x->aead) 11471a6509d9SHerbert Xu err = esp_init_aead(x); 11481a6509d9SHerbert Xu else 11491a6509d9SHerbert Xu err = esp_init_authenc(x); 11501a6509d9SHerbert Xu 115138320c70SHerbert Xu if (err) 11521da177e4SLinus Torvalds goto error; 115338320c70SHerbert Xu 11541c5ad13fSMathias Krause aead = x->data; 11551a6509d9SHerbert Xu 115638320c70SHerbert Xu x->props.header_len = sizeof(struct ip_esp_hdr) + 115738320c70SHerbert Xu crypto_aead_ivsize(aead); 11587e49e6deSMasahide NAKAMURA if (x->props.mode == XFRM_MODE_TUNNEL) 11591da177e4SLinus Torvalds x->props.header_len += sizeof(struct iphdr); 1160eb49e630SJoakim Koskela else if (x->props.mode == XFRM_MODE_BEET && x->sel.family != AF_INET6) 1161ac758e3cSPatrick McHardy x->props.header_len += IPV4_BEET_PHMAXLEN; 11621da177e4SLinus Torvalds if (x->encap) { 11631da177e4SLinus Torvalds struct xfrm_encap_tmpl *encap = x->encap; 11641da177e4SLinus Torvalds 11651da177e4SLinus Torvalds switch (encap->encap_type) { 11661da177e4SLinus Torvalds default: 1167bcfd09f7SHerbert Xu err = -EINVAL; 11681da177e4SLinus Torvalds goto error; 11691da177e4SLinus Torvalds case UDP_ENCAP_ESPINUDP: 11701da177e4SLinus Torvalds x->props.header_len += sizeof(struct udphdr); 11711da177e4SLinus Torvalds break; 11721da177e4SLinus Torvalds case UDP_ENCAP_ESPINUDP_NON_IKE: 11731da177e4SLinus Torvalds x->props.header_len += sizeof(struct udphdr) + 2 * sizeof(u32); 11741da177e4SLinus Torvalds break; 1175e27cca96SSabrina Dubroca #ifdef CONFIG_INET_ESPINTCP 1176e27cca96SSabrina Dubroca case TCP_ENCAP_ESPINTCP: 1177e27cca96SSabrina Dubroca /* only the length field, TCP encap is done by 1178e27cca96SSabrina Dubroca * the socket 1179e27cca96SSabrina Dubroca */ 1180e27cca96SSabrina Dubroca x->props.header_len += 2; 1181e27cca96SSabrina Dubroca break; 1182e27cca96SSabrina Dubroca #endif 11831da177e4SLinus Torvalds } 11841da177e4SLinus Torvalds } 118538320c70SHerbert Xu 118638320c70SHerbert Xu align = ALIGN(crypto_aead_blocksize(aead), 4); 11871c5ad13fSMathias Krause x->props.trailer_len = align + 1 + crypto_aead_authsize(aead); 11881da177e4SLinus Torvalds 11891da177e4SLinus Torvalds error: 119038320c70SHerbert Xu return err; 11911da177e4SLinus Torvalds } 11921da177e4SLinus Torvalds 1193827789cbSSteffen Klassert static int esp4_rcv_cb(struct sk_buff *skb, int err) 1194827789cbSSteffen Klassert { 1195827789cbSSteffen Klassert return 0; 1196827789cbSSteffen Klassert } 1197827789cbSSteffen Klassert 1198533cb5b0SEric Dumazet static const struct xfrm_type esp_type = 11991da177e4SLinus Torvalds { 12001da177e4SLinus Torvalds .owner = THIS_MODULE, 12011da177e4SLinus Torvalds .proto = IPPROTO_ESP, 1202436a0a40SHerbert Xu .flags = XFRM_TYPE_REPLAY_PROT, 12031da177e4SLinus Torvalds .init_state = esp_init_state, 12041da177e4SLinus Torvalds .destructor = esp_destroy, 12051da177e4SLinus Torvalds .input = esp_input, 1206fca11ebdSSteffen Klassert .output = esp_output, 12071da177e4SLinus Torvalds }; 12081da177e4SLinus Torvalds 1209827789cbSSteffen Klassert static struct xfrm4_protocol esp4_protocol = { 12101da177e4SLinus Torvalds .handler = xfrm4_rcv, 1211827789cbSSteffen Klassert .input_handler = xfrm_input, 1212827789cbSSteffen Klassert .cb_handler = esp4_rcv_cb, 12131da177e4SLinus Torvalds .err_handler = esp4_err, 1214827789cbSSteffen Klassert .priority = 0, 12151da177e4SLinus Torvalds }; 12161da177e4SLinus Torvalds 12171da177e4SLinus Torvalds static int __init esp4_init(void) 12181da177e4SLinus Torvalds { 12191da177e4SLinus Torvalds if (xfrm_register_type(&esp_type, AF_INET) < 0) { 1220058bd4d2SJoe Perches pr_info("%s: can't add xfrm type\n", __func__); 12211da177e4SLinus Torvalds return -EAGAIN; 12221da177e4SLinus Torvalds } 1223827789cbSSteffen Klassert if (xfrm4_protocol_register(&esp4_protocol, IPPROTO_ESP) < 0) { 1224058bd4d2SJoe Perches pr_info("%s: can't add protocol\n", __func__); 12251da177e4SLinus Torvalds xfrm_unregister_type(&esp_type, AF_INET); 12261da177e4SLinus Torvalds return -EAGAIN; 12271da177e4SLinus Torvalds } 12281da177e4SLinus Torvalds return 0; 12291da177e4SLinus Torvalds } 12301da177e4SLinus Torvalds 12311da177e4SLinus Torvalds static void __exit esp4_fini(void) 12321da177e4SLinus Torvalds { 1233827789cbSSteffen Klassert if (xfrm4_protocol_deregister(&esp4_protocol, IPPROTO_ESP) < 0) 1234058bd4d2SJoe Perches pr_info("%s: can't remove protocol\n", __func__); 12354f518e80SFlorian Westphal xfrm_unregister_type(&esp_type, AF_INET); 12361da177e4SLinus Torvalds } 12371da177e4SLinus Torvalds 12381da177e4SLinus Torvalds module_init(esp4_init); 12391da177e4SLinus Torvalds module_exit(esp4_fini); 12401da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 1241d3d6dd3aSMasahide NAKAMURA MODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_ESP); 1242