18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
28c2ecf20Sopenharmony_ci/* Copyright (C) 2019 Netronome Systems, Inc. */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <linux/bitfield.h>
58c2ecf20Sopenharmony_ci#include <linux/ipv6.h>
68c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
78c2ecf20Sopenharmony_ci#include <linux/string.h>
88c2ecf20Sopenharmony_ci#include <net/inet6_hashtables.h>
98c2ecf20Sopenharmony_ci#include <net/tls.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include "../ccm.h"
128c2ecf20Sopenharmony_ci#include "../nfp_net.h"
138c2ecf20Sopenharmony_ci#include "crypto.h"
148c2ecf20Sopenharmony_ci#include "fw.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#define NFP_NET_TLS_CCM_MBOX_OPS_MASK		\
178c2ecf20Sopenharmony_ci	(BIT(NFP_CCM_TYPE_CRYPTO_RESET) |	\
188c2ecf20Sopenharmony_ci	 BIT(NFP_CCM_TYPE_CRYPTO_ADD) |		\
198c2ecf20Sopenharmony_ci	 BIT(NFP_CCM_TYPE_CRYPTO_DEL) |		\
208c2ecf20Sopenharmony_ci	 BIT(NFP_CCM_TYPE_CRYPTO_UPDATE))
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define NFP_NET_TLS_OPCODE_MASK_RX			\
238c2ecf20Sopenharmony_ci	BIT(NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_DEC)
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#define NFP_NET_TLS_OPCODE_MASK_TX			\
268c2ecf20Sopenharmony_ci	BIT(NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_ENC)
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define NFP_NET_TLS_OPCODE_MASK						\
298c2ecf20Sopenharmony_ci	(NFP_NET_TLS_OPCODE_MASK_RX | NFP_NET_TLS_OPCODE_MASK_TX)
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistatic void nfp_net_crypto_set_op(struct nfp_net *nn, u8 opcode, bool on)
328c2ecf20Sopenharmony_ci{
338c2ecf20Sopenharmony_ci	u32 off, val;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	off = nn->tlv_caps.crypto_enable_off + round_down(opcode / 8, 4);
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	val = nn_readl(nn, off);
388c2ecf20Sopenharmony_ci	if (on)
398c2ecf20Sopenharmony_ci		val |= BIT(opcode & 31);
408c2ecf20Sopenharmony_ci	else
418c2ecf20Sopenharmony_ci		val &= ~BIT(opcode & 31);
428c2ecf20Sopenharmony_ci	nn_writel(nn, off, val);
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistatic bool
468c2ecf20Sopenharmony_ci__nfp_net_tls_conn_cnt_changed(struct nfp_net *nn, int add,
478c2ecf20Sopenharmony_ci			       enum tls_offload_ctx_dir direction)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	u8 opcode;
508c2ecf20Sopenharmony_ci	int cnt;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	if (direction == TLS_OFFLOAD_CTX_DIR_TX) {
538c2ecf20Sopenharmony_ci		opcode = NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_ENC;
548c2ecf20Sopenharmony_ci		nn->ktls_tx_conn_cnt += add;
558c2ecf20Sopenharmony_ci		cnt = nn->ktls_tx_conn_cnt;
568c2ecf20Sopenharmony_ci		nn->dp.ktls_tx = !!nn->ktls_tx_conn_cnt;
578c2ecf20Sopenharmony_ci	} else {
588c2ecf20Sopenharmony_ci		opcode = NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_DEC;
598c2ecf20Sopenharmony_ci		nn->ktls_rx_conn_cnt += add;
608c2ecf20Sopenharmony_ci		cnt = nn->ktls_rx_conn_cnt;
618c2ecf20Sopenharmony_ci	}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	/* Care only about 0 -> 1 and 1 -> 0 transitions */
648c2ecf20Sopenharmony_ci	if (cnt > 1)
658c2ecf20Sopenharmony_ci		return false;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	nfp_net_crypto_set_op(nn, opcode, cnt);
688c2ecf20Sopenharmony_ci	return true;
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic int
728c2ecf20Sopenharmony_cinfp_net_tls_conn_cnt_changed(struct nfp_net *nn, int add,
738c2ecf20Sopenharmony_ci			     enum tls_offload_ctx_dir direction)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	int ret = 0;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	/* Use the BAR lock to protect the connection counts */
788c2ecf20Sopenharmony_ci	nn_ctrl_bar_lock(nn);
798c2ecf20Sopenharmony_ci	if (__nfp_net_tls_conn_cnt_changed(nn, add, direction)) {
808c2ecf20Sopenharmony_ci		ret = __nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_CRYPTO);
818c2ecf20Sopenharmony_ci		/* Undo the cnt adjustment if failed */
828c2ecf20Sopenharmony_ci		if (ret)
838c2ecf20Sopenharmony_ci			__nfp_net_tls_conn_cnt_changed(nn, -add, direction);
848c2ecf20Sopenharmony_ci	}
858c2ecf20Sopenharmony_ci	nn_ctrl_bar_unlock(nn);
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	return ret;
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic int
918c2ecf20Sopenharmony_cinfp_net_tls_conn_add(struct nfp_net *nn, enum tls_offload_ctx_dir direction)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	return nfp_net_tls_conn_cnt_changed(nn, 1, direction);
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic int
978c2ecf20Sopenharmony_cinfp_net_tls_conn_remove(struct nfp_net *nn, enum tls_offload_ctx_dir direction)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	return nfp_net_tls_conn_cnt_changed(nn, -1, direction);
1008c2ecf20Sopenharmony_ci}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistatic struct sk_buff *
1038c2ecf20Sopenharmony_cinfp_net_tls_alloc_simple(struct nfp_net *nn, size_t req_sz, gfp_t flags)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	return nfp_ccm_mbox_msg_alloc(nn, req_sz,
1068c2ecf20Sopenharmony_ci				      sizeof(struct nfp_crypto_reply_simple),
1078c2ecf20Sopenharmony_ci				      flags);
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic int
1118c2ecf20Sopenharmony_cinfp_net_tls_communicate_simple(struct nfp_net *nn, struct sk_buff *skb,
1128c2ecf20Sopenharmony_ci			       const char *name, enum nfp_ccm_type type)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	struct nfp_crypto_reply_simple *reply;
1158c2ecf20Sopenharmony_ci	int err;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	err = __nfp_ccm_mbox_communicate(nn, skb, type,
1188c2ecf20Sopenharmony_ci					 sizeof(*reply), sizeof(*reply),
1198c2ecf20Sopenharmony_ci					 type == NFP_CCM_TYPE_CRYPTO_DEL);
1208c2ecf20Sopenharmony_ci	if (err) {
1218c2ecf20Sopenharmony_ci		nn_dp_warn(&nn->dp, "failed to %s TLS: %d\n", name, err);
1228c2ecf20Sopenharmony_ci		return err;
1238c2ecf20Sopenharmony_ci	}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	reply = (void *)skb->data;
1268c2ecf20Sopenharmony_ci	err = -be32_to_cpu(reply->error);
1278c2ecf20Sopenharmony_ci	if (err)
1288c2ecf20Sopenharmony_ci		nn_dp_warn(&nn->dp, "failed to %s TLS, fw replied: %d\n",
1298c2ecf20Sopenharmony_ci			   name, err);
1308c2ecf20Sopenharmony_ci	dev_consume_skb_any(skb);
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	return err;
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic void nfp_net_tls_del_fw(struct nfp_net *nn, __be32 *fw_handle)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	struct nfp_crypto_req_del *req;
1388c2ecf20Sopenharmony_ci	struct sk_buff *skb;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	skb = nfp_net_tls_alloc_simple(nn, sizeof(*req), GFP_KERNEL);
1418c2ecf20Sopenharmony_ci	if (!skb)
1428c2ecf20Sopenharmony_ci		return;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	req = (void *)skb->data;
1458c2ecf20Sopenharmony_ci	req->ep_id = 0;
1468c2ecf20Sopenharmony_ci	memcpy(req->handle, fw_handle, sizeof(req->handle));
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	nfp_net_tls_communicate_simple(nn, skb, "delete",
1498c2ecf20Sopenharmony_ci				       NFP_CCM_TYPE_CRYPTO_DEL);
1508c2ecf20Sopenharmony_ci}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_cistatic void
1538c2ecf20Sopenharmony_cinfp_net_tls_set_ipver_vlan(struct nfp_crypto_req_add_front *front, u8 ipver)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	front->ipver_vlan = cpu_to_be16(FIELD_PREP(NFP_NET_TLS_IPVER, ipver) |
1568c2ecf20Sopenharmony_ci					FIELD_PREP(NFP_NET_TLS_VLAN,
1578c2ecf20Sopenharmony_ci						   NFP_NET_TLS_VLAN_UNUSED));
1588c2ecf20Sopenharmony_ci}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_cistatic void
1618c2ecf20Sopenharmony_cinfp_net_tls_assign_conn_id(struct nfp_net *nn,
1628c2ecf20Sopenharmony_ci			   struct nfp_crypto_req_add_front *front)
1638c2ecf20Sopenharmony_ci{
1648c2ecf20Sopenharmony_ci	u32 len;
1658c2ecf20Sopenharmony_ci	u64 id;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	id = atomic64_inc_return(&nn->ktls_conn_id_gen);
1688c2ecf20Sopenharmony_ci	len = front->key_len - NFP_NET_TLS_NON_ADDR_KEY_LEN;
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	memcpy(front->l3_addrs, &id, sizeof(id));
1718c2ecf20Sopenharmony_ci	memset(front->l3_addrs + sizeof(id), 0, len - sizeof(id));
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic struct nfp_crypto_req_add_back *
1758c2ecf20Sopenharmony_cinfp_net_tls_set_ipv4(struct nfp_net *nn, struct nfp_crypto_req_add_v4 *req,
1768c2ecf20Sopenharmony_ci		     struct sock *sk, int direction)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	struct inet_sock *inet = inet_sk(sk);
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	req->front.key_len += sizeof(__be32) * 2;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	if (direction == TLS_OFFLOAD_CTX_DIR_TX) {
1838c2ecf20Sopenharmony_ci		nfp_net_tls_assign_conn_id(nn, &req->front);
1848c2ecf20Sopenharmony_ci	} else {
1858c2ecf20Sopenharmony_ci		req->src_ip = inet->inet_daddr;
1868c2ecf20Sopenharmony_ci		req->dst_ip = inet->inet_saddr;
1878c2ecf20Sopenharmony_ci	}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	return &req->back;
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_cistatic struct nfp_crypto_req_add_back *
1938c2ecf20Sopenharmony_cinfp_net_tls_set_ipv6(struct nfp_net *nn, struct nfp_crypto_req_add_v6 *req,
1948c2ecf20Sopenharmony_ci		     struct sock *sk, int direction)
1958c2ecf20Sopenharmony_ci{
1968c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
1978c2ecf20Sopenharmony_ci	struct ipv6_pinfo *np = inet6_sk(sk);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	req->front.key_len += sizeof(struct in6_addr) * 2;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	if (direction == TLS_OFFLOAD_CTX_DIR_TX) {
2028c2ecf20Sopenharmony_ci		nfp_net_tls_assign_conn_id(nn, &req->front);
2038c2ecf20Sopenharmony_ci	} else {
2048c2ecf20Sopenharmony_ci		memcpy(req->src_ip, &sk->sk_v6_daddr, sizeof(req->src_ip));
2058c2ecf20Sopenharmony_ci		memcpy(req->dst_ip, &np->saddr, sizeof(req->dst_ip));
2068c2ecf20Sopenharmony_ci	}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci#endif
2098c2ecf20Sopenharmony_ci	return &req->back;
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_cistatic void
2138c2ecf20Sopenharmony_cinfp_net_tls_set_l4(struct nfp_crypto_req_add_front *front,
2148c2ecf20Sopenharmony_ci		   struct nfp_crypto_req_add_back *back, struct sock *sk,
2158c2ecf20Sopenharmony_ci		   int direction)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	struct inet_sock *inet = inet_sk(sk);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	front->l4_proto = IPPROTO_TCP;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	if (direction == TLS_OFFLOAD_CTX_DIR_TX) {
2228c2ecf20Sopenharmony_ci		back->src_port = 0;
2238c2ecf20Sopenharmony_ci		back->dst_port = 0;
2248c2ecf20Sopenharmony_ci	} else {
2258c2ecf20Sopenharmony_ci		back->src_port = inet->inet_dport;
2268c2ecf20Sopenharmony_ci		back->dst_port = inet->inet_sport;
2278c2ecf20Sopenharmony_ci	}
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_cistatic u8 nfp_tls_1_2_dir_to_opcode(enum tls_offload_ctx_dir direction)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	switch (direction) {
2338c2ecf20Sopenharmony_ci	case TLS_OFFLOAD_CTX_DIR_TX:
2348c2ecf20Sopenharmony_ci		return NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_ENC;
2358c2ecf20Sopenharmony_ci	case TLS_OFFLOAD_CTX_DIR_RX:
2368c2ecf20Sopenharmony_ci		return NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_DEC;
2378c2ecf20Sopenharmony_ci	default:
2388c2ecf20Sopenharmony_ci		WARN_ON_ONCE(1);
2398c2ecf20Sopenharmony_ci		return 0;
2408c2ecf20Sopenharmony_ci	}
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_cistatic bool
2448c2ecf20Sopenharmony_cinfp_net_cipher_supported(struct nfp_net *nn, u16 cipher_type,
2458c2ecf20Sopenharmony_ci			 enum tls_offload_ctx_dir direction)
2468c2ecf20Sopenharmony_ci{
2478c2ecf20Sopenharmony_ci	u8 bit;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	switch (cipher_type) {
2508c2ecf20Sopenharmony_ci	case TLS_CIPHER_AES_GCM_128:
2518c2ecf20Sopenharmony_ci		if (direction == TLS_OFFLOAD_CTX_DIR_TX)
2528c2ecf20Sopenharmony_ci			bit = NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_ENC;
2538c2ecf20Sopenharmony_ci		else
2548c2ecf20Sopenharmony_ci			bit = NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_DEC;
2558c2ecf20Sopenharmony_ci		break;
2568c2ecf20Sopenharmony_ci	default:
2578c2ecf20Sopenharmony_ci		return false;
2588c2ecf20Sopenharmony_ci	}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	return nn->tlv_caps.crypto_ops & BIT(bit);
2618c2ecf20Sopenharmony_ci}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_cistatic int
2648c2ecf20Sopenharmony_cinfp_net_tls_add(struct net_device *netdev, struct sock *sk,
2658c2ecf20Sopenharmony_ci		enum tls_offload_ctx_dir direction,
2668c2ecf20Sopenharmony_ci		struct tls_crypto_info *crypto_info,
2678c2ecf20Sopenharmony_ci		u32 start_offload_tcp_sn)
2688c2ecf20Sopenharmony_ci{
2698c2ecf20Sopenharmony_ci	struct tls12_crypto_info_aes_gcm_128 *tls_ci;
2708c2ecf20Sopenharmony_ci	struct nfp_net *nn = netdev_priv(netdev);
2718c2ecf20Sopenharmony_ci	struct nfp_crypto_req_add_front *front;
2728c2ecf20Sopenharmony_ci	struct nfp_net_tls_offload_ctx *ntls;
2738c2ecf20Sopenharmony_ci	struct nfp_crypto_req_add_back *back;
2748c2ecf20Sopenharmony_ci	struct nfp_crypto_reply_add *reply;
2758c2ecf20Sopenharmony_ci	struct sk_buff *skb;
2768c2ecf20Sopenharmony_ci	size_t req_sz;
2778c2ecf20Sopenharmony_ci	void *req;
2788c2ecf20Sopenharmony_ci	bool ipv6;
2798c2ecf20Sopenharmony_ci	int err;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct nfp_net_tls_offload_ctx) >
2828c2ecf20Sopenharmony_ci		     TLS_DRIVER_STATE_SIZE_TX);
2838c2ecf20Sopenharmony_ci	BUILD_BUG_ON(offsetof(struct nfp_net_tls_offload_ctx, rx_end) >
2848c2ecf20Sopenharmony_ci		     TLS_DRIVER_STATE_SIZE_RX);
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	if (!nfp_net_cipher_supported(nn, crypto_info->cipher_type, direction))
2878c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	switch (sk->sk_family) {
2908c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
2918c2ecf20Sopenharmony_ci	case AF_INET6:
2928c2ecf20Sopenharmony_ci		if (sk->sk_ipv6only ||
2938c2ecf20Sopenharmony_ci		    ipv6_addr_type(&sk->sk_v6_daddr) != IPV6_ADDR_MAPPED) {
2948c2ecf20Sopenharmony_ci			req_sz = sizeof(struct nfp_crypto_req_add_v6);
2958c2ecf20Sopenharmony_ci			ipv6 = true;
2968c2ecf20Sopenharmony_ci			break;
2978c2ecf20Sopenharmony_ci		}
2988c2ecf20Sopenharmony_ci#endif
2998c2ecf20Sopenharmony_ci		fallthrough;
3008c2ecf20Sopenharmony_ci	case AF_INET:
3018c2ecf20Sopenharmony_ci		req_sz = sizeof(struct nfp_crypto_req_add_v4);
3028c2ecf20Sopenharmony_ci		ipv6 = false;
3038c2ecf20Sopenharmony_ci		break;
3048c2ecf20Sopenharmony_ci	default:
3058c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
3068c2ecf20Sopenharmony_ci	}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	err = nfp_net_tls_conn_add(nn, direction);
3098c2ecf20Sopenharmony_ci	if (err)
3108c2ecf20Sopenharmony_ci		return err;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	skb = nfp_ccm_mbox_msg_alloc(nn, req_sz, sizeof(*reply), GFP_KERNEL);
3138c2ecf20Sopenharmony_ci	if (!skb) {
3148c2ecf20Sopenharmony_ci		err = -ENOMEM;
3158c2ecf20Sopenharmony_ci		goto err_conn_remove;
3168c2ecf20Sopenharmony_ci	}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	front = (void *)skb->data;
3198c2ecf20Sopenharmony_ci	front->ep_id = 0;
3208c2ecf20Sopenharmony_ci	front->key_len = NFP_NET_TLS_NON_ADDR_KEY_LEN;
3218c2ecf20Sopenharmony_ci	front->opcode = nfp_tls_1_2_dir_to_opcode(direction);
3228c2ecf20Sopenharmony_ci	memset(front->resv, 0, sizeof(front->resv));
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	nfp_net_tls_set_ipver_vlan(front, ipv6 ? 6 : 4);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	req = (void *)skb->data;
3278c2ecf20Sopenharmony_ci	if (ipv6)
3288c2ecf20Sopenharmony_ci		back = nfp_net_tls_set_ipv6(nn, req, sk, direction);
3298c2ecf20Sopenharmony_ci	else
3308c2ecf20Sopenharmony_ci		back = nfp_net_tls_set_ipv4(nn, req, sk, direction);
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	nfp_net_tls_set_l4(front, back, sk, direction);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	back->counter = 0;
3358c2ecf20Sopenharmony_ci	back->tcp_seq = cpu_to_be32(start_offload_tcp_sn);
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	tls_ci = (struct tls12_crypto_info_aes_gcm_128 *)crypto_info;
3388c2ecf20Sopenharmony_ci	memcpy(back->key, tls_ci->key, TLS_CIPHER_AES_GCM_128_KEY_SIZE);
3398c2ecf20Sopenharmony_ci	memset(&back->key[TLS_CIPHER_AES_GCM_128_KEY_SIZE / 4], 0,
3408c2ecf20Sopenharmony_ci	       sizeof(back->key) - TLS_CIPHER_AES_GCM_128_KEY_SIZE);
3418c2ecf20Sopenharmony_ci	memcpy(back->iv, tls_ci->iv, TLS_CIPHER_AES_GCM_128_IV_SIZE);
3428c2ecf20Sopenharmony_ci	memcpy(&back->salt, tls_ci->salt, TLS_CIPHER_AES_GCM_128_SALT_SIZE);
3438c2ecf20Sopenharmony_ci	memcpy(back->rec_no, tls_ci->rec_seq, sizeof(tls_ci->rec_seq));
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	/* Get an extra ref on the skb so we can wipe the key after */
3468c2ecf20Sopenharmony_ci	skb_get(skb);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	err = nfp_ccm_mbox_communicate(nn, skb, NFP_CCM_TYPE_CRYPTO_ADD,
3498c2ecf20Sopenharmony_ci				       sizeof(*reply), sizeof(*reply));
3508c2ecf20Sopenharmony_ci	reply = (void *)skb->data;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	/* We depend on CCM MBOX code not reallocating skb we sent
3538c2ecf20Sopenharmony_ci	 * so we can clear the key material out of the memory.
3548c2ecf20Sopenharmony_ci	 */
3558c2ecf20Sopenharmony_ci	if (!WARN_ON_ONCE((u8 *)back < skb->head ||
3568c2ecf20Sopenharmony_ci			  (u8 *)back > skb_end_pointer(skb)) &&
3578c2ecf20Sopenharmony_ci	    !WARN_ON_ONCE((u8 *)&reply[1] > (u8 *)back))
3588c2ecf20Sopenharmony_ci		memzero_explicit(back, sizeof(*back));
3598c2ecf20Sopenharmony_ci	dev_consume_skb_any(skb); /* the extra ref from skb_get() above */
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	if (err) {
3628c2ecf20Sopenharmony_ci		nn_dp_warn(&nn->dp, "failed to add TLS: %d (%d)\n",
3638c2ecf20Sopenharmony_ci			   err, direction == TLS_OFFLOAD_CTX_DIR_TX);
3648c2ecf20Sopenharmony_ci		/* communicate frees skb on error */
3658c2ecf20Sopenharmony_ci		goto err_conn_remove;
3668c2ecf20Sopenharmony_ci	}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	err = -be32_to_cpu(reply->error);
3698c2ecf20Sopenharmony_ci	if (err) {
3708c2ecf20Sopenharmony_ci		if (err == -ENOSPC) {
3718c2ecf20Sopenharmony_ci			if (!atomic_fetch_inc(&nn->ktls_no_space))
3728c2ecf20Sopenharmony_ci				nn_info(nn, "HW TLS table full\n");
3738c2ecf20Sopenharmony_ci		} else {
3748c2ecf20Sopenharmony_ci			nn_dp_warn(&nn->dp,
3758c2ecf20Sopenharmony_ci				   "failed to add TLS, FW replied: %d\n", err);
3768c2ecf20Sopenharmony_ci		}
3778c2ecf20Sopenharmony_ci		goto err_free_skb;
3788c2ecf20Sopenharmony_ci	}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	if (!reply->handle[0] && !reply->handle[1]) {
3818c2ecf20Sopenharmony_ci		nn_dp_warn(&nn->dp, "FW returned NULL handle\n");
3828c2ecf20Sopenharmony_ci		err = -EINVAL;
3838c2ecf20Sopenharmony_ci		goto err_fw_remove;
3848c2ecf20Sopenharmony_ci	}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	ntls = tls_driver_ctx(sk, direction);
3878c2ecf20Sopenharmony_ci	memcpy(ntls->fw_handle, reply->handle, sizeof(ntls->fw_handle));
3888c2ecf20Sopenharmony_ci	if (direction == TLS_OFFLOAD_CTX_DIR_TX)
3898c2ecf20Sopenharmony_ci		ntls->next_seq = start_offload_tcp_sn;
3908c2ecf20Sopenharmony_ci	dev_consume_skb_any(skb);
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	if (direction == TLS_OFFLOAD_CTX_DIR_TX)
3938c2ecf20Sopenharmony_ci		return 0;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	if (!nn->tlv_caps.tls_resync_ss)
3968c2ecf20Sopenharmony_ci		tls_offload_rx_resync_set_type(sk, TLS_OFFLOAD_SYNC_TYPE_CORE_NEXT_HINT);
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	return 0;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_cierr_fw_remove:
4018c2ecf20Sopenharmony_ci	nfp_net_tls_del_fw(nn, reply->handle);
4028c2ecf20Sopenharmony_cierr_free_skb:
4038c2ecf20Sopenharmony_ci	dev_consume_skb_any(skb);
4048c2ecf20Sopenharmony_cierr_conn_remove:
4058c2ecf20Sopenharmony_ci	nfp_net_tls_conn_remove(nn, direction);
4068c2ecf20Sopenharmony_ci	return err;
4078c2ecf20Sopenharmony_ci}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_cistatic void
4108c2ecf20Sopenharmony_cinfp_net_tls_del(struct net_device *netdev, struct tls_context *tls_ctx,
4118c2ecf20Sopenharmony_ci		enum tls_offload_ctx_dir direction)
4128c2ecf20Sopenharmony_ci{
4138c2ecf20Sopenharmony_ci	struct nfp_net *nn = netdev_priv(netdev);
4148c2ecf20Sopenharmony_ci	struct nfp_net_tls_offload_ctx *ntls;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	nfp_net_tls_conn_remove(nn, direction);
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	ntls = __tls_driver_ctx(tls_ctx, direction);
4198c2ecf20Sopenharmony_ci	nfp_net_tls_del_fw(nn, ntls->fw_handle);
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_cistatic int
4238c2ecf20Sopenharmony_cinfp_net_tls_resync(struct net_device *netdev, struct sock *sk, u32 seq,
4248c2ecf20Sopenharmony_ci		   u8 *rcd_sn, enum tls_offload_ctx_dir direction)
4258c2ecf20Sopenharmony_ci{
4268c2ecf20Sopenharmony_ci	struct nfp_net *nn = netdev_priv(netdev);
4278c2ecf20Sopenharmony_ci	struct nfp_net_tls_offload_ctx *ntls;
4288c2ecf20Sopenharmony_ci	struct nfp_crypto_req_update *req;
4298c2ecf20Sopenharmony_ci	enum nfp_ccm_type type;
4308c2ecf20Sopenharmony_ci	struct sk_buff *skb;
4318c2ecf20Sopenharmony_ci	gfp_t flags;
4328c2ecf20Sopenharmony_ci	int err;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	flags = direction == TLS_OFFLOAD_CTX_DIR_TX ? GFP_KERNEL : GFP_ATOMIC;
4358c2ecf20Sopenharmony_ci	skb = nfp_net_tls_alloc_simple(nn, sizeof(*req), flags);
4368c2ecf20Sopenharmony_ci	if (!skb)
4378c2ecf20Sopenharmony_ci		return -ENOMEM;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	ntls = tls_driver_ctx(sk, direction);
4408c2ecf20Sopenharmony_ci	req = (void *)skb->data;
4418c2ecf20Sopenharmony_ci	req->ep_id = 0;
4428c2ecf20Sopenharmony_ci	req->opcode = nfp_tls_1_2_dir_to_opcode(direction);
4438c2ecf20Sopenharmony_ci	memset(req->resv, 0, sizeof(req->resv));
4448c2ecf20Sopenharmony_ci	memcpy(req->handle, ntls->fw_handle, sizeof(ntls->fw_handle));
4458c2ecf20Sopenharmony_ci	req->tcp_seq = cpu_to_be32(seq);
4468c2ecf20Sopenharmony_ci	memcpy(req->rec_no, rcd_sn, sizeof(req->rec_no));
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	type = NFP_CCM_TYPE_CRYPTO_UPDATE;
4498c2ecf20Sopenharmony_ci	if (direction == TLS_OFFLOAD_CTX_DIR_TX) {
4508c2ecf20Sopenharmony_ci		err = nfp_net_tls_communicate_simple(nn, skb, "sync", type);
4518c2ecf20Sopenharmony_ci		if (err)
4528c2ecf20Sopenharmony_ci			return err;
4538c2ecf20Sopenharmony_ci		ntls->next_seq = seq;
4548c2ecf20Sopenharmony_ci	} else {
4558c2ecf20Sopenharmony_ci		if (nn->tlv_caps.tls_resync_ss)
4568c2ecf20Sopenharmony_ci			type = NFP_CCM_TYPE_CRYPTO_RESYNC;
4578c2ecf20Sopenharmony_ci		nfp_ccm_mbox_post(nn, skb, type,
4588c2ecf20Sopenharmony_ci				  sizeof(struct nfp_crypto_reply_simple));
4598c2ecf20Sopenharmony_ci		atomic_inc(&nn->ktls_rx_resync_sent);
4608c2ecf20Sopenharmony_ci	}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	return 0;
4638c2ecf20Sopenharmony_ci}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_cistatic const struct tlsdev_ops nfp_net_tls_ops = {
4668c2ecf20Sopenharmony_ci	.tls_dev_add = nfp_net_tls_add,
4678c2ecf20Sopenharmony_ci	.tls_dev_del = nfp_net_tls_del,
4688c2ecf20Sopenharmony_ci	.tls_dev_resync = nfp_net_tls_resync,
4698c2ecf20Sopenharmony_ci};
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ciint nfp_net_tls_rx_resync_req(struct net_device *netdev,
4728c2ecf20Sopenharmony_ci			      struct nfp_net_tls_resync_req *req,
4738c2ecf20Sopenharmony_ci			      void *pkt, unsigned int pkt_len)
4748c2ecf20Sopenharmony_ci{
4758c2ecf20Sopenharmony_ci	struct nfp_net *nn = netdev_priv(netdev);
4768c2ecf20Sopenharmony_ci	struct nfp_net_tls_offload_ctx *ntls;
4778c2ecf20Sopenharmony_ci	struct ipv6hdr *ipv6h;
4788c2ecf20Sopenharmony_ci	struct tcphdr *th;
4798c2ecf20Sopenharmony_ci	struct iphdr *iph;
4808c2ecf20Sopenharmony_ci	struct sock *sk;
4818c2ecf20Sopenharmony_ci	__be32 tcp_seq;
4828c2ecf20Sopenharmony_ci	int err;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	iph = pkt + req->l3_offset;
4858c2ecf20Sopenharmony_ci	ipv6h = pkt + req->l3_offset;
4868c2ecf20Sopenharmony_ci	th = pkt + req->l4_offset;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	if ((u8 *)&th[1] > (u8 *)pkt + pkt_len) {
4898c2ecf20Sopenharmony_ci		netdev_warn_once(netdev, "invalid TLS RX resync request (l3_off: %hhu l4_off: %hhu pkt_len: %u)\n",
4908c2ecf20Sopenharmony_ci				 req->l3_offset, req->l4_offset, pkt_len);
4918c2ecf20Sopenharmony_ci		err = -EINVAL;
4928c2ecf20Sopenharmony_ci		goto err_cnt_ign;
4938c2ecf20Sopenharmony_ci	}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	switch (iph->version) {
4968c2ecf20Sopenharmony_ci	case 4:
4978c2ecf20Sopenharmony_ci		sk = inet_lookup_established(dev_net(netdev), &tcp_hashinfo,
4988c2ecf20Sopenharmony_ci					     iph->saddr, th->source, iph->daddr,
4998c2ecf20Sopenharmony_ci					     th->dest, netdev->ifindex);
5008c2ecf20Sopenharmony_ci		break;
5018c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
5028c2ecf20Sopenharmony_ci	case 6:
5038c2ecf20Sopenharmony_ci		sk = __inet6_lookup_established(dev_net(netdev), &tcp_hashinfo,
5048c2ecf20Sopenharmony_ci						&ipv6h->saddr, th->source,
5058c2ecf20Sopenharmony_ci						&ipv6h->daddr, ntohs(th->dest),
5068c2ecf20Sopenharmony_ci						netdev->ifindex, 0);
5078c2ecf20Sopenharmony_ci		break;
5088c2ecf20Sopenharmony_ci#endif
5098c2ecf20Sopenharmony_ci	default:
5108c2ecf20Sopenharmony_ci		netdev_warn_once(netdev, "invalid TLS RX resync request (l3_off: %hhu l4_off: %hhu ipver: %u)\n",
5118c2ecf20Sopenharmony_ci				 req->l3_offset, req->l4_offset, iph->version);
5128c2ecf20Sopenharmony_ci		err = -EINVAL;
5138c2ecf20Sopenharmony_ci		goto err_cnt_ign;
5148c2ecf20Sopenharmony_ci	}
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	err = 0;
5178c2ecf20Sopenharmony_ci	if (!sk)
5188c2ecf20Sopenharmony_ci		goto err_cnt_ign;
5198c2ecf20Sopenharmony_ci	if (!tls_is_sk_rx_device_offloaded(sk) ||
5208c2ecf20Sopenharmony_ci	    sk->sk_shutdown & RCV_SHUTDOWN)
5218c2ecf20Sopenharmony_ci		goto err_put_sock;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	ntls = tls_driver_ctx(sk, TLS_OFFLOAD_CTX_DIR_RX);
5248c2ecf20Sopenharmony_ci	/* some FW versions can't report the handle and report 0s */
5258c2ecf20Sopenharmony_ci	if (memchr_inv(&req->fw_handle, 0, sizeof(req->fw_handle)) &&
5268c2ecf20Sopenharmony_ci	    memcmp(&req->fw_handle, &ntls->fw_handle, sizeof(ntls->fw_handle)))
5278c2ecf20Sopenharmony_ci		goto err_put_sock;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	/* copy to ensure alignment */
5308c2ecf20Sopenharmony_ci	memcpy(&tcp_seq, &req->tcp_seq, sizeof(tcp_seq));
5318c2ecf20Sopenharmony_ci	tls_offload_rx_resync_request(sk, tcp_seq);
5328c2ecf20Sopenharmony_ci	atomic_inc(&nn->ktls_rx_resync_req);
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	sock_gen_put(sk);
5358c2ecf20Sopenharmony_ci	return 0;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_cierr_put_sock:
5388c2ecf20Sopenharmony_ci	sock_gen_put(sk);
5398c2ecf20Sopenharmony_cierr_cnt_ign:
5408c2ecf20Sopenharmony_ci	atomic_inc(&nn->ktls_rx_resync_ign);
5418c2ecf20Sopenharmony_ci	return err;
5428c2ecf20Sopenharmony_ci}
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_cistatic int nfp_net_tls_reset(struct nfp_net *nn)
5458c2ecf20Sopenharmony_ci{
5468c2ecf20Sopenharmony_ci	struct nfp_crypto_req_reset *req;
5478c2ecf20Sopenharmony_ci	struct sk_buff *skb;
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	skb = nfp_net_tls_alloc_simple(nn, sizeof(*req), GFP_KERNEL);
5508c2ecf20Sopenharmony_ci	if (!skb)
5518c2ecf20Sopenharmony_ci		return -ENOMEM;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	req = (void *)skb->data;
5548c2ecf20Sopenharmony_ci	req->ep_id = 0;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	return nfp_net_tls_communicate_simple(nn, skb, "reset",
5578c2ecf20Sopenharmony_ci					      NFP_CCM_TYPE_CRYPTO_RESET);
5588c2ecf20Sopenharmony_ci}
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ciint nfp_net_tls_init(struct nfp_net *nn)
5618c2ecf20Sopenharmony_ci{
5628c2ecf20Sopenharmony_ci	struct net_device *netdev = nn->dp.netdev;
5638c2ecf20Sopenharmony_ci	int err;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	if (!(nn->tlv_caps.crypto_ops & NFP_NET_TLS_OPCODE_MASK))
5668c2ecf20Sopenharmony_ci		return 0;
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci	if ((nn->tlv_caps.mbox_cmsg_types & NFP_NET_TLS_CCM_MBOX_OPS_MASK) !=
5698c2ecf20Sopenharmony_ci	    NFP_NET_TLS_CCM_MBOX_OPS_MASK)
5708c2ecf20Sopenharmony_ci		return 0;
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	if (!nfp_ccm_mbox_fits(nn, sizeof(struct nfp_crypto_req_add_v6))) {
5738c2ecf20Sopenharmony_ci		nn_warn(nn, "disabling TLS offload - mbox too small: %d\n",
5748c2ecf20Sopenharmony_ci			nn->tlv_caps.mbox_len);
5758c2ecf20Sopenharmony_ci		return 0;
5768c2ecf20Sopenharmony_ci	}
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	err = nfp_net_tls_reset(nn);
5798c2ecf20Sopenharmony_ci	if (err)
5808c2ecf20Sopenharmony_ci		return err;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	nn_ctrl_bar_lock(nn);
5838c2ecf20Sopenharmony_ci	nn_writel(nn, nn->tlv_caps.crypto_enable_off, 0);
5848c2ecf20Sopenharmony_ci	err = __nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_CRYPTO);
5858c2ecf20Sopenharmony_ci	nn_ctrl_bar_unlock(nn);
5868c2ecf20Sopenharmony_ci	if (err)
5878c2ecf20Sopenharmony_ci		return err;
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	if (nn->tlv_caps.crypto_ops & NFP_NET_TLS_OPCODE_MASK_RX) {
5908c2ecf20Sopenharmony_ci		netdev->hw_features |= NETIF_F_HW_TLS_RX;
5918c2ecf20Sopenharmony_ci		netdev->features |= NETIF_F_HW_TLS_RX;
5928c2ecf20Sopenharmony_ci	}
5938c2ecf20Sopenharmony_ci	if (nn->tlv_caps.crypto_ops & NFP_NET_TLS_OPCODE_MASK_TX) {
5948c2ecf20Sopenharmony_ci		netdev->hw_features |= NETIF_F_HW_TLS_TX;
5958c2ecf20Sopenharmony_ci		netdev->features |= NETIF_F_HW_TLS_TX;
5968c2ecf20Sopenharmony_ci	}
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	netdev->tlsdev_ops = &nfp_net_tls_ops;
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	return 0;
6018c2ecf20Sopenharmony_ci}
602