162306a36Sopenharmony_ci/* Copyright (c) 2018, Mellanox Technologies All rights reserved. 262306a36Sopenharmony_ci * 362306a36Sopenharmony_ci * This software is available to you under a choice of one of two 462306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 562306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 662306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 762306a36Sopenharmony_ci * OpenIB.org BSD license below: 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1062306a36Sopenharmony_ci * without modification, are permitted provided that the following 1162306a36Sopenharmony_ci * conditions are met: 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1462306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1562306a36Sopenharmony_ci * disclaimer. 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 1862306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1962306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2062306a36Sopenharmony_ci * provided with the distribution. 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2362306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2462306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2562306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2662306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2762306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2862306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 2962306a36Sopenharmony_ci * SOFTWARE. 3062306a36Sopenharmony_ci */ 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include <net/tls.h> 3362306a36Sopenharmony_ci#include <crypto/aead.h> 3462306a36Sopenharmony_ci#include <crypto/scatterwalk.h> 3562306a36Sopenharmony_ci#include <net/ip6_checksum.h> 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include "tls.h" 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic void chain_to_walk(struct scatterlist *sg, struct scatter_walk *walk) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci struct scatterlist *src = walk->sg; 4262306a36Sopenharmony_ci int diff = walk->offset - src->offset; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci sg_set_page(sg, sg_page(src), 4562306a36Sopenharmony_ci src->length - diff, walk->offset); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci scatterwalk_crypto_chain(sg, sg_next(src), 2); 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic int tls_enc_record(struct aead_request *aead_req, 5162306a36Sopenharmony_ci struct crypto_aead *aead, char *aad, 5262306a36Sopenharmony_ci char *iv, __be64 rcd_sn, 5362306a36Sopenharmony_ci struct scatter_walk *in, 5462306a36Sopenharmony_ci struct scatter_walk *out, int *in_len, 5562306a36Sopenharmony_ci struct tls_prot_info *prot) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci unsigned char buf[TLS_HEADER_SIZE + MAX_IV_SIZE]; 5862306a36Sopenharmony_ci const struct tls_cipher_desc *cipher_desc; 5962306a36Sopenharmony_ci struct scatterlist sg_in[3]; 6062306a36Sopenharmony_ci struct scatterlist sg_out[3]; 6162306a36Sopenharmony_ci unsigned int buf_size; 6262306a36Sopenharmony_ci u16 len; 6362306a36Sopenharmony_ci int rc; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci switch (prot->cipher_type) { 6662306a36Sopenharmony_ci case TLS_CIPHER_AES_GCM_128: 6762306a36Sopenharmony_ci case TLS_CIPHER_AES_GCM_256: 6862306a36Sopenharmony_ci break; 6962306a36Sopenharmony_ci default: 7062306a36Sopenharmony_ci return -EINVAL; 7162306a36Sopenharmony_ci } 7262306a36Sopenharmony_ci cipher_desc = get_cipher_desc(prot->cipher_type); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci buf_size = TLS_HEADER_SIZE + cipher_desc->iv; 7562306a36Sopenharmony_ci len = min_t(int, *in_len, buf_size); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci scatterwalk_copychunks(buf, in, len, 0); 7862306a36Sopenharmony_ci scatterwalk_copychunks(buf, out, len, 1); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci *in_len -= len; 8162306a36Sopenharmony_ci if (!*in_len) 8262306a36Sopenharmony_ci return 0; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci scatterwalk_pagedone(in, 0, 1); 8562306a36Sopenharmony_ci scatterwalk_pagedone(out, 1, 1); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci len = buf[4] | (buf[3] << 8); 8862306a36Sopenharmony_ci len -= cipher_desc->iv; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci tls_make_aad(aad, len - cipher_desc->tag, (char *)&rcd_sn, buf[0], prot); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci memcpy(iv + cipher_desc->salt, buf + TLS_HEADER_SIZE, cipher_desc->iv); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci sg_init_table(sg_in, ARRAY_SIZE(sg_in)); 9562306a36Sopenharmony_ci sg_init_table(sg_out, ARRAY_SIZE(sg_out)); 9662306a36Sopenharmony_ci sg_set_buf(sg_in, aad, TLS_AAD_SPACE_SIZE); 9762306a36Sopenharmony_ci sg_set_buf(sg_out, aad, TLS_AAD_SPACE_SIZE); 9862306a36Sopenharmony_ci chain_to_walk(sg_in + 1, in); 9962306a36Sopenharmony_ci chain_to_walk(sg_out + 1, out); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci *in_len -= len; 10262306a36Sopenharmony_ci if (*in_len < 0) { 10362306a36Sopenharmony_ci *in_len += cipher_desc->tag; 10462306a36Sopenharmony_ci /* the input buffer doesn't contain the entire record. 10562306a36Sopenharmony_ci * trim len accordingly. The resulting authentication tag 10662306a36Sopenharmony_ci * will contain garbage, but we don't care, so we won't 10762306a36Sopenharmony_ci * include any of it in the output skb 10862306a36Sopenharmony_ci * Note that we assume the output buffer length 10962306a36Sopenharmony_ci * is larger then input buffer length + tag size 11062306a36Sopenharmony_ci */ 11162306a36Sopenharmony_ci if (*in_len < 0) 11262306a36Sopenharmony_ci len += *in_len; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci *in_len = 0; 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci if (*in_len) { 11862306a36Sopenharmony_ci scatterwalk_copychunks(NULL, in, len, 2); 11962306a36Sopenharmony_ci scatterwalk_pagedone(in, 0, 1); 12062306a36Sopenharmony_ci scatterwalk_copychunks(NULL, out, len, 2); 12162306a36Sopenharmony_ci scatterwalk_pagedone(out, 1, 1); 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci len -= cipher_desc->tag; 12562306a36Sopenharmony_ci aead_request_set_crypt(aead_req, sg_in, sg_out, len, iv); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci rc = crypto_aead_encrypt(aead_req); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci return rc; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic void tls_init_aead_request(struct aead_request *aead_req, 13362306a36Sopenharmony_ci struct crypto_aead *aead) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci aead_request_set_tfm(aead_req, aead); 13662306a36Sopenharmony_ci aead_request_set_ad(aead_req, TLS_AAD_SPACE_SIZE); 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic struct aead_request *tls_alloc_aead_request(struct crypto_aead *aead, 14062306a36Sopenharmony_ci gfp_t flags) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci unsigned int req_size = sizeof(struct aead_request) + 14362306a36Sopenharmony_ci crypto_aead_reqsize(aead); 14462306a36Sopenharmony_ci struct aead_request *aead_req; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci aead_req = kzalloc(req_size, flags); 14762306a36Sopenharmony_ci if (aead_req) 14862306a36Sopenharmony_ci tls_init_aead_request(aead_req, aead); 14962306a36Sopenharmony_ci return aead_req; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic int tls_enc_records(struct aead_request *aead_req, 15362306a36Sopenharmony_ci struct crypto_aead *aead, struct scatterlist *sg_in, 15462306a36Sopenharmony_ci struct scatterlist *sg_out, char *aad, char *iv, 15562306a36Sopenharmony_ci u64 rcd_sn, int len, struct tls_prot_info *prot) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci struct scatter_walk out, in; 15862306a36Sopenharmony_ci int rc; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci scatterwalk_start(&in, sg_in); 16162306a36Sopenharmony_ci scatterwalk_start(&out, sg_out); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci do { 16462306a36Sopenharmony_ci rc = tls_enc_record(aead_req, aead, aad, iv, 16562306a36Sopenharmony_ci cpu_to_be64(rcd_sn), &in, &out, &len, prot); 16662306a36Sopenharmony_ci rcd_sn++; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci } while (rc == 0 && len); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci scatterwalk_done(&in, 0, 0); 17162306a36Sopenharmony_ci scatterwalk_done(&out, 1, 0); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci return rc; 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci/* Can't use icsk->icsk_af_ops->send_check here because the ip addresses 17762306a36Sopenharmony_ci * might have been changed by NAT. 17862306a36Sopenharmony_ci */ 17962306a36Sopenharmony_cistatic void update_chksum(struct sk_buff *skb, int headln) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci struct tcphdr *th = tcp_hdr(skb); 18262306a36Sopenharmony_ci int datalen = skb->len - headln; 18362306a36Sopenharmony_ci const struct ipv6hdr *ipv6h; 18462306a36Sopenharmony_ci const struct iphdr *iph; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci /* We only changed the payload so if we are using partial we don't 18762306a36Sopenharmony_ci * need to update anything. 18862306a36Sopenharmony_ci */ 18962306a36Sopenharmony_ci if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) 19062306a36Sopenharmony_ci return; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_PARTIAL; 19362306a36Sopenharmony_ci skb->csum_start = skb_transport_header(skb) - skb->head; 19462306a36Sopenharmony_ci skb->csum_offset = offsetof(struct tcphdr, check); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (skb->sk->sk_family == AF_INET6) { 19762306a36Sopenharmony_ci ipv6h = ipv6_hdr(skb); 19862306a36Sopenharmony_ci th->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, 19962306a36Sopenharmony_ci datalen, IPPROTO_TCP, 0); 20062306a36Sopenharmony_ci } else { 20162306a36Sopenharmony_ci iph = ip_hdr(skb); 20262306a36Sopenharmony_ci th->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, datalen, 20362306a36Sopenharmony_ci IPPROTO_TCP, 0); 20462306a36Sopenharmony_ci } 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistatic void complete_skb(struct sk_buff *nskb, struct sk_buff *skb, int headln) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci struct sock *sk = skb->sk; 21062306a36Sopenharmony_ci int delta; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci skb_copy_header(nskb, skb); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci skb_put(nskb, skb->len); 21562306a36Sopenharmony_ci memcpy(nskb->data, skb->data, headln); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci nskb->destructor = skb->destructor; 21862306a36Sopenharmony_ci nskb->sk = sk; 21962306a36Sopenharmony_ci skb->destructor = NULL; 22062306a36Sopenharmony_ci skb->sk = NULL; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci update_chksum(nskb, headln); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci /* sock_efree means skb must gone through skb_orphan_partial() */ 22562306a36Sopenharmony_ci if (nskb->destructor == sock_efree) 22662306a36Sopenharmony_ci return; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci delta = nskb->truesize - skb->truesize; 22962306a36Sopenharmony_ci if (likely(delta < 0)) 23062306a36Sopenharmony_ci WARN_ON_ONCE(refcount_sub_and_test(-delta, &sk->sk_wmem_alloc)); 23162306a36Sopenharmony_ci else if (delta) 23262306a36Sopenharmony_ci refcount_add(delta, &sk->sk_wmem_alloc); 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci/* This function may be called after the user socket is already 23662306a36Sopenharmony_ci * closed so make sure we don't use anything freed during 23762306a36Sopenharmony_ci * tls_sk_proto_close here 23862306a36Sopenharmony_ci */ 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic int fill_sg_in(struct scatterlist *sg_in, 24162306a36Sopenharmony_ci struct sk_buff *skb, 24262306a36Sopenharmony_ci struct tls_offload_context_tx *ctx, 24362306a36Sopenharmony_ci u64 *rcd_sn, 24462306a36Sopenharmony_ci s32 *sync_size, 24562306a36Sopenharmony_ci int *resync_sgs) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci int tcp_payload_offset = skb_tcp_all_headers(skb); 24862306a36Sopenharmony_ci int payload_len = skb->len - tcp_payload_offset; 24962306a36Sopenharmony_ci u32 tcp_seq = ntohl(tcp_hdr(skb)->seq); 25062306a36Sopenharmony_ci struct tls_record_info *record; 25162306a36Sopenharmony_ci unsigned long flags; 25262306a36Sopenharmony_ci int remaining; 25362306a36Sopenharmony_ci int i; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci spin_lock_irqsave(&ctx->lock, flags); 25662306a36Sopenharmony_ci record = tls_get_record(ctx, tcp_seq, rcd_sn); 25762306a36Sopenharmony_ci if (!record) { 25862306a36Sopenharmony_ci spin_unlock_irqrestore(&ctx->lock, flags); 25962306a36Sopenharmony_ci return -EINVAL; 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci *sync_size = tcp_seq - tls_record_start_seq(record); 26362306a36Sopenharmony_ci if (*sync_size < 0) { 26462306a36Sopenharmony_ci int is_start_marker = tls_record_is_start_marker(record); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci spin_unlock_irqrestore(&ctx->lock, flags); 26762306a36Sopenharmony_ci /* This should only occur if the relevant record was 26862306a36Sopenharmony_ci * already acked. In that case it should be ok 26962306a36Sopenharmony_ci * to drop the packet and avoid retransmission. 27062306a36Sopenharmony_ci * 27162306a36Sopenharmony_ci * There is a corner case where the packet contains 27262306a36Sopenharmony_ci * both an acked and a non-acked record. 27362306a36Sopenharmony_ci * We currently don't handle that case and rely 27462306a36Sopenharmony_ci * on TCP to retransmit a packet that doesn't contain 27562306a36Sopenharmony_ci * already acked payload. 27662306a36Sopenharmony_ci */ 27762306a36Sopenharmony_ci if (!is_start_marker) 27862306a36Sopenharmony_ci *sync_size = 0; 27962306a36Sopenharmony_ci return -EINVAL; 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci remaining = *sync_size; 28362306a36Sopenharmony_ci for (i = 0; remaining > 0; i++) { 28462306a36Sopenharmony_ci skb_frag_t *frag = &record->frags[i]; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci __skb_frag_ref(frag); 28762306a36Sopenharmony_ci sg_set_page(sg_in + i, skb_frag_page(frag), 28862306a36Sopenharmony_ci skb_frag_size(frag), skb_frag_off(frag)); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci remaining -= skb_frag_size(frag); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (remaining < 0) 29362306a36Sopenharmony_ci sg_in[i].length += remaining; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci *resync_sgs = i; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci spin_unlock_irqrestore(&ctx->lock, flags); 29862306a36Sopenharmony_ci if (skb_to_sgvec(skb, &sg_in[i], tcp_payload_offset, payload_len) < 0) 29962306a36Sopenharmony_ci return -EINVAL; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci return 0; 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic void fill_sg_out(struct scatterlist sg_out[3], void *buf, 30562306a36Sopenharmony_ci struct tls_context *tls_ctx, 30662306a36Sopenharmony_ci struct sk_buff *nskb, 30762306a36Sopenharmony_ci int tcp_payload_offset, 30862306a36Sopenharmony_ci int payload_len, 30962306a36Sopenharmony_ci int sync_size, 31062306a36Sopenharmony_ci void *dummy_buf) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci const struct tls_cipher_desc *cipher_desc = 31362306a36Sopenharmony_ci get_cipher_desc(tls_ctx->crypto_send.info.cipher_type); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci sg_set_buf(&sg_out[0], dummy_buf, sync_size); 31662306a36Sopenharmony_ci sg_set_buf(&sg_out[1], nskb->data + tcp_payload_offset, payload_len); 31762306a36Sopenharmony_ci /* Add room for authentication tag produced by crypto */ 31862306a36Sopenharmony_ci dummy_buf += sync_size; 31962306a36Sopenharmony_ci sg_set_buf(&sg_out[2], dummy_buf, cipher_desc->tag); 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cistatic struct sk_buff *tls_enc_skb(struct tls_context *tls_ctx, 32362306a36Sopenharmony_ci struct scatterlist sg_out[3], 32462306a36Sopenharmony_ci struct scatterlist *sg_in, 32562306a36Sopenharmony_ci struct sk_buff *skb, 32662306a36Sopenharmony_ci s32 sync_size, u64 rcd_sn) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci struct tls_offload_context_tx *ctx = tls_offload_ctx_tx(tls_ctx); 32962306a36Sopenharmony_ci int tcp_payload_offset = skb_tcp_all_headers(skb); 33062306a36Sopenharmony_ci int payload_len = skb->len - tcp_payload_offset; 33162306a36Sopenharmony_ci const struct tls_cipher_desc *cipher_desc; 33262306a36Sopenharmony_ci void *buf, *iv, *aad, *dummy_buf, *salt; 33362306a36Sopenharmony_ci struct aead_request *aead_req; 33462306a36Sopenharmony_ci struct sk_buff *nskb = NULL; 33562306a36Sopenharmony_ci int buf_len; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci aead_req = tls_alloc_aead_request(ctx->aead_send, GFP_ATOMIC); 33862306a36Sopenharmony_ci if (!aead_req) 33962306a36Sopenharmony_ci return NULL; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci switch (tls_ctx->crypto_send.info.cipher_type) { 34262306a36Sopenharmony_ci case TLS_CIPHER_AES_GCM_128: 34362306a36Sopenharmony_ci salt = tls_ctx->crypto_send.aes_gcm_128.salt; 34462306a36Sopenharmony_ci break; 34562306a36Sopenharmony_ci case TLS_CIPHER_AES_GCM_256: 34662306a36Sopenharmony_ci salt = tls_ctx->crypto_send.aes_gcm_256.salt; 34762306a36Sopenharmony_ci break; 34862306a36Sopenharmony_ci default: 34962306a36Sopenharmony_ci goto free_req; 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci cipher_desc = get_cipher_desc(tls_ctx->crypto_send.info.cipher_type); 35262306a36Sopenharmony_ci buf_len = cipher_desc->salt + cipher_desc->iv + TLS_AAD_SPACE_SIZE + 35362306a36Sopenharmony_ci sync_size + cipher_desc->tag; 35462306a36Sopenharmony_ci buf = kmalloc(buf_len, GFP_ATOMIC); 35562306a36Sopenharmony_ci if (!buf) 35662306a36Sopenharmony_ci goto free_req; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci iv = buf; 35962306a36Sopenharmony_ci memcpy(iv, salt, cipher_desc->salt); 36062306a36Sopenharmony_ci aad = buf + cipher_desc->salt + cipher_desc->iv; 36162306a36Sopenharmony_ci dummy_buf = aad + TLS_AAD_SPACE_SIZE; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci nskb = alloc_skb(skb_headroom(skb) + skb->len, GFP_ATOMIC); 36462306a36Sopenharmony_ci if (!nskb) 36562306a36Sopenharmony_ci goto free_buf; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci skb_reserve(nskb, skb_headroom(skb)); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci fill_sg_out(sg_out, buf, tls_ctx, nskb, tcp_payload_offset, 37062306a36Sopenharmony_ci payload_len, sync_size, dummy_buf); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if (tls_enc_records(aead_req, ctx->aead_send, sg_in, sg_out, aad, iv, 37362306a36Sopenharmony_ci rcd_sn, sync_size + payload_len, 37462306a36Sopenharmony_ci &tls_ctx->prot_info) < 0) 37562306a36Sopenharmony_ci goto free_nskb; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci complete_skb(nskb, skb, tcp_payload_offset); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci /* validate_xmit_skb_list assumes that if the skb wasn't segmented 38062306a36Sopenharmony_ci * nskb->prev will point to the skb itself 38162306a36Sopenharmony_ci */ 38262306a36Sopenharmony_ci nskb->prev = nskb; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cifree_buf: 38562306a36Sopenharmony_ci kfree(buf); 38662306a36Sopenharmony_cifree_req: 38762306a36Sopenharmony_ci kfree(aead_req); 38862306a36Sopenharmony_ci return nskb; 38962306a36Sopenharmony_cifree_nskb: 39062306a36Sopenharmony_ci kfree_skb(nskb); 39162306a36Sopenharmony_ci nskb = NULL; 39262306a36Sopenharmony_ci goto free_buf; 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistatic struct sk_buff *tls_sw_fallback(struct sock *sk, struct sk_buff *skb) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci int tcp_payload_offset = skb_tcp_all_headers(skb); 39862306a36Sopenharmony_ci struct tls_context *tls_ctx = tls_get_ctx(sk); 39962306a36Sopenharmony_ci struct tls_offload_context_tx *ctx = tls_offload_ctx_tx(tls_ctx); 40062306a36Sopenharmony_ci int payload_len = skb->len - tcp_payload_offset; 40162306a36Sopenharmony_ci struct scatterlist *sg_in, sg_out[3]; 40262306a36Sopenharmony_ci struct sk_buff *nskb = NULL; 40362306a36Sopenharmony_ci int sg_in_max_elements; 40462306a36Sopenharmony_ci int resync_sgs = 0; 40562306a36Sopenharmony_ci s32 sync_size = 0; 40662306a36Sopenharmony_ci u64 rcd_sn; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci /* worst case is: 40962306a36Sopenharmony_ci * MAX_SKB_FRAGS in tls_record_info 41062306a36Sopenharmony_ci * MAX_SKB_FRAGS + 1 in SKB head and frags. 41162306a36Sopenharmony_ci */ 41262306a36Sopenharmony_ci sg_in_max_elements = 2 * MAX_SKB_FRAGS + 1; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci if (!payload_len) 41562306a36Sopenharmony_ci return skb; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci sg_in = kmalloc_array(sg_in_max_elements, sizeof(*sg_in), GFP_ATOMIC); 41862306a36Sopenharmony_ci if (!sg_in) 41962306a36Sopenharmony_ci goto free_orig; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci sg_init_table(sg_in, sg_in_max_elements); 42262306a36Sopenharmony_ci sg_init_table(sg_out, ARRAY_SIZE(sg_out)); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci if (fill_sg_in(sg_in, skb, ctx, &rcd_sn, &sync_size, &resync_sgs)) { 42562306a36Sopenharmony_ci /* bypass packets before kernel TLS socket option was set */ 42662306a36Sopenharmony_ci if (sync_size < 0 && payload_len <= -sync_size) 42762306a36Sopenharmony_ci nskb = skb_get(skb); 42862306a36Sopenharmony_ci goto put_sg; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci nskb = tls_enc_skb(tls_ctx, sg_out, sg_in, skb, sync_size, rcd_sn); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ciput_sg: 43462306a36Sopenharmony_ci while (resync_sgs) 43562306a36Sopenharmony_ci put_page(sg_page(&sg_in[--resync_sgs])); 43662306a36Sopenharmony_ci kfree(sg_in); 43762306a36Sopenharmony_cifree_orig: 43862306a36Sopenharmony_ci if (nskb) 43962306a36Sopenharmony_ci consume_skb(skb); 44062306a36Sopenharmony_ci else 44162306a36Sopenharmony_ci kfree_skb(skb); 44262306a36Sopenharmony_ci return nskb; 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistruct sk_buff *tls_validate_xmit_skb(struct sock *sk, 44662306a36Sopenharmony_ci struct net_device *dev, 44762306a36Sopenharmony_ci struct sk_buff *skb) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci if (dev == rcu_dereference_bh(tls_get_ctx(sk)->netdev) || 45062306a36Sopenharmony_ci netif_is_bond_master(dev)) 45162306a36Sopenharmony_ci return skb; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci return tls_sw_fallback(sk, skb); 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tls_validate_xmit_skb); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cistruct sk_buff *tls_validate_xmit_skb_sw(struct sock *sk, 45862306a36Sopenharmony_ci struct net_device *dev, 45962306a36Sopenharmony_ci struct sk_buff *skb) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci return tls_sw_fallback(sk, skb); 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cistruct sk_buff *tls_encrypt_skb(struct sk_buff *skb) 46562306a36Sopenharmony_ci{ 46662306a36Sopenharmony_ci return tls_sw_fallback(skb->sk, skb); 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(tls_encrypt_skb); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ciint tls_sw_fallback_init(struct sock *sk, 47162306a36Sopenharmony_ci struct tls_offload_context_tx *offload_ctx, 47262306a36Sopenharmony_ci struct tls_crypto_info *crypto_info) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci const struct tls_cipher_desc *cipher_desc; 47562306a36Sopenharmony_ci int rc; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci cipher_desc = get_cipher_desc(crypto_info->cipher_type); 47862306a36Sopenharmony_ci if (!cipher_desc || !cipher_desc->offloadable) 47962306a36Sopenharmony_ci return -EINVAL; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci offload_ctx->aead_send = 48262306a36Sopenharmony_ci crypto_alloc_aead(cipher_desc->cipher_name, 0, CRYPTO_ALG_ASYNC); 48362306a36Sopenharmony_ci if (IS_ERR(offload_ctx->aead_send)) { 48462306a36Sopenharmony_ci rc = PTR_ERR(offload_ctx->aead_send); 48562306a36Sopenharmony_ci pr_err_ratelimited("crypto_alloc_aead failed rc=%d\n", rc); 48662306a36Sopenharmony_ci offload_ctx->aead_send = NULL; 48762306a36Sopenharmony_ci goto err_out; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci rc = crypto_aead_setkey(offload_ctx->aead_send, 49162306a36Sopenharmony_ci crypto_info_key(crypto_info, cipher_desc), 49262306a36Sopenharmony_ci cipher_desc->key); 49362306a36Sopenharmony_ci if (rc) 49462306a36Sopenharmony_ci goto free_aead; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci rc = crypto_aead_setauthsize(offload_ctx->aead_send, cipher_desc->tag); 49762306a36Sopenharmony_ci if (rc) 49862306a36Sopenharmony_ci goto free_aead; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci return 0; 50162306a36Sopenharmony_cifree_aead: 50262306a36Sopenharmony_ci crypto_free_aead(offload_ctx->aead_send); 50362306a36Sopenharmony_cierr_out: 50462306a36Sopenharmony_ci return rc; 50562306a36Sopenharmony_ci} 506