18c2ecf20Sopenharmony_ci/* Copyright (c) 2018, Mellanox Technologies All rights reserved.
28c2ecf20Sopenharmony_ci *
38c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two
48c2ecf20Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
58c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
68c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the
78c2ecf20Sopenharmony_ci * OpenIB.org BSD license below:
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
108c2ecf20Sopenharmony_ci *     without modification, are permitted provided that the following
118c2ecf20Sopenharmony_ci *     conditions are met:
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci *      - Redistributions of source code must retain the above
148c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
158c2ecf20Sopenharmony_ci *        disclaimer.
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
188c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
198c2ecf20Sopenharmony_ci *        disclaimer in the documentation and/or other materials
208c2ecf20Sopenharmony_ci *        provided with the distribution.
218c2ecf20Sopenharmony_ci *
228c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
238c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
248c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
258c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
268c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
278c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
288c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
298c2ecf20Sopenharmony_ci * SOFTWARE.
308c2ecf20Sopenharmony_ci */
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#include <net/tls.h>
338c2ecf20Sopenharmony_ci#include <crypto/aead.h>
348c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h>
358c2ecf20Sopenharmony_ci#include <net/ip6_checksum.h>
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic void chain_to_walk(struct scatterlist *sg, struct scatter_walk *walk)
388c2ecf20Sopenharmony_ci{
398c2ecf20Sopenharmony_ci	struct scatterlist *src = walk->sg;
408c2ecf20Sopenharmony_ci	int diff = walk->offset - src->offset;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	sg_set_page(sg, sg_page(src),
438c2ecf20Sopenharmony_ci		    src->length - diff, walk->offset);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	scatterwalk_crypto_chain(sg, sg_next(src), 2);
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic int tls_enc_record(struct aead_request *aead_req,
498c2ecf20Sopenharmony_ci			  struct crypto_aead *aead, char *aad,
508c2ecf20Sopenharmony_ci			  char *iv, __be64 rcd_sn,
518c2ecf20Sopenharmony_ci			  struct scatter_walk *in,
528c2ecf20Sopenharmony_ci			  struct scatter_walk *out, int *in_len)
538c2ecf20Sopenharmony_ci{
548c2ecf20Sopenharmony_ci	unsigned char buf[TLS_HEADER_SIZE + TLS_CIPHER_AES_GCM_128_IV_SIZE];
558c2ecf20Sopenharmony_ci	struct scatterlist sg_in[3];
568c2ecf20Sopenharmony_ci	struct scatterlist sg_out[3];
578c2ecf20Sopenharmony_ci	u16 len;
588c2ecf20Sopenharmony_ci	int rc;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	len = min_t(int, *in_len, ARRAY_SIZE(buf));
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	scatterwalk_copychunks(buf, in, len, 0);
638c2ecf20Sopenharmony_ci	scatterwalk_copychunks(buf, out, len, 1);
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	*in_len -= len;
668c2ecf20Sopenharmony_ci	if (!*in_len)
678c2ecf20Sopenharmony_ci		return 0;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	scatterwalk_pagedone(in, 0, 1);
708c2ecf20Sopenharmony_ci	scatterwalk_pagedone(out, 1, 1);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	len = buf[4] | (buf[3] << 8);
738c2ecf20Sopenharmony_ci	len -= TLS_CIPHER_AES_GCM_128_IV_SIZE;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	tls_make_aad(aad, len - TLS_CIPHER_AES_GCM_128_TAG_SIZE,
768c2ecf20Sopenharmony_ci		(char *)&rcd_sn, sizeof(rcd_sn), buf[0],
778c2ecf20Sopenharmony_ci		TLS_1_2_VERSION);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	memcpy(iv + TLS_CIPHER_AES_GCM_128_SALT_SIZE, buf + TLS_HEADER_SIZE,
808c2ecf20Sopenharmony_ci	       TLS_CIPHER_AES_GCM_128_IV_SIZE);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	sg_init_table(sg_in, ARRAY_SIZE(sg_in));
838c2ecf20Sopenharmony_ci	sg_init_table(sg_out, ARRAY_SIZE(sg_out));
848c2ecf20Sopenharmony_ci	sg_set_buf(sg_in, aad, TLS_AAD_SPACE_SIZE);
858c2ecf20Sopenharmony_ci	sg_set_buf(sg_out, aad, TLS_AAD_SPACE_SIZE);
868c2ecf20Sopenharmony_ci	chain_to_walk(sg_in + 1, in);
878c2ecf20Sopenharmony_ci	chain_to_walk(sg_out + 1, out);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	*in_len -= len;
908c2ecf20Sopenharmony_ci	if (*in_len < 0) {
918c2ecf20Sopenharmony_ci		*in_len += TLS_CIPHER_AES_GCM_128_TAG_SIZE;
928c2ecf20Sopenharmony_ci		/* the input buffer doesn't contain the entire record.
938c2ecf20Sopenharmony_ci		 * trim len accordingly. The resulting authentication tag
948c2ecf20Sopenharmony_ci		 * will contain garbage, but we don't care, so we won't
958c2ecf20Sopenharmony_ci		 * include any of it in the output skb
968c2ecf20Sopenharmony_ci		 * Note that we assume the output buffer length
978c2ecf20Sopenharmony_ci		 * is larger then input buffer length + tag size
988c2ecf20Sopenharmony_ci		 */
998c2ecf20Sopenharmony_ci		if (*in_len < 0)
1008c2ecf20Sopenharmony_ci			len += *in_len;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci		*in_len = 0;
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	if (*in_len) {
1068c2ecf20Sopenharmony_ci		scatterwalk_copychunks(NULL, in, len, 2);
1078c2ecf20Sopenharmony_ci		scatterwalk_pagedone(in, 0, 1);
1088c2ecf20Sopenharmony_ci		scatterwalk_copychunks(NULL, out, len, 2);
1098c2ecf20Sopenharmony_ci		scatterwalk_pagedone(out, 1, 1);
1108c2ecf20Sopenharmony_ci	}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	len -= TLS_CIPHER_AES_GCM_128_TAG_SIZE;
1138c2ecf20Sopenharmony_ci	aead_request_set_crypt(aead_req, sg_in, sg_out, len, iv);
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	rc = crypto_aead_encrypt(aead_req);
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	return rc;
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic void tls_init_aead_request(struct aead_request *aead_req,
1218c2ecf20Sopenharmony_ci				  struct crypto_aead *aead)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	aead_request_set_tfm(aead_req, aead);
1248c2ecf20Sopenharmony_ci	aead_request_set_ad(aead_req, TLS_AAD_SPACE_SIZE);
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic struct aead_request *tls_alloc_aead_request(struct crypto_aead *aead,
1288c2ecf20Sopenharmony_ci						   gfp_t flags)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	unsigned int req_size = sizeof(struct aead_request) +
1318c2ecf20Sopenharmony_ci		crypto_aead_reqsize(aead);
1328c2ecf20Sopenharmony_ci	struct aead_request *aead_req;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	aead_req = kzalloc(req_size, flags);
1358c2ecf20Sopenharmony_ci	if (aead_req)
1368c2ecf20Sopenharmony_ci		tls_init_aead_request(aead_req, aead);
1378c2ecf20Sopenharmony_ci	return aead_req;
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_cistatic int tls_enc_records(struct aead_request *aead_req,
1418c2ecf20Sopenharmony_ci			   struct crypto_aead *aead, struct scatterlist *sg_in,
1428c2ecf20Sopenharmony_ci			   struct scatterlist *sg_out, char *aad, char *iv,
1438c2ecf20Sopenharmony_ci			   u64 rcd_sn, int len)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	struct scatter_walk out, in;
1468c2ecf20Sopenharmony_ci	int rc;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	scatterwalk_start(&in, sg_in);
1498c2ecf20Sopenharmony_ci	scatterwalk_start(&out, sg_out);
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	do {
1528c2ecf20Sopenharmony_ci		rc = tls_enc_record(aead_req, aead, aad, iv,
1538c2ecf20Sopenharmony_ci				    cpu_to_be64(rcd_sn), &in, &out, &len);
1548c2ecf20Sopenharmony_ci		rcd_sn++;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	} while (rc == 0 && len);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	scatterwalk_done(&in, 0, 0);
1598c2ecf20Sopenharmony_ci	scatterwalk_done(&out, 1, 0);
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	return rc;
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci/* Can't use icsk->icsk_af_ops->send_check here because the ip addresses
1658c2ecf20Sopenharmony_ci * might have been changed by NAT.
1668c2ecf20Sopenharmony_ci */
1678c2ecf20Sopenharmony_cistatic void update_chksum(struct sk_buff *skb, int headln)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	struct tcphdr *th = tcp_hdr(skb);
1708c2ecf20Sopenharmony_ci	int datalen = skb->len - headln;
1718c2ecf20Sopenharmony_ci	const struct ipv6hdr *ipv6h;
1728c2ecf20Sopenharmony_ci	const struct iphdr *iph;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	/* We only changed the payload so if we are using partial we don't
1758c2ecf20Sopenharmony_ci	 * need to update anything.
1768c2ecf20Sopenharmony_ci	 */
1778c2ecf20Sopenharmony_ci	if (likely(skb->ip_summed == CHECKSUM_PARTIAL))
1788c2ecf20Sopenharmony_ci		return;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	skb->ip_summed = CHECKSUM_PARTIAL;
1818c2ecf20Sopenharmony_ci	skb->csum_start = skb_transport_header(skb) - skb->head;
1828c2ecf20Sopenharmony_ci	skb->csum_offset = offsetof(struct tcphdr, check);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	if (skb->sk->sk_family == AF_INET6) {
1858c2ecf20Sopenharmony_ci		ipv6h = ipv6_hdr(skb);
1868c2ecf20Sopenharmony_ci		th->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr,
1878c2ecf20Sopenharmony_ci					     datalen, IPPROTO_TCP, 0);
1888c2ecf20Sopenharmony_ci	} else {
1898c2ecf20Sopenharmony_ci		iph = ip_hdr(skb);
1908c2ecf20Sopenharmony_ci		th->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, datalen,
1918c2ecf20Sopenharmony_ci					       IPPROTO_TCP, 0);
1928c2ecf20Sopenharmony_ci	}
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic void complete_skb(struct sk_buff *nskb, struct sk_buff *skb, int headln)
1968c2ecf20Sopenharmony_ci{
1978c2ecf20Sopenharmony_ci	struct sock *sk = skb->sk;
1988c2ecf20Sopenharmony_ci	int delta;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	skb_copy_header(nskb, skb);
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	skb_put(nskb, skb->len);
2038c2ecf20Sopenharmony_ci	memcpy(nskb->data, skb->data, headln);
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	nskb->destructor = skb->destructor;
2068c2ecf20Sopenharmony_ci	nskb->sk = sk;
2078c2ecf20Sopenharmony_ci	skb->destructor = NULL;
2088c2ecf20Sopenharmony_ci	skb->sk = NULL;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	update_chksum(nskb, headln);
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	/* sock_efree means skb must gone through skb_orphan_partial() */
2138c2ecf20Sopenharmony_ci	if (nskb->destructor == sock_efree)
2148c2ecf20Sopenharmony_ci		return;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	delta = nskb->truesize - skb->truesize;
2178c2ecf20Sopenharmony_ci	if (likely(delta < 0))
2188c2ecf20Sopenharmony_ci		WARN_ON_ONCE(refcount_sub_and_test(-delta, &sk->sk_wmem_alloc));
2198c2ecf20Sopenharmony_ci	else if (delta)
2208c2ecf20Sopenharmony_ci		refcount_add(delta, &sk->sk_wmem_alloc);
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci/* This function may be called after the user socket is already
2248c2ecf20Sopenharmony_ci * closed so make sure we don't use anything freed during
2258c2ecf20Sopenharmony_ci * tls_sk_proto_close here
2268c2ecf20Sopenharmony_ci */
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic int fill_sg_in(struct scatterlist *sg_in,
2298c2ecf20Sopenharmony_ci		      struct sk_buff *skb,
2308c2ecf20Sopenharmony_ci		      struct tls_offload_context_tx *ctx,
2318c2ecf20Sopenharmony_ci		      u64 *rcd_sn,
2328c2ecf20Sopenharmony_ci		      s32 *sync_size,
2338c2ecf20Sopenharmony_ci		      int *resync_sgs)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	int tcp_payload_offset = skb_transport_offset(skb) + tcp_hdrlen(skb);
2368c2ecf20Sopenharmony_ci	int payload_len = skb->len - tcp_payload_offset;
2378c2ecf20Sopenharmony_ci	u32 tcp_seq = ntohl(tcp_hdr(skb)->seq);
2388c2ecf20Sopenharmony_ci	struct tls_record_info *record;
2398c2ecf20Sopenharmony_ci	unsigned long flags;
2408c2ecf20Sopenharmony_ci	int remaining;
2418c2ecf20Sopenharmony_ci	int i;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ctx->lock, flags);
2448c2ecf20Sopenharmony_ci	record = tls_get_record(ctx, tcp_seq, rcd_sn);
2458c2ecf20Sopenharmony_ci	if (!record) {
2468c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ctx->lock, flags);
2478c2ecf20Sopenharmony_ci		return -EINVAL;
2488c2ecf20Sopenharmony_ci	}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	*sync_size = tcp_seq - tls_record_start_seq(record);
2518c2ecf20Sopenharmony_ci	if (*sync_size < 0) {
2528c2ecf20Sopenharmony_ci		int is_start_marker = tls_record_is_start_marker(record);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ctx->lock, flags);
2558c2ecf20Sopenharmony_ci		/* This should only occur if the relevant record was
2568c2ecf20Sopenharmony_ci		 * already acked. In that case it should be ok
2578c2ecf20Sopenharmony_ci		 * to drop the packet and avoid retransmission.
2588c2ecf20Sopenharmony_ci		 *
2598c2ecf20Sopenharmony_ci		 * There is a corner case where the packet contains
2608c2ecf20Sopenharmony_ci		 * both an acked and a non-acked record.
2618c2ecf20Sopenharmony_ci		 * We currently don't handle that case and rely
2628c2ecf20Sopenharmony_ci		 * on TCP to retranmit a packet that doesn't contain
2638c2ecf20Sopenharmony_ci		 * already acked payload.
2648c2ecf20Sopenharmony_ci		 */
2658c2ecf20Sopenharmony_ci		if (!is_start_marker)
2668c2ecf20Sopenharmony_ci			*sync_size = 0;
2678c2ecf20Sopenharmony_ci		return -EINVAL;
2688c2ecf20Sopenharmony_ci	}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	remaining = *sync_size;
2718c2ecf20Sopenharmony_ci	for (i = 0; remaining > 0; i++) {
2728c2ecf20Sopenharmony_ci		skb_frag_t *frag = &record->frags[i];
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci		__skb_frag_ref(frag);
2758c2ecf20Sopenharmony_ci		sg_set_page(sg_in + i, skb_frag_page(frag),
2768c2ecf20Sopenharmony_ci			    skb_frag_size(frag), skb_frag_off(frag));
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci		remaining -= skb_frag_size(frag);
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci		if (remaining < 0)
2818c2ecf20Sopenharmony_ci			sg_in[i].length += remaining;
2828c2ecf20Sopenharmony_ci	}
2838c2ecf20Sopenharmony_ci	*resync_sgs = i;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ctx->lock, flags);
2868c2ecf20Sopenharmony_ci	if (skb_to_sgvec(skb, &sg_in[i], tcp_payload_offset, payload_len) < 0)
2878c2ecf20Sopenharmony_ci		return -EINVAL;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	return 0;
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistatic void fill_sg_out(struct scatterlist sg_out[3], void *buf,
2938c2ecf20Sopenharmony_ci			struct tls_context *tls_ctx,
2948c2ecf20Sopenharmony_ci			struct sk_buff *nskb,
2958c2ecf20Sopenharmony_ci			int tcp_payload_offset,
2968c2ecf20Sopenharmony_ci			int payload_len,
2978c2ecf20Sopenharmony_ci			int sync_size,
2988c2ecf20Sopenharmony_ci			void *dummy_buf)
2998c2ecf20Sopenharmony_ci{
3008c2ecf20Sopenharmony_ci	sg_set_buf(&sg_out[0], dummy_buf, sync_size);
3018c2ecf20Sopenharmony_ci	sg_set_buf(&sg_out[1], nskb->data + tcp_payload_offset, payload_len);
3028c2ecf20Sopenharmony_ci	/* Add room for authentication tag produced by crypto */
3038c2ecf20Sopenharmony_ci	dummy_buf += sync_size;
3048c2ecf20Sopenharmony_ci	sg_set_buf(&sg_out[2], dummy_buf, TLS_CIPHER_AES_GCM_128_TAG_SIZE);
3058c2ecf20Sopenharmony_ci}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_cistatic struct sk_buff *tls_enc_skb(struct tls_context *tls_ctx,
3088c2ecf20Sopenharmony_ci				   struct scatterlist sg_out[3],
3098c2ecf20Sopenharmony_ci				   struct scatterlist *sg_in,
3108c2ecf20Sopenharmony_ci				   struct sk_buff *skb,
3118c2ecf20Sopenharmony_ci				   s32 sync_size, u64 rcd_sn)
3128c2ecf20Sopenharmony_ci{
3138c2ecf20Sopenharmony_ci	int tcp_payload_offset = skb_transport_offset(skb) + tcp_hdrlen(skb);
3148c2ecf20Sopenharmony_ci	struct tls_offload_context_tx *ctx = tls_offload_ctx_tx(tls_ctx);
3158c2ecf20Sopenharmony_ci	int payload_len = skb->len - tcp_payload_offset;
3168c2ecf20Sopenharmony_ci	void *buf, *iv, *aad, *dummy_buf;
3178c2ecf20Sopenharmony_ci	struct aead_request *aead_req;
3188c2ecf20Sopenharmony_ci	struct sk_buff *nskb = NULL;
3198c2ecf20Sopenharmony_ci	int buf_len;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	aead_req = tls_alloc_aead_request(ctx->aead_send, GFP_ATOMIC);
3228c2ecf20Sopenharmony_ci	if (!aead_req)
3238c2ecf20Sopenharmony_ci		return NULL;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	buf_len = TLS_CIPHER_AES_GCM_128_SALT_SIZE +
3268c2ecf20Sopenharmony_ci		  TLS_CIPHER_AES_GCM_128_IV_SIZE +
3278c2ecf20Sopenharmony_ci		  TLS_AAD_SPACE_SIZE +
3288c2ecf20Sopenharmony_ci		  sync_size +
3298c2ecf20Sopenharmony_ci		  TLS_CIPHER_AES_GCM_128_TAG_SIZE;
3308c2ecf20Sopenharmony_ci	buf = kmalloc(buf_len, GFP_ATOMIC);
3318c2ecf20Sopenharmony_ci	if (!buf)
3328c2ecf20Sopenharmony_ci		goto free_req;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	iv = buf;
3358c2ecf20Sopenharmony_ci	memcpy(iv, tls_ctx->crypto_send.aes_gcm_128.salt,
3368c2ecf20Sopenharmony_ci	       TLS_CIPHER_AES_GCM_128_SALT_SIZE);
3378c2ecf20Sopenharmony_ci	aad = buf + TLS_CIPHER_AES_GCM_128_SALT_SIZE +
3388c2ecf20Sopenharmony_ci	      TLS_CIPHER_AES_GCM_128_IV_SIZE;
3398c2ecf20Sopenharmony_ci	dummy_buf = aad + TLS_AAD_SPACE_SIZE;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	nskb = alloc_skb(skb_headroom(skb) + skb->len, GFP_ATOMIC);
3428c2ecf20Sopenharmony_ci	if (!nskb)
3438c2ecf20Sopenharmony_ci		goto free_buf;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	skb_reserve(nskb, skb_headroom(skb));
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	fill_sg_out(sg_out, buf, tls_ctx, nskb, tcp_payload_offset,
3488c2ecf20Sopenharmony_ci		    payload_len, sync_size, dummy_buf);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	if (tls_enc_records(aead_req, ctx->aead_send, sg_in, sg_out, aad, iv,
3518c2ecf20Sopenharmony_ci			    rcd_sn, sync_size + payload_len) < 0)
3528c2ecf20Sopenharmony_ci		goto free_nskb;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	complete_skb(nskb, skb, tcp_payload_offset);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	/* validate_xmit_skb_list assumes that if the skb wasn't segmented
3578c2ecf20Sopenharmony_ci	 * nskb->prev will point to the skb itself
3588c2ecf20Sopenharmony_ci	 */
3598c2ecf20Sopenharmony_ci	nskb->prev = nskb;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_cifree_buf:
3628c2ecf20Sopenharmony_ci	kfree(buf);
3638c2ecf20Sopenharmony_cifree_req:
3648c2ecf20Sopenharmony_ci	kfree(aead_req);
3658c2ecf20Sopenharmony_ci	return nskb;
3668c2ecf20Sopenharmony_cifree_nskb:
3678c2ecf20Sopenharmony_ci	kfree_skb(nskb);
3688c2ecf20Sopenharmony_ci	nskb = NULL;
3698c2ecf20Sopenharmony_ci	goto free_buf;
3708c2ecf20Sopenharmony_ci}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_cistatic struct sk_buff *tls_sw_fallback(struct sock *sk, struct sk_buff *skb)
3738c2ecf20Sopenharmony_ci{
3748c2ecf20Sopenharmony_ci	int tcp_payload_offset = skb_transport_offset(skb) + tcp_hdrlen(skb);
3758c2ecf20Sopenharmony_ci	struct tls_context *tls_ctx = tls_get_ctx(sk);
3768c2ecf20Sopenharmony_ci	struct tls_offload_context_tx *ctx = tls_offload_ctx_tx(tls_ctx);
3778c2ecf20Sopenharmony_ci	int payload_len = skb->len - tcp_payload_offset;
3788c2ecf20Sopenharmony_ci	struct scatterlist *sg_in, sg_out[3];
3798c2ecf20Sopenharmony_ci	struct sk_buff *nskb = NULL;
3808c2ecf20Sopenharmony_ci	int sg_in_max_elements;
3818c2ecf20Sopenharmony_ci	int resync_sgs = 0;
3828c2ecf20Sopenharmony_ci	s32 sync_size = 0;
3838c2ecf20Sopenharmony_ci	u64 rcd_sn;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	/* worst case is:
3868c2ecf20Sopenharmony_ci	 * MAX_SKB_FRAGS in tls_record_info
3878c2ecf20Sopenharmony_ci	 * MAX_SKB_FRAGS + 1 in SKB head and frags.
3888c2ecf20Sopenharmony_ci	 */
3898c2ecf20Sopenharmony_ci	sg_in_max_elements = 2 * MAX_SKB_FRAGS + 1;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	if (!payload_len)
3928c2ecf20Sopenharmony_ci		return skb;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	sg_in = kmalloc_array(sg_in_max_elements, sizeof(*sg_in), GFP_ATOMIC);
3958c2ecf20Sopenharmony_ci	if (!sg_in)
3968c2ecf20Sopenharmony_ci		goto free_orig;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	sg_init_table(sg_in, sg_in_max_elements);
3998c2ecf20Sopenharmony_ci	sg_init_table(sg_out, ARRAY_SIZE(sg_out));
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	if (fill_sg_in(sg_in, skb, ctx, &rcd_sn, &sync_size, &resync_sgs)) {
4028c2ecf20Sopenharmony_ci		/* bypass packets before kernel TLS socket option was set */
4038c2ecf20Sopenharmony_ci		if (sync_size < 0 && payload_len <= -sync_size)
4048c2ecf20Sopenharmony_ci			nskb = skb_get(skb);
4058c2ecf20Sopenharmony_ci		goto put_sg;
4068c2ecf20Sopenharmony_ci	}
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	nskb = tls_enc_skb(tls_ctx, sg_out, sg_in, skb, sync_size, rcd_sn);
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ciput_sg:
4118c2ecf20Sopenharmony_ci	while (resync_sgs)
4128c2ecf20Sopenharmony_ci		put_page(sg_page(&sg_in[--resync_sgs]));
4138c2ecf20Sopenharmony_ci	kfree(sg_in);
4148c2ecf20Sopenharmony_cifree_orig:
4158c2ecf20Sopenharmony_ci	if (nskb)
4168c2ecf20Sopenharmony_ci		consume_skb(skb);
4178c2ecf20Sopenharmony_ci	else
4188c2ecf20Sopenharmony_ci		kfree_skb(skb);
4198c2ecf20Sopenharmony_ci	return nskb;
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_cistruct sk_buff *tls_validate_xmit_skb(struct sock *sk,
4238c2ecf20Sopenharmony_ci				      struct net_device *dev,
4248c2ecf20Sopenharmony_ci				      struct sk_buff *skb)
4258c2ecf20Sopenharmony_ci{
4268c2ecf20Sopenharmony_ci	if (dev == tls_get_ctx(sk)->netdev)
4278c2ecf20Sopenharmony_ci		return skb;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	return tls_sw_fallback(sk, skb);
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tls_validate_xmit_skb);
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_cistruct sk_buff *tls_validate_xmit_skb_sw(struct sock *sk,
4348c2ecf20Sopenharmony_ci					 struct net_device *dev,
4358c2ecf20Sopenharmony_ci					 struct sk_buff *skb)
4368c2ecf20Sopenharmony_ci{
4378c2ecf20Sopenharmony_ci	return tls_sw_fallback(sk, skb);
4388c2ecf20Sopenharmony_ci}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_cistruct sk_buff *tls_encrypt_skb(struct sk_buff *skb)
4418c2ecf20Sopenharmony_ci{
4428c2ecf20Sopenharmony_ci	return tls_sw_fallback(skb->sk, skb);
4438c2ecf20Sopenharmony_ci}
4448c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tls_encrypt_skb);
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ciint tls_sw_fallback_init(struct sock *sk,
4478c2ecf20Sopenharmony_ci			 struct tls_offload_context_tx *offload_ctx,
4488c2ecf20Sopenharmony_ci			 struct tls_crypto_info *crypto_info)
4498c2ecf20Sopenharmony_ci{
4508c2ecf20Sopenharmony_ci	const u8 *key;
4518c2ecf20Sopenharmony_ci	int rc;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	offload_ctx->aead_send =
4548c2ecf20Sopenharmony_ci	    crypto_alloc_aead("gcm(aes)", 0, CRYPTO_ALG_ASYNC);
4558c2ecf20Sopenharmony_ci	if (IS_ERR(offload_ctx->aead_send)) {
4568c2ecf20Sopenharmony_ci		rc = PTR_ERR(offload_ctx->aead_send);
4578c2ecf20Sopenharmony_ci		pr_err_ratelimited("crypto_alloc_aead failed rc=%d\n", rc);
4588c2ecf20Sopenharmony_ci		offload_ctx->aead_send = NULL;
4598c2ecf20Sopenharmony_ci		goto err_out;
4608c2ecf20Sopenharmony_ci	}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	key = ((struct tls12_crypto_info_aes_gcm_128 *)crypto_info)->key;
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_ci	rc = crypto_aead_setkey(offload_ctx->aead_send, key,
4658c2ecf20Sopenharmony_ci				TLS_CIPHER_AES_GCM_128_KEY_SIZE);
4668c2ecf20Sopenharmony_ci	if (rc)
4678c2ecf20Sopenharmony_ci		goto free_aead;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	rc = crypto_aead_setauthsize(offload_ctx->aead_send,
4708c2ecf20Sopenharmony_ci				     TLS_CIPHER_AES_GCM_128_TAG_SIZE);
4718c2ecf20Sopenharmony_ci	if (rc)
4728c2ecf20Sopenharmony_ci		goto free_aead;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	return 0;
4758c2ecf20Sopenharmony_cifree_aead:
4768c2ecf20Sopenharmony_ci	crypto_free_aead(offload_ctx->aead_send);
4778c2ecf20Sopenharmony_cierr_out:
4788c2ecf20Sopenharmony_ci	return rc;
4798c2ecf20Sopenharmony_ci}
480