138320c70SHerbert Xu #include <crypto/aead.h> 238320c70SHerbert Xu #include <crypto/authenc.h> 36b7326c8SHerbert Xu #include <linux/err.h> 41da177e4SLinus Torvalds #include <linux/module.h> 51da177e4SLinus Torvalds #include <net/ip.h> 61da177e4SLinus Torvalds #include <net/xfrm.h> 71da177e4SLinus Torvalds #include <net/esp.h> 872998d8cSAdrian Bunk #include <linux/scatterlist.h> 9a02a6422SHerbert Xu #include <linux/kernel.h> 101da177e4SLinus Torvalds #include <linux/pfkeyv2.h> 1138320c70SHerbert Xu #include <linux/rtnetlink.h> 1238320c70SHerbert Xu #include <linux/slab.h> 13b7c6538cSHerbert Xu #include <linux/spinlock.h> 142017a72cSThomas Graf #include <linux/in6.h> 151da177e4SLinus Torvalds #include <net/icmp.h> 1614c85021SArnaldo Carvalho de Melo #include <net/protocol.h> 171da177e4SLinus Torvalds #include <net/udp.h> 181da177e4SLinus Torvalds 1938320c70SHerbert Xu struct esp_skb_cb { 2038320c70SHerbert Xu struct xfrm_skb_cb xfrm; 2138320c70SHerbert Xu void *tmp; 2238320c70SHerbert Xu }; 2338320c70SHerbert Xu 2438320c70SHerbert Xu #define ESP_SKB_CB(__skb) ((struct esp_skb_cb *)&((__skb)->cb[0])) 2538320c70SHerbert Xu 2638320c70SHerbert Xu /* 2738320c70SHerbert Xu * Allocate an AEAD request structure with extra space for SG and IV. 2838320c70SHerbert Xu * 2938320c70SHerbert Xu * For alignment considerations the IV is placed at the front, followed 3038320c70SHerbert Xu * by the request and finally the SG list. 3138320c70SHerbert Xu * 3238320c70SHerbert Xu * TODO: Use spare space in skb for this where possible. 3338320c70SHerbert Xu */ 3438320c70SHerbert Xu static void *esp_alloc_tmp(struct crypto_aead *aead, int nfrags) 3538320c70SHerbert Xu { 3638320c70SHerbert Xu unsigned int len; 3738320c70SHerbert Xu 3838320c70SHerbert Xu len = crypto_aead_ivsize(aead); 3938320c70SHerbert Xu if (len) { 4038320c70SHerbert Xu len += crypto_aead_alignmask(aead) & 4138320c70SHerbert Xu ~(crypto_tfm_ctx_alignment() - 1); 4238320c70SHerbert Xu len = ALIGN(len, crypto_tfm_ctx_alignment()); 4338320c70SHerbert Xu } 4438320c70SHerbert Xu 4538320c70SHerbert Xu len += sizeof(struct aead_givcrypt_request) + crypto_aead_reqsize(aead); 4638320c70SHerbert Xu len = ALIGN(len, __alignof__(struct scatterlist)); 4738320c70SHerbert Xu 4838320c70SHerbert Xu len += sizeof(struct scatterlist) * nfrags; 4938320c70SHerbert Xu 5038320c70SHerbert Xu return kmalloc(len, GFP_ATOMIC); 5138320c70SHerbert Xu } 5238320c70SHerbert Xu 5338320c70SHerbert Xu static inline u8 *esp_tmp_iv(struct crypto_aead *aead, void *tmp) 5438320c70SHerbert Xu { 5538320c70SHerbert Xu return crypto_aead_ivsize(aead) ? 5638320c70SHerbert Xu PTR_ALIGN((u8 *)tmp, crypto_aead_alignmask(aead) + 1) : tmp; 5738320c70SHerbert Xu } 5838320c70SHerbert Xu 5938320c70SHerbert Xu static inline struct aead_givcrypt_request *esp_tmp_givreq( 6038320c70SHerbert Xu struct crypto_aead *aead, u8 *iv) 6138320c70SHerbert Xu { 6238320c70SHerbert Xu struct aead_givcrypt_request *req; 6338320c70SHerbert Xu 6438320c70SHerbert Xu req = (void *)PTR_ALIGN(iv + crypto_aead_ivsize(aead), 6538320c70SHerbert Xu crypto_tfm_ctx_alignment()); 6638320c70SHerbert Xu aead_givcrypt_set_tfm(req, aead); 6738320c70SHerbert Xu return req; 6838320c70SHerbert Xu } 6938320c70SHerbert Xu 7038320c70SHerbert Xu static inline struct aead_request *esp_tmp_req(struct crypto_aead *aead, u8 *iv) 7138320c70SHerbert Xu { 7238320c70SHerbert Xu struct aead_request *req; 7338320c70SHerbert Xu 7438320c70SHerbert Xu req = (void *)PTR_ALIGN(iv + crypto_aead_ivsize(aead), 7538320c70SHerbert Xu crypto_tfm_ctx_alignment()); 7638320c70SHerbert Xu aead_request_set_tfm(req, aead); 7738320c70SHerbert Xu return req; 7838320c70SHerbert Xu } 7938320c70SHerbert Xu 8038320c70SHerbert Xu static inline struct scatterlist *esp_req_sg(struct crypto_aead *aead, 8138320c70SHerbert Xu struct aead_request *req) 8238320c70SHerbert Xu { 8338320c70SHerbert Xu return (void *)ALIGN((unsigned long)(req + 1) + 8438320c70SHerbert Xu crypto_aead_reqsize(aead), 8538320c70SHerbert Xu __alignof__(struct scatterlist)); 8638320c70SHerbert Xu } 8738320c70SHerbert Xu 8838320c70SHerbert Xu static inline struct scatterlist *esp_givreq_sg( 8938320c70SHerbert Xu struct crypto_aead *aead, struct aead_givcrypt_request *req) 9038320c70SHerbert Xu { 9138320c70SHerbert Xu return (void *)ALIGN((unsigned long)(req + 1) + 9238320c70SHerbert Xu crypto_aead_reqsize(aead), 9338320c70SHerbert Xu __alignof__(struct scatterlist)); 9438320c70SHerbert Xu } 9538320c70SHerbert Xu 9638320c70SHerbert Xu static void esp_output_done(struct crypto_async_request *base, int err) 9738320c70SHerbert Xu { 9838320c70SHerbert Xu struct sk_buff *skb = base->data; 9938320c70SHerbert Xu 10038320c70SHerbert Xu kfree(ESP_SKB_CB(skb)->tmp); 10138320c70SHerbert Xu xfrm_output_resume(skb, err); 10238320c70SHerbert Xu } 10338320c70SHerbert Xu 1041da177e4SLinus Torvalds static int esp_output(struct xfrm_state *x, struct sk_buff *skb) 1051da177e4SLinus Torvalds { 1061da177e4SLinus Torvalds int err; 1071da177e4SLinus Torvalds struct ip_esp_hdr *esph; 10838320c70SHerbert Xu struct crypto_aead *aead; 10938320c70SHerbert Xu struct aead_givcrypt_request *req; 11038320c70SHerbert Xu struct scatterlist *sg; 11138320c70SHerbert Xu struct scatterlist *asg; 1121da177e4SLinus Torvalds struct esp_data *esp; 1131da177e4SLinus Torvalds struct sk_buff *trailer; 11438320c70SHerbert Xu void *tmp; 11538320c70SHerbert Xu u8 *iv; 11627a884dcSArnaldo Carvalho de Melo u8 *tail; 1171da177e4SLinus Torvalds int blksize; 1181da177e4SLinus Torvalds int clen; 1191da177e4SLinus Torvalds int alen; 1201da177e4SLinus Torvalds int nfrags; 1211da177e4SLinus Torvalds 1227b277b1aSHerbert Xu /* skb is pure payload to encrypt */ 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds err = -ENOMEM; 1251da177e4SLinus Torvalds 1261da177e4SLinus Torvalds /* Round to block size */ 1271da177e4SLinus Torvalds clen = skb->len; 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds esp = x->data; 13038320c70SHerbert Xu aead = esp->aead; 13138320c70SHerbert Xu alen = crypto_aead_authsize(aead); 1321da177e4SLinus Torvalds 13338320c70SHerbert Xu blksize = ALIGN(crypto_aead_blocksize(aead), 4); 13438320c70SHerbert Xu clen = ALIGN(clen + 2, blksize); 13538320c70SHerbert Xu if (esp->padlen) 13638320c70SHerbert Xu clen = ALIGN(clen, esp->padlen); 13738320c70SHerbert Xu 13838320c70SHerbert Xu if ((err = skb_cow_data(skb, clen - skb->len + alen, &trailer)) < 0) 1391da177e4SLinus Torvalds goto error; 14038320c70SHerbert Xu nfrags = err; 14138320c70SHerbert Xu 14238320c70SHerbert Xu tmp = esp_alloc_tmp(aead, nfrags + 1); 14338320c70SHerbert Xu if (!tmp) 14438320c70SHerbert Xu goto error; 14538320c70SHerbert Xu 14638320c70SHerbert Xu iv = esp_tmp_iv(aead, tmp); 14738320c70SHerbert Xu req = esp_tmp_givreq(aead, iv); 14838320c70SHerbert Xu asg = esp_givreq_sg(aead, req); 14938320c70SHerbert Xu sg = asg + 1; 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds /* Fill padding... */ 15227a884dcSArnaldo Carvalho de Melo tail = skb_tail_pointer(trailer); 1531da177e4SLinus Torvalds do { 1541da177e4SLinus Torvalds int i; 1551da177e4SLinus Torvalds for (i=0; i<clen-skb->len - 2; i++) 15627a884dcSArnaldo Carvalho de Melo tail[i] = i + 1; 1571da177e4SLinus Torvalds } while (0); 15827a884dcSArnaldo Carvalho de Melo tail[clen - skb->len - 2] = (clen - skb->len) - 2; 15938320c70SHerbert Xu tail[clen - skb->len - 1] = *skb_mac_header(skb); 16038320c70SHerbert Xu pskb_put(skb, trailer, clen - skb->len + alen); 1611da177e4SLinus Torvalds 1627b277b1aSHerbert Xu skb_push(skb, -skb_network_offset(skb)); 16387bdc48dSHerbert Xu esph = ip_esp_hdr(skb); 16437fedd3aSHerbert Xu *skb_mac_header(skb) = IPPROTO_ESP; 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds /* this is non-NULL only with UDP Encapsulation */ 1671da177e4SLinus Torvalds if (x->encap) { 1681da177e4SLinus Torvalds struct xfrm_encap_tmpl *encap = x->encap; 1691da177e4SLinus Torvalds struct udphdr *uh; 170d5a0a1e3SAl Viro __be32 *udpdata32; 1715e226e4dSAl Viro __be16 sport, dport; 17238320c70SHerbert Xu int encap_type; 17338320c70SHerbert Xu 17438320c70SHerbert Xu spin_lock_bh(&x->lock); 17538320c70SHerbert Xu sport = encap->encap_sport; 17638320c70SHerbert Xu dport = encap->encap_dport; 17738320c70SHerbert Xu encap_type = encap->encap_type; 17838320c70SHerbert Xu spin_unlock_bh(&x->lock); 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds uh = (struct udphdr *)esph; 18138320c70SHerbert Xu uh->source = sport; 18238320c70SHerbert Xu uh->dest = dport; 18338320c70SHerbert Xu uh->len = htons(skb->len - skb_transport_offset(skb)); 1841da177e4SLinus Torvalds uh->check = 0; 1851da177e4SLinus Torvalds 18638320c70SHerbert Xu switch (encap_type) { 1871da177e4SLinus Torvalds default: 1881da177e4SLinus Torvalds case UDP_ENCAP_ESPINUDP: 1891da177e4SLinus Torvalds esph = (struct ip_esp_hdr *)(uh + 1); 1901da177e4SLinus Torvalds break; 1911da177e4SLinus Torvalds case UDP_ENCAP_ESPINUDP_NON_IKE: 192d5a0a1e3SAl Viro udpdata32 = (__be32 *)(uh + 1); 1931da177e4SLinus Torvalds udpdata32[0] = udpdata32[1] = 0; 1941da177e4SLinus Torvalds esph = (struct ip_esp_hdr *)(udpdata32 + 2); 1951da177e4SLinus Torvalds break; 1961da177e4SLinus Torvalds } 1971da177e4SLinus Torvalds 19837fedd3aSHerbert Xu *skb_mac_header(skb) = IPPROTO_UDP; 19937fedd3aSHerbert Xu } 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds esph->spi = x->id.spi; 202b318e0e4SHerbert Xu esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output); 2031da177e4SLinus Torvalds 204ed0e7e0cSDavid S. Miller sg_init_table(sg, nfrags); 20551c739d1SDavid S. Miller skb_to_sgvec(skb, sg, 20638320c70SHerbert Xu esph->enc_data + crypto_aead_ivsize(aead) - skb->data, 20738320c70SHerbert Xu clen + alen); 20838320c70SHerbert Xu sg_init_one(asg, esph, sizeof(*esph)); 2091da177e4SLinus Torvalds 21038320c70SHerbert Xu aead_givcrypt_set_callback(req, 0, esp_output_done, skb); 21138320c70SHerbert Xu aead_givcrypt_set_crypt(req, sg, sg, clen, iv); 21238320c70SHerbert Xu aead_givcrypt_set_assoc(req, asg, sizeof(*esph)); 213b318e0e4SHerbert Xu aead_givcrypt_set_giv(req, esph->enc_data, 214b318e0e4SHerbert Xu XFRM_SKB_CB(skb)->seq.output); 2156b7326c8SHerbert Xu 21638320c70SHerbert Xu ESP_SKB_CB(skb)->tmp = tmp; 21738320c70SHerbert Xu err = crypto_aead_givencrypt(req); 21838320c70SHerbert Xu if (err == -EINPROGRESS) 21938320c70SHerbert Xu goto error; 2201da177e4SLinus Torvalds 22138320c70SHerbert Xu if (err == -EBUSY) 22238320c70SHerbert Xu err = NET_XMIT_DROP; 2231da177e4SLinus Torvalds 22438320c70SHerbert Xu kfree(tmp); 225b7c6538cSHerbert Xu 2261da177e4SLinus Torvalds error: 2271da177e4SLinus Torvalds return err; 2281da177e4SLinus Torvalds } 2291da177e4SLinus Torvalds 23038320c70SHerbert Xu static int esp_input_done2(struct sk_buff *skb, int err) 2311da177e4SLinus Torvalds { 2321da177e4SLinus Torvalds struct iphdr *iph; 23338320c70SHerbert Xu struct xfrm_state *x = xfrm_input_state(skb); 2341da177e4SLinus Torvalds struct esp_data *esp = x->data; 23538320c70SHerbert Xu struct crypto_aead *aead = esp->aead; 23638320c70SHerbert Xu int alen = crypto_aead_authsize(aead); 23738320c70SHerbert Xu int hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead); 23838320c70SHerbert Xu int elen = skb->len - hlen; 23931a4ab93SHerbert Xu int ihl; 2404bf05eceSHerbert Xu u8 nexthdr[2]; 2414bf05eceSHerbert Xu int padlen; 2421da177e4SLinus Torvalds 24338320c70SHerbert Xu kfree(ESP_SKB_CB(skb)->tmp); 2440ebea8efSHerbert Xu 2456b7326c8SHerbert Xu if (unlikely(err)) 246668dc8afSHerbert Xu goto out; 2471da177e4SLinus Torvalds 2481da177e4SLinus Torvalds if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2)) 2491da177e4SLinus Torvalds BUG(); 2501da177e4SLinus Torvalds 251668dc8afSHerbert Xu err = -EINVAL; 2521da177e4SLinus Torvalds padlen = nexthdr[0]; 25338320c70SHerbert Xu if (padlen + 2 + alen >= elen) 2541da177e4SLinus Torvalds goto out; 2551da177e4SLinus Torvalds 2561da177e4SLinus Torvalds /* ... check padding bits here. Silly. :-) */ 2571da177e4SLinus Torvalds 258eddc9ec5SArnaldo Carvalho de Melo iph = ip_hdr(skb); 25931a4ab93SHerbert Xu ihl = iph->ihl * 4; 26031a4ab93SHerbert Xu 2611da177e4SLinus Torvalds if (x->encap) { 262752c1f4cSHerbert Xu struct xfrm_encap_tmpl *encap = x->encap; 263d56f90a7SArnaldo Carvalho de Melo struct udphdr *uh = (void *)(skb_network_header(skb) + ihl); 264752c1f4cSHerbert Xu 2651da177e4SLinus Torvalds /* 2661da177e4SLinus Torvalds * 1) if the NAT-T peer's IP or port changed then 2671da177e4SLinus Torvalds * advertize the change to the keying daemon. 2681da177e4SLinus Torvalds * This is an inbound SA, so just compare 2691da177e4SLinus Torvalds * SRC ports. 2701da177e4SLinus Torvalds */ 271752c1f4cSHerbert Xu if (iph->saddr != x->props.saddr.a4 || 272752c1f4cSHerbert Xu uh->source != encap->encap_sport) { 2731da177e4SLinus Torvalds xfrm_address_t ipaddr; 2741da177e4SLinus Torvalds 275752c1f4cSHerbert Xu ipaddr.a4 = iph->saddr; 276752c1f4cSHerbert Xu km_new_mapping(x, &ipaddr, uh->source); 2771da177e4SLinus Torvalds 2781da177e4SLinus Torvalds /* XXX: perhaps add an extra 2791da177e4SLinus Torvalds * policy check here, to see 2801da177e4SLinus Torvalds * if we should allow or 2811da177e4SLinus Torvalds * reject a packet from a 2821da177e4SLinus Torvalds * different source 2831da177e4SLinus Torvalds * address/port. 2841da177e4SLinus Torvalds */ 2851da177e4SLinus Torvalds } 2861da177e4SLinus Torvalds 2871da177e4SLinus Torvalds /* 2881da177e4SLinus Torvalds * 2) ignore UDP/TCP checksums in case 2891da177e4SLinus Torvalds * of NAT-T in Transport Mode, or 2901da177e4SLinus Torvalds * perform other post-processing fixes 291752c1f4cSHerbert Xu * as per draft-ietf-ipsec-udp-encaps-06, 2921da177e4SLinus Torvalds * section 3.1.2 2931da177e4SLinus Torvalds */ 2948bd17075SHerbert Xu if (x->props.mode == XFRM_MODE_TRANSPORT) 2951da177e4SLinus Torvalds skb->ip_summed = CHECKSUM_UNNECESSARY; 296752c1f4cSHerbert Xu } 2971da177e4SLinus Torvalds 298752c1f4cSHerbert Xu pskb_trim(skb, skb->len - alen - padlen - 2); 29938320c70SHerbert Xu __skb_pull(skb, hlen); 300967b05f6SArnaldo Carvalho de Melo skb_set_transport_header(skb, -ihl); 301752c1f4cSHerbert Xu 30238320c70SHerbert Xu err = nexthdr[1]; 30338320c70SHerbert Xu 30438320c70SHerbert Xu /* RFC4303: Drop dummy packets without any error */ 30538320c70SHerbert Xu if (err == IPPROTO_NONE) 30638320c70SHerbert Xu err = -EINVAL; 30738320c70SHerbert Xu 30838320c70SHerbert Xu out: 30938320c70SHerbert Xu return err; 31038320c70SHerbert Xu } 31138320c70SHerbert Xu 31238320c70SHerbert Xu static void esp_input_done(struct crypto_async_request *base, int err) 31338320c70SHerbert Xu { 31438320c70SHerbert Xu struct sk_buff *skb = base->data; 31538320c70SHerbert Xu 31638320c70SHerbert Xu xfrm_input_resume(skb, esp_input_done2(skb, err)); 31738320c70SHerbert Xu } 31838320c70SHerbert Xu 31938320c70SHerbert Xu /* 32038320c70SHerbert Xu * Note: detecting truncated vs. non-truncated authentication data is very 32138320c70SHerbert Xu * expensive, so we only support truncated data, which is the recommended 32238320c70SHerbert Xu * and common case. 32338320c70SHerbert Xu */ 32438320c70SHerbert Xu static int esp_input(struct xfrm_state *x, struct sk_buff *skb) 32538320c70SHerbert Xu { 32638320c70SHerbert Xu struct ip_esp_hdr *esph; 32738320c70SHerbert Xu struct esp_data *esp = x->data; 32838320c70SHerbert Xu struct crypto_aead *aead = esp->aead; 32938320c70SHerbert Xu struct aead_request *req; 33038320c70SHerbert Xu struct sk_buff *trailer; 33138320c70SHerbert Xu int elen = skb->len - sizeof(*esph) - crypto_aead_ivsize(aead); 33238320c70SHerbert Xu int nfrags; 33338320c70SHerbert Xu void *tmp; 33438320c70SHerbert Xu u8 *iv; 33538320c70SHerbert Xu struct scatterlist *sg; 33638320c70SHerbert Xu struct scatterlist *asg; 33738320c70SHerbert Xu int err = -EINVAL; 33838320c70SHerbert Xu 339920fc941SThomas Graf if (!pskb_may_pull(skb, sizeof(*esph) + crypto_aead_ivsize(aead))) 34038320c70SHerbert Xu goto out; 34138320c70SHerbert Xu 34238320c70SHerbert Xu if (elen <= 0) 34338320c70SHerbert Xu goto out; 34438320c70SHerbert Xu 34538320c70SHerbert Xu if ((err = skb_cow_data(skb, 0, &trailer)) < 0) 34638320c70SHerbert Xu goto out; 34738320c70SHerbert Xu nfrags = err; 34838320c70SHerbert Xu 34938320c70SHerbert Xu err = -ENOMEM; 35038320c70SHerbert Xu tmp = esp_alloc_tmp(aead, nfrags + 1); 35138320c70SHerbert Xu if (!tmp) 35238320c70SHerbert Xu goto out; 35338320c70SHerbert Xu 35438320c70SHerbert Xu ESP_SKB_CB(skb)->tmp = tmp; 35538320c70SHerbert Xu iv = esp_tmp_iv(aead, tmp); 35638320c70SHerbert Xu req = esp_tmp_req(aead, iv); 35738320c70SHerbert Xu asg = esp_req_sg(aead, req); 35838320c70SHerbert Xu sg = asg + 1; 35938320c70SHerbert Xu 36038320c70SHerbert Xu skb->ip_summed = CHECKSUM_NONE; 36138320c70SHerbert Xu 36238320c70SHerbert Xu esph = (struct ip_esp_hdr *)skb->data; 36338320c70SHerbert Xu 36438320c70SHerbert Xu /* Get ivec. This can be wrong, check against another impls. */ 36538320c70SHerbert Xu iv = esph->enc_data; 36638320c70SHerbert Xu 36738320c70SHerbert Xu sg_init_table(sg, nfrags); 36838320c70SHerbert Xu skb_to_sgvec(skb, sg, sizeof(*esph) + crypto_aead_ivsize(aead), elen); 36938320c70SHerbert Xu sg_init_one(asg, esph, sizeof(*esph)); 37038320c70SHerbert Xu 37138320c70SHerbert Xu aead_request_set_callback(req, 0, esp_input_done, skb); 37238320c70SHerbert Xu aead_request_set_crypt(req, sg, sg, elen, iv); 37338320c70SHerbert Xu aead_request_set_assoc(req, asg, sizeof(*esph)); 37438320c70SHerbert Xu 37538320c70SHerbert Xu err = crypto_aead_decrypt(req); 37638320c70SHerbert Xu if (err == -EINPROGRESS) 37738320c70SHerbert Xu goto out; 37838320c70SHerbert Xu 37938320c70SHerbert Xu err = esp_input_done2(skb, err); 380752c1f4cSHerbert Xu 381752c1f4cSHerbert Xu out: 382668dc8afSHerbert Xu return err; 3831da177e4SLinus Torvalds } 3841da177e4SLinus Torvalds 385c5c25238SPatrick McHardy static u32 esp4_get_mtu(struct xfrm_state *x, int mtu) 3861da177e4SLinus Torvalds { 3871da177e4SLinus Torvalds struct esp_data *esp = x->data; 38838320c70SHerbert Xu u32 blksize = ALIGN(crypto_aead_blocksize(esp->aead), 4); 38938320c70SHerbert Xu u32 align = max_t(u32, blksize, esp->padlen); 390c5c25238SPatrick McHardy u32 rem; 391c5c25238SPatrick McHardy 39238320c70SHerbert Xu mtu -= x->props.header_len + crypto_aead_authsize(esp->aead); 393c5c25238SPatrick McHardy rem = mtu & (align - 1); 394c5c25238SPatrick McHardy mtu &= ~(align - 1); 3951da177e4SLinus Torvalds 3960a69452cSDiego Beltrami switch (x->props.mode) { 3970a69452cSDiego Beltrami case XFRM_MODE_TUNNEL: 3980a69452cSDiego Beltrami break; 3990a69452cSDiego Beltrami default: 4000a69452cSDiego Beltrami case XFRM_MODE_TRANSPORT: 4010a69452cSDiego Beltrami /* The worst case */ 402c5c25238SPatrick McHardy mtu -= blksize - 4; 403c5c25238SPatrick McHardy mtu += min_t(u32, blksize - 4, rem); 4040a69452cSDiego Beltrami break; 4050a69452cSDiego Beltrami case XFRM_MODE_BEET: 4060a69452cSDiego Beltrami /* The worst case. */ 407c5c25238SPatrick McHardy mtu += min_t(u32, IPV4_BEET_PHMAXLEN, rem); 4080a69452cSDiego Beltrami break; 4091da177e4SLinus Torvalds } 4100a69452cSDiego Beltrami 411c5c25238SPatrick McHardy return mtu - 2; 4121da177e4SLinus Torvalds } 4131da177e4SLinus Torvalds 4141da177e4SLinus Torvalds static void esp4_err(struct sk_buff *skb, u32 info) 4151da177e4SLinus Torvalds { 4164fb236baSAlexey Dobriyan struct net *net = dev_net(skb->dev); 4171da177e4SLinus Torvalds struct iphdr *iph = (struct iphdr *)skb->data; 4181da177e4SLinus Torvalds struct ip_esp_hdr *esph = (struct ip_esp_hdr *)(skb->data+(iph->ihl<<2)); 4191da177e4SLinus Torvalds struct xfrm_state *x; 4201da177e4SLinus Torvalds 42188c7664fSArnaldo Carvalho de Melo if (icmp_hdr(skb)->type != ICMP_DEST_UNREACH || 42288c7664fSArnaldo Carvalho de Melo icmp_hdr(skb)->code != ICMP_FRAG_NEEDED) 4231da177e4SLinus Torvalds return; 4241da177e4SLinus Torvalds 4254fb236baSAlexey Dobriyan x = xfrm_state_lookup(net, (xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET); 4261da177e4SLinus Torvalds if (!x) 4271da177e4SLinus Torvalds return; 42864ce2073SPatrick McHardy NETDEBUG(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%08x\n", 42964ce2073SPatrick McHardy ntohl(esph->spi), ntohl(iph->daddr)); 4301da177e4SLinus Torvalds xfrm_state_put(x); 4311da177e4SLinus Torvalds } 4321da177e4SLinus Torvalds 4331da177e4SLinus Torvalds static void esp_destroy(struct xfrm_state *x) 4341da177e4SLinus Torvalds { 4351da177e4SLinus Torvalds struct esp_data *esp = x->data; 4361da177e4SLinus Torvalds 4371da177e4SLinus Torvalds if (!esp) 4381da177e4SLinus Torvalds return; 4391da177e4SLinus Torvalds 44038320c70SHerbert Xu crypto_free_aead(esp->aead); 4411da177e4SLinus Torvalds kfree(esp); 4421da177e4SLinus Torvalds } 4431da177e4SLinus Torvalds 4441a6509d9SHerbert Xu static int esp_init_aead(struct xfrm_state *x) 4451da177e4SLinus Torvalds { 4461a6509d9SHerbert Xu struct esp_data *esp = x->data; 4471a6509d9SHerbert Xu struct crypto_aead *aead; 4481a6509d9SHerbert Xu int err; 4491a6509d9SHerbert Xu 4501a6509d9SHerbert Xu aead = crypto_alloc_aead(x->aead->alg_name, 0, 0); 4511a6509d9SHerbert Xu err = PTR_ERR(aead); 4521a6509d9SHerbert Xu if (IS_ERR(aead)) 4531a6509d9SHerbert Xu goto error; 4541a6509d9SHerbert Xu 4551a6509d9SHerbert Xu esp->aead = aead; 4561a6509d9SHerbert Xu 4571a6509d9SHerbert Xu err = crypto_aead_setkey(aead, x->aead->alg_key, 4581a6509d9SHerbert Xu (x->aead->alg_key_len + 7) / 8); 4591a6509d9SHerbert Xu if (err) 4601a6509d9SHerbert Xu goto error; 4611a6509d9SHerbert Xu 4621a6509d9SHerbert Xu err = crypto_aead_setauthsize(aead, x->aead->alg_icv_len / 8); 4631a6509d9SHerbert Xu if (err) 4641a6509d9SHerbert Xu goto error; 4651a6509d9SHerbert Xu 4661a6509d9SHerbert Xu error: 4671a6509d9SHerbert Xu return err; 4681a6509d9SHerbert Xu } 4691a6509d9SHerbert Xu 4701a6509d9SHerbert Xu static int esp_init_authenc(struct xfrm_state *x) 4711a6509d9SHerbert Xu { 4721a6509d9SHerbert Xu struct esp_data *esp = x->data; 47338320c70SHerbert Xu struct crypto_aead *aead; 47438320c70SHerbert Xu struct crypto_authenc_key_param *param; 47538320c70SHerbert Xu struct rtattr *rta; 47638320c70SHerbert Xu char *key; 47738320c70SHerbert Xu char *p; 47838320c70SHerbert Xu char authenc_name[CRYPTO_MAX_ALG_NAME]; 47938320c70SHerbert Xu unsigned int keylen; 48038320c70SHerbert Xu int err; 4811da177e4SLinus Torvalds 4821a6509d9SHerbert Xu err = -EINVAL; 4831da177e4SLinus Torvalds if (x->ealg == NULL) 4841a6509d9SHerbert Xu goto error; 48538320c70SHerbert Xu 4861a6509d9SHerbert Xu err = -ENAMETOOLONG; 48738320c70SHerbert Xu if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME, "authenc(%s,%s)", 48838320c70SHerbert Xu x->aalg ? x->aalg->alg_name : "digest_null", 48938320c70SHerbert Xu x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME) 4901a6509d9SHerbert Xu goto error; 49138320c70SHerbert Xu 49238320c70SHerbert Xu aead = crypto_alloc_aead(authenc_name, 0, 0); 49338320c70SHerbert Xu err = PTR_ERR(aead); 49438320c70SHerbert Xu if (IS_ERR(aead)) 49538320c70SHerbert Xu goto error; 49638320c70SHerbert Xu 49738320c70SHerbert Xu esp->aead = aead; 49838320c70SHerbert Xu 49938320c70SHerbert Xu keylen = (x->aalg ? (x->aalg->alg_key_len + 7) / 8 : 0) + 50038320c70SHerbert Xu (x->ealg->alg_key_len + 7) / 8 + RTA_SPACE(sizeof(*param)); 50138320c70SHerbert Xu err = -ENOMEM; 50238320c70SHerbert Xu key = kmalloc(keylen, GFP_KERNEL); 50338320c70SHerbert Xu if (!key) 50438320c70SHerbert Xu goto error; 50538320c70SHerbert Xu 50638320c70SHerbert Xu p = key; 50738320c70SHerbert Xu rta = (void *)p; 50838320c70SHerbert Xu rta->rta_type = CRYPTO_AUTHENC_KEYA_PARAM; 50938320c70SHerbert Xu rta->rta_len = RTA_LENGTH(sizeof(*param)); 51038320c70SHerbert Xu param = RTA_DATA(rta); 51138320c70SHerbert Xu p += RTA_SPACE(sizeof(*param)); 51238320c70SHerbert Xu 5131da177e4SLinus Torvalds if (x->aalg) { 5141da177e4SLinus Torvalds struct xfrm_algo_desc *aalg_desc; 5151da177e4SLinus Torvalds 51638320c70SHerbert Xu memcpy(p, x->aalg->alg_key, (x->aalg->alg_key_len + 7) / 8); 51738320c70SHerbert Xu p += (x->aalg->alg_key_len + 7) / 8; 5181da177e4SLinus Torvalds 5191da177e4SLinus Torvalds aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0); 5201da177e4SLinus Torvalds BUG_ON(!aalg_desc); 5211da177e4SLinus Torvalds 52238320c70SHerbert Xu err = -EINVAL; 5231da177e4SLinus Torvalds if (aalg_desc->uinfo.auth.icv_fullbits/8 != 52438320c70SHerbert Xu crypto_aead_authsize(aead)) { 52564ce2073SPatrick McHardy NETDEBUG(KERN_INFO "ESP: %s digestsize %u != %hu\n", 5261da177e4SLinus Torvalds x->aalg->alg_name, 52738320c70SHerbert Xu crypto_aead_authsize(aead), 52864ce2073SPatrick McHardy aalg_desc->uinfo.auth.icv_fullbits/8); 52938320c70SHerbert Xu goto free_key; 5301da177e4SLinus Torvalds } 5311da177e4SLinus Torvalds 53238320c70SHerbert Xu err = crypto_aead_setauthsize( 53338320c70SHerbert Xu aead, aalg_desc->uinfo.auth.icv_truncbits / 8); 53438320c70SHerbert Xu if (err) 53538320c70SHerbert Xu goto free_key; 5361da177e4SLinus Torvalds } 5374b7137ffSHerbert Xu 53838320c70SHerbert Xu param->enckeylen = cpu_to_be32((x->ealg->alg_key_len + 7) / 8); 53938320c70SHerbert Xu memcpy(p, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8); 54038320c70SHerbert Xu 54138320c70SHerbert Xu err = crypto_aead_setkey(aead, key, keylen); 54238320c70SHerbert Xu 54338320c70SHerbert Xu free_key: 54438320c70SHerbert Xu kfree(key); 54538320c70SHerbert Xu 5461a6509d9SHerbert Xu error: 5471a6509d9SHerbert Xu return err; 5481a6509d9SHerbert Xu } 5491a6509d9SHerbert Xu 5501a6509d9SHerbert Xu static int esp_init_state(struct xfrm_state *x) 5511a6509d9SHerbert Xu { 5521a6509d9SHerbert Xu struct esp_data *esp; 5531a6509d9SHerbert Xu struct crypto_aead *aead; 5541a6509d9SHerbert Xu u32 align; 5551a6509d9SHerbert Xu int err; 5561a6509d9SHerbert Xu 5571a6509d9SHerbert Xu esp = kzalloc(sizeof(*esp), GFP_KERNEL); 5581a6509d9SHerbert Xu if (esp == NULL) 5591a6509d9SHerbert Xu return -ENOMEM; 5601a6509d9SHerbert Xu 5611a6509d9SHerbert Xu x->data = esp; 5621a6509d9SHerbert Xu 5631a6509d9SHerbert Xu if (x->aead) 5641a6509d9SHerbert Xu err = esp_init_aead(x); 5651a6509d9SHerbert Xu else 5661a6509d9SHerbert Xu err = esp_init_authenc(x); 5671a6509d9SHerbert Xu 56838320c70SHerbert Xu if (err) 5691da177e4SLinus Torvalds goto error; 57038320c70SHerbert Xu 5711a6509d9SHerbert Xu aead = esp->aead; 5721a6509d9SHerbert Xu 5731a6509d9SHerbert Xu esp->padlen = 0; 5741a6509d9SHerbert Xu 57538320c70SHerbert Xu x->props.header_len = sizeof(struct ip_esp_hdr) + 57638320c70SHerbert Xu crypto_aead_ivsize(aead); 5777e49e6deSMasahide NAKAMURA if (x->props.mode == XFRM_MODE_TUNNEL) 5781da177e4SLinus Torvalds x->props.header_len += sizeof(struct iphdr); 579eb49e630SJoakim Koskela else if (x->props.mode == XFRM_MODE_BEET && x->sel.family != AF_INET6) 580ac758e3cSPatrick McHardy x->props.header_len += IPV4_BEET_PHMAXLEN; 5811da177e4SLinus Torvalds if (x->encap) { 5821da177e4SLinus Torvalds struct xfrm_encap_tmpl *encap = x->encap; 5831da177e4SLinus Torvalds 5841da177e4SLinus Torvalds switch (encap->encap_type) { 5851da177e4SLinus Torvalds default: 5861da177e4SLinus Torvalds goto error; 5871da177e4SLinus Torvalds case UDP_ENCAP_ESPINUDP: 5881da177e4SLinus Torvalds x->props.header_len += sizeof(struct udphdr); 5891da177e4SLinus Torvalds break; 5901da177e4SLinus Torvalds case UDP_ENCAP_ESPINUDP_NON_IKE: 5911da177e4SLinus Torvalds x->props.header_len += sizeof(struct udphdr) + 2 * sizeof(u32); 5921da177e4SLinus Torvalds break; 5931da177e4SLinus Torvalds } 5941da177e4SLinus Torvalds } 59538320c70SHerbert Xu 59638320c70SHerbert Xu align = ALIGN(crypto_aead_blocksize(aead), 4); 59738320c70SHerbert Xu if (esp->padlen) 59838320c70SHerbert Xu align = max_t(u32, align, esp->padlen); 59938320c70SHerbert Xu x->props.trailer_len = align + 1 + crypto_aead_authsize(esp->aead); 6001da177e4SLinus Torvalds 6011da177e4SLinus Torvalds error: 60238320c70SHerbert Xu return err; 6031da177e4SLinus Torvalds } 6041da177e4SLinus Torvalds 605533cb5b0SEric Dumazet static const struct xfrm_type esp_type = 6061da177e4SLinus Torvalds { 6071da177e4SLinus Torvalds .description = "ESP4", 6081da177e4SLinus Torvalds .owner = THIS_MODULE, 6091da177e4SLinus Torvalds .proto = IPPROTO_ESP, 610436a0a40SHerbert Xu .flags = XFRM_TYPE_REPLAY_PROT, 6111da177e4SLinus Torvalds .init_state = esp_init_state, 6121da177e4SLinus Torvalds .destructor = esp_destroy, 613c5c25238SPatrick McHardy .get_mtu = esp4_get_mtu, 6141da177e4SLinus Torvalds .input = esp_input, 6151da177e4SLinus Torvalds .output = esp_output 6161da177e4SLinus Torvalds }; 6171da177e4SLinus Torvalds 618*32613090SAlexey Dobriyan static const struct net_protocol esp4_protocol = { 6191da177e4SLinus Torvalds .handler = xfrm4_rcv, 6201da177e4SLinus Torvalds .err_handler = esp4_err, 6211da177e4SLinus Torvalds .no_policy = 1, 6224fb236baSAlexey Dobriyan .netns_ok = 1, 6231da177e4SLinus Torvalds }; 6241da177e4SLinus Torvalds 6251da177e4SLinus Torvalds static int __init esp4_init(void) 6261da177e4SLinus Torvalds { 6271da177e4SLinus Torvalds if (xfrm_register_type(&esp_type, AF_INET) < 0) { 6281da177e4SLinus Torvalds printk(KERN_INFO "ip esp init: can't add xfrm type\n"); 6291da177e4SLinus Torvalds return -EAGAIN; 6301da177e4SLinus Torvalds } 6311da177e4SLinus Torvalds if (inet_add_protocol(&esp4_protocol, IPPROTO_ESP) < 0) { 6321da177e4SLinus Torvalds printk(KERN_INFO "ip esp init: can't add protocol\n"); 6331da177e4SLinus Torvalds xfrm_unregister_type(&esp_type, AF_INET); 6341da177e4SLinus Torvalds return -EAGAIN; 6351da177e4SLinus Torvalds } 6361da177e4SLinus Torvalds return 0; 6371da177e4SLinus Torvalds } 6381da177e4SLinus Torvalds 6391da177e4SLinus Torvalds static void __exit esp4_fini(void) 6401da177e4SLinus Torvalds { 6411da177e4SLinus Torvalds if (inet_del_protocol(&esp4_protocol, IPPROTO_ESP) < 0) 6421da177e4SLinus Torvalds printk(KERN_INFO "ip esp close: can't remove protocol\n"); 6431da177e4SLinus Torvalds if (xfrm_unregister_type(&esp_type, AF_INET) < 0) 6441da177e4SLinus Torvalds printk(KERN_INFO "ip esp close: can't remove xfrm type\n"); 6451da177e4SLinus Torvalds } 6461da177e4SLinus Torvalds 6471da177e4SLinus Torvalds module_init(esp4_init); 6481da177e4SLinus Torvalds module_exit(esp4_fini); 6491da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 650d3d6dd3aSMasahide NAKAMURA MODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_ESP); 651