xref: /openbmc/linux/drivers/net/ethernet/netronome/nfp/crypto/tls.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1232eeb1fSJakub Kicinski // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2232eeb1fSJakub Kicinski /* Copyright (C) 2019 Netronome Systems, Inc. */
3232eeb1fSJakub Kicinski 
41f35a56cSDirk van der Merwe #include <linux/bitfield.h>
51f35a56cSDirk van der Merwe #include <linux/ipv6.h>
6232eeb1fSJakub Kicinski #include <linux/skbuff.h>
7c3b64911SJakub Kicinski #include <linux/string.h>
86a35ddc5SJakub Kicinski #include <net/inet6_hashtables.h>
9232eeb1fSJakub Kicinski #include <net/tls.h>
10232eeb1fSJakub Kicinski 
11232eeb1fSJakub Kicinski #include "../ccm.h"
12232eeb1fSJakub Kicinski #include "../nfp_net.h"
13232eeb1fSJakub Kicinski #include "crypto.h"
14232eeb1fSJakub Kicinski #include "fw.h"
15232eeb1fSJakub Kicinski 
16232eeb1fSJakub Kicinski #define NFP_NET_TLS_CCM_MBOX_OPS_MASK		\
17232eeb1fSJakub Kicinski 	(BIT(NFP_CCM_TYPE_CRYPTO_RESET) |	\
18232eeb1fSJakub Kicinski 	 BIT(NFP_CCM_TYPE_CRYPTO_ADD) |		\
19232eeb1fSJakub Kicinski 	 BIT(NFP_CCM_TYPE_CRYPTO_DEL) |		\
20232eeb1fSJakub Kicinski 	 BIT(NFP_CCM_TYPE_CRYPTO_UPDATE))
21232eeb1fSJakub Kicinski 
22232eeb1fSJakub Kicinski #define NFP_NET_TLS_OPCODE_MASK_RX			\
23232eeb1fSJakub Kicinski 	BIT(NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_DEC)
24232eeb1fSJakub Kicinski 
25232eeb1fSJakub Kicinski #define NFP_NET_TLS_OPCODE_MASK_TX			\
26232eeb1fSJakub Kicinski 	BIT(NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_ENC)
27232eeb1fSJakub Kicinski 
28232eeb1fSJakub Kicinski #define NFP_NET_TLS_OPCODE_MASK						\
29232eeb1fSJakub Kicinski 	(NFP_NET_TLS_OPCODE_MASK_RX | NFP_NET_TLS_OPCODE_MASK_TX)
30232eeb1fSJakub Kicinski 
nfp_net_crypto_set_op(struct nfp_net * nn,u8 opcode,bool on)311f35a56cSDirk van der Merwe static void nfp_net_crypto_set_op(struct nfp_net *nn, u8 opcode, bool on)
321f35a56cSDirk van der Merwe {
331f35a56cSDirk van der Merwe 	u32 off, val;
341f35a56cSDirk van der Merwe 
351f35a56cSDirk van der Merwe 	off = nn->tlv_caps.crypto_enable_off + round_down(opcode / 8, 4);
361f35a56cSDirk van der Merwe 
371f35a56cSDirk van der Merwe 	val = nn_readl(nn, off);
381f35a56cSDirk van der Merwe 	if (on)
391f35a56cSDirk van der Merwe 		val |= BIT(opcode & 31);
401f35a56cSDirk van der Merwe 	else
411f35a56cSDirk van der Merwe 		val &= ~BIT(opcode & 31);
421f35a56cSDirk van der Merwe 	nn_writel(nn, off, val);
431f35a56cSDirk van der Merwe }
441f35a56cSDirk van der Merwe 
451f35a56cSDirk van der Merwe static bool
__nfp_net_tls_conn_cnt_changed(struct nfp_net * nn,int add,enum tls_offload_ctx_dir direction)461f35a56cSDirk van der Merwe __nfp_net_tls_conn_cnt_changed(struct nfp_net *nn, int add,
471f35a56cSDirk van der Merwe 			       enum tls_offload_ctx_dir direction)
481f35a56cSDirk van der Merwe {
491f35a56cSDirk van der Merwe 	u8 opcode;
501f35a56cSDirk van der Merwe 	int cnt;
511f35a56cSDirk van der Merwe 
52c0a4948eSJakub Kicinski 	if (direction == TLS_OFFLOAD_CTX_DIR_TX) {
531f35a56cSDirk van der Merwe 		opcode = NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_ENC;
541f35a56cSDirk van der Merwe 		nn->ktls_tx_conn_cnt += add;
551f35a56cSDirk van der Merwe 		cnt = nn->ktls_tx_conn_cnt;
561f35a56cSDirk van der Merwe 		nn->dp.ktls_tx = !!nn->ktls_tx_conn_cnt;
57c0a4948eSJakub Kicinski 	} else {
58c0a4948eSJakub Kicinski 		opcode = NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_DEC;
59c0a4948eSJakub Kicinski 		nn->ktls_rx_conn_cnt += add;
60c0a4948eSJakub Kicinski 		cnt = nn->ktls_rx_conn_cnt;
61c0a4948eSJakub Kicinski 	}
621f35a56cSDirk van der Merwe 
631f35a56cSDirk van der Merwe 	/* Care only about 0 -> 1 and 1 -> 0 transitions */
641f35a56cSDirk van der Merwe 	if (cnt > 1)
651f35a56cSDirk van der Merwe 		return false;
661f35a56cSDirk van der Merwe 
671f35a56cSDirk van der Merwe 	nfp_net_crypto_set_op(nn, opcode, cnt);
681f35a56cSDirk van der Merwe 	return true;
691f35a56cSDirk van der Merwe }
701f35a56cSDirk van der Merwe 
711f35a56cSDirk van der Merwe static int
nfp_net_tls_conn_cnt_changed(struct nfp_net * nn,int add,enum tls_offload_ctx_dir direction)721f35a56cSDirk van der Merwe nfp_net_tls_conn_cnt_changed(struct nfp_net *nn, int add,
731f35a56cSDirk van der Merwe 			     enum tls_offload_ctx_dir direction)
741f35a56cSDirk van der Merwe {
751f35a56cSDirk van der Merwe 	int ret = 0;
761f35a56cSDirk van der Merwe 
771f35a56cSDirk van der Merwe 	/* Use the BAR lock to protect the connection counts */
781f35a56cSDirk van der Merwe 	nn_ctrl_bar_lock(nn);
791f35a56cSDirk van der Merwe 	if (__nfp_net_tls_conn_cnt_changed(nn, add, direction)) {
801f35a56cSDirk van der Merwe 		ret = __nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_CRYPTO);
811f35a56cSDirk van der Merwe 		/* Undo the cnt adjustment if failed */
821f35a56cSDirk van der Merwe 		if (ret)
831f35a56cSDirk van der Merwe 			__nfp_net_tls_conn_cnt_changed(nn, -add, direction);
841f35a56cSDirk van der Merwe 	}
851f35a56cSDirk van der Merwe 	nn_ctrl_bar_unlock(nn);
861f35a56cSDirk van der Merwe 
871f35a56cSDirk van der Merwe 	return ret;
881f35a56cSDirk van der Merwe }
891f35a56cSDirk van der Merwe 
901f35a56cSDirk van der Merwe static int
nfp_net_tls_conn_add(struct nfp_net * nn,enum tls_offload_ctx_dir direction)911f35a56cSDirk van der Merwe nfp_net_tls_conn_add(struct nfp_net *nn, enum tls_offload_ctx_dir direction)
921f35a56cSDirk van der Merwe {
931f35a56cSDirk van der Merwe 	return nfp_net_tls_conn_cnt_changed(nn, 1, direction);
941f35a56cSDirk van der Merwe }
951f35a56cSDirk van der Merwe 
961f35a56cSDirk van der Merwe static int
nfp_net_tls_conn_remove(struct nfp_net * nn,enum tls_offload_ctx_dir direction)971f35a56cSDirk van der Merwe nfp_net_tls_conn_remove(struct nfp_net *nn, enum tls_offload_ctx_dir direction)
981f35a56cSDirk van der Merwe {
991f35a56cSDirk van der Merwe 	return nfp_net_tls_conn_cnt_changed(nn, -1, direction);
1001f35a56cSDirk van der Merwe }
1011f35a56cSDirk van der Merwe 
102232eeb1fSJakub Kicinski static struct sk_buff *
nfp_net_tls_alloc_simple(struct nfp_net * nn,size_t req_sz,gfp_t flags)103232eeb1fSJakub Kicinski nfp_net_tls_alloc_simple(struct nfp_net *nn, size_t req_sz, gfp_t flags)
104232eeb1fSJakub Kicinski {
105d7053e04SJakub Kicinski 	return nfp_ccm_mbox_msg_alloc(nn, req_sz,
106232eeb1fSJakub Kicinski 				      sizeof(struct nfp_crypto_reply_simple),
107232eeb1fSJakub Kicinski 				      flags);
108232eeb1fSJakub Kicinski }
109232eeb1fSJakub Kicinski 
110232eeb1fSJakub Kicinski static int
nfp_net_tls_communicate_simple(struct nfp_net * nn,struct sk_buff * skb,const char * name,enum nfp_ccm_type type)111232eeb1fSJakub Kicinski nfp_net_tls_communicate_simple(struct nfp_net *nn, struct sk_buff *skb,
112232eeb1fSJakub Kicinski 			       const char *name, enum nfp_ccm_type type)
113232eeb1fSJakub Kicinski {
114232eeb1fSJakub Kicinski 	struct nfp_crypto_reply_simple *reply;
115232eeb1fSJakub Kicinski 	int err;
116232eeb1fSJakub Kicinski 
1170f93242dSJakub Kicinski 	err = __nfp_ccm_mbox_communicate(nn, skb, type,
1180f93242dSJakub Kicinski 					 sizeof(*reply), sizeof(*reply),
1190f93242dSJakub Kicinski 					 type == NFP_CCM_TYPE_CRYPTO_DEL);
120232eeb1fSJakub Kicinski 	if (err) {
121232eeb1fSJakub Kicinski 		nn_dp_warn(&nn->dp, "failed to %s TLS: %d\n", name, err);
122232eeb1fSJakub Kicinski 		return err;
123232eeb1fSJakub Kicinski 	}
124232eeb1fSJakub Kicinski 
125232eeb1fSJakub Kicinski 	reply = (void *)skb->data;
126232eeb1fSJakub Kicinski 	err = -be32_to_cpu(reply->error);
127232eeb1fSJakub Kicinski 	if (err)
128232eeb1fSJakub Kicinski 		nn_dp_warn(&nn->dp, "failed to %s TLS, fw replied: %d\n",
129232eeb1fSJakub Kicinski 			   name, err);
130232eeb1fSJakub Kicinski 	dev_consume_skb_any(skb);
131232eeb1fSJakub Kicinski 
132232eeb1fSJakub Kicinski 	return err;
133232eeb1fSJakub Kicinski }
134232eeb1fSJakub Kicinski 
nfp_net_tls_del_fw(struct nfp_net * nn,__be32 * fw_handle)1351f35a56cSDirk van der Merwe static void nfp_net_tls_del_fw(struct nfp_net *nn, __be32 *fw_handle)
1361f35a56cSDirk van der Merwe {
1371f35a56cSDirk van der Merwe 	struct nfp_crypto_req_del *req;
1381f35a56cSDirk van der Merwe 	struct sk_buff *skb;
1391f35a56cSDirk van der Merwe 
1401f35a56cSDirk van der Merwe 	skb = nfp_net_tls_alloc_simple(nn, sizeof(*req), GFP_KERNEL);
1411f35a56cSDirk van der Merwe 	if (!skb)
1421f35a56cSDirk van der Merwe 		return;
1431f35a56cSDirk van der Merwe 
1441f35a56cSDirk van der Merwe 	req = (void *)skb->data;
1451f35a56cSDirk van der Merwe 	req->ep_id = 0;
1461f35a56cSDirk van der Merwe 	memcpy(req->handle, fw_handle, sizeof(req->handle));
1471f35a56cSDirk van der Merwe 
1481f35a56cSDirk van der Merwe 	nfp_net_tls_communicate_simple(nn, skb, "delete",
1491f35a56cSDirk van der Merwe 				       NFP_CCM_TYPE_CRYPTO_DEL);
1501f35a56cSDirk van der Merwe }
1511f35a56cSDirk van der Merwe 
152ff8869d5SJakub Kicinski static void
nfp_net_tls_set_ipver_vlan(struct nfp_crypto_req_add_front * front,u8 ipver)153ff8869d5SJakub Kicinski nfp_net_tls_set_ipver_vlan(struct nfp_crypto_req_add_front *front, u8 ipver)
154ff8869d5SJakub Kicinski {
155ff8869d5SJakub Kicinski 	front->ipver_vlan = cpu_to_be16(FIELD_PREP(NFP_NET_TLS_IPVER, ipver) |
156ff8869d5SJakub Kicinski 					FIELD_PREP(NFP_NET_TLS_VLAN,
157ff8869d5SJakub Kicinski 						   NFP_NET_TLS_VLAN_UNUSED));
158ff8869d5SJakub Kicinski }
159ff8869d5SJakub Kicinski 
16053601c68SJakub Kicinski static void
nfp_net_tls_assign_conn_id(struct nfp_net * nn,struct nfp_crypto_req_add_front * front)16153601c68SJakub Kicinski nfp_net_tls_assign_conn_id(struct nfp_net *nn,
16253601c68SJakub Kicinski 			   struct nfp_crypto_req_add_front *front)
16353601c68SJakub Kicinski {
16453601c68SJakub Kicinski 	u32 len;
16553601c68SJakub Kicinski 	u64 id;
16653601c68SJakub Kicinski 
16753601c68SJakub Kicinski 	id = atomic64_inc_return(&nn->ktls_conn_id_gen);
16853601c68SJakub Kicinski 	len = front->key_len - NFP_NET_TLS_NON_ADDR_KEY_LEN;
16953601c68SJakub Kicinski 
17053601c68SJakub Kicinski 	memcpy(front->l3_addrs, &id, sizeof(id));
17153601c68SJakub Kicinski 	memset(front->l3_addrs + sizeof(id), 0, len - sizeof(id));
17253601c68SJakub Kicinski }
17353601c68SJakub Kicinski 
1741f35a56cSDirk van der Merwe static struct nfp_crypto_req_add_back *
nfp_net_tls_set_ipv4(struct nfp_net * nn,struct nfp_crypto_req_add_v4 * req,struct sock * sk,int direction)17553601c68SJakub Kicinski nfp_net_tls_set_ipv4(struct nfp_net *nn, struct nfp_crypto_req_add_v4 *req,
17653601c68SJakub Kicinski 		     struct sock *sk, int direction)
1771f35a56cSDirk van der Merwe {
1781f35a56cSDirk van der Merwe 	struct inet_sock *inet = inet_sk(sk);
1791f35a56cSDirk van der Merwe 
1801f35a56cSDirk van der Merwe 	req->front.key_len += sizeof(__be32) * 2;
1811f35a56cSDirk van der Merwe 
1821f35a56cSDirk van der Merwe 	if (direction == TLS_OFFLOAD_CTX_DIR_TX) {
18353601c68SJakub Kicinski 		nfp_net_tls_assign_conn_id(nn, &req->front);
1841f35a56cSDirk van der Merwe 	} else {
1851f35a56cSDirk van der Merwe 		req->src_ip = inet->inet_daddr;
1861f35a56cSDirk van der Merwe 		req->dst_ip = inet->inet_saddr;
1871f35a56cSDirk van der Merwe 	}
1881f35a56cSDirk van der Merwe 
1891f35a56cSDirk van der Merwe 	return &req->back;
1901f35a56cSDirk van der Merwe }
1911f35a56cSDirk van der Merwe 
1921f35a56cSDirk van der Merwe static struct nfp_crypto_req_add_back *
nfp_net_tls_set_ipv6(struct nfp_net * nn,struct nfp_crypto_req_add_v6 * req,struct sock * sk,int direction)19353601c68SJakub Kicinski nfp_net_tls_set_ipv6(struct nfp_net *nn, struct nfp_crypto_req_add_v6 *req,
19453601c68SJakub Kicinski 		     struct sock *sk, int direction)
1951f35a56cSDirk van der Merwe {
1961f35a56cSDirk van der Merwe #if IS_ENABLED(CONFIG_IPV6)
1971f35a56cSDirk van der Merwe 	struct ipv6_pinfo *np = inet6_sk(sk);
1981f35a56cSDirk van der Merwe 
1991f35a56cSDirk van der Merwe 	req->front.key_len += sizeof(struct in6_addr) * 2;
2001f35a56cSDirk van der Merwe 
2011f35a56cSDirk van der Merwe 	if (direction == TLS_OFFLOAD_CTX_DIR_TX) {
20253601c68SJakub Kicinski 		nfp_net_tls_assign_conn_id(nn, &req->front);
2031f35a56cSDirk van der Merwe 	} else {
2041f35a56cSDirk van der Merwe 		memcpy(req->src_ip, &sk->sk_v6_daddr, sizeof(req->src_ip));
2051f35a56cSDirk van der Merwe 		memcpy(req->dst_ip, &np->saddr, sizeof(req->dst_ip));
2061f35a56cSDirk van der Merwe 	}
2071f35a56cSDirk van der Merwe 
2081f35a56cSDirk van der Merwe #endif
2091f35a56cSDirk van der Merwe 	return &req->back;
2101f35a56cSDirk van der Merwe }
2111f35a56cSDirk van der Merwe 
2121f35a56cSDirk van der Merwe static void
nfp_net_tls_set_l4(struct nfp_crypto_req_add_front * front,struct nfp_crypto_req_add_back * back,struct sock * sk,int direction)2131f35a56cSDirk van der Merwe nfp_net_tls_set_l4(struct nfp_crypto_req_add_front *front,
2141f35a56cSDirk van der Merwe 		   struct nfp_crypto_req_add_back *back, struct sock *sk,
2151f35a56cSDirk van der Merwe 		   int direction)
2161f35a56cSDirk van der Merwe {
2171f35a56cSDirk van der Merwe 	struct inet_sock *inet = inet_sk(sk);
2181f35a56cSDirk van der Merwe 
2191f35a56cSDirk van der Merwe 	front->l4_proto = IPPROTO_TCP;
2201f35a56cSDirk van der Merwe 
2211f35a56cSDirk van der Merwe 	if (direction == TLS_OFFLOAD_CTX_DIR_TX) {
22253601c68SJakub Kicinski 		back->src_port = 0;
22353601c68SJakub Kicinski 		back->dst_port = 0;
2241f35a56cSDirk van der Merwe 	} else {
2251f35a56cSDirk van der Merwe 		back->src_port = inet->inet_dport;
2261f35a56cSDirk van der Merwe 		back->dst_port = inet->inet_sport;
2271f35a56cSDirk van der Merwe 	}
2281f35a56cSDirk van der Merwe }
2291f35a56cSDirk van der Merwe 
nfp_tls_1_2_dir_to_opcode(enum tls_offload_ctx_dir direction)2301f35a56cSDirk van der Merwe static u8 nfp_tls_1_2_dir_to_opcode(enum tls_offload_ctx_dir direction)
2311f35a56cSDirk van der Merwe {
2321f35a56cSDirk van der Merwe 	switch (direction) {
2331f35a56cSDirk van der Merwe 	case TLS_OFFLOAD_CTX_DIR_TX:
2341f35a56cSDirk van der Merwe 		return NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_ENC;
2351f35a56cSDirk van der Merwe 	case TLS_OFFLOAD_CTX_DIR_RX:
2361f35a56cSDirk van der Merwe 		return NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_DEC;
2371f35a56cSDirk van der Merwe 	default:
2381f35a56cSDirk van der Merwe 		WARN_ON_ONCE(1);
2391f35a56cSDirk van der Merwe 		return 0;
2401f35a56cSDirk van der Merwe 	}
2411f35a56cSDirk van der Merwe }
2421f35a56cSDirk van der Merwe 
2431f35a56cSDirk van der Merwe static bool
nfp_net_cipher_supported(struct nfp_net * nn,u16 cipher_type,enum tls_offload_ctx_dir direction)2441f35a56cSDirk van der Merwe nfp_net_cipher_supported(struct nfp_net *nn, u16 cipher_type,
2451f35a56cSDirk van der Merwe 			 enum tls_offload_ctx_dir direction)
2461f35a56cSDirk van der Merwe {
2471f35a56cSDirk van der Merwe 	u8 bit;
2481f35a56cSDirk van der Merwe 
2491f35a56cSDirk van der Merwe 	switch (cipher_type) {
2501f35a56cSDirk van der Merwe 	case TLS_CIPHER_AES_GCM_128:
2511f35a56cSDirk van der Merwe 		if (direction == TLS_OFFLOAD_CTX_DIR_TX)
2521f35a56cSDirk van der Merwe 			bit = NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_ENC;
2531f35a56cSDirk van der Merwe 		else
254c0a4948eSJakub Kicinski 			bit = NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_DEC;
2551f35a56cSDirk van der Merwe 		break;
2561f35a56cSDirk van der Merwe 	default:
2571f35a56cSDirk van der Merwe 		return false;
2581f35a56cSDirk van der Merwe 	}
2591f35a56cSDirk van der Merwe 
2601f35a56cSDirk van der Merwe 	return nn->tlv_caps.crypto_ops & BIT(bit);
2611f35a56cSDirk van der Merwe }
2621f35a56cSDirk van der Merwe 
263232eeb1fSJakub Kicinski static int
nfp_net_tls_add(struct net_device * netdev,struct sock * sk,enum tls_offload_ctx_dir direction,struct tls_crypto_info * crypto_info,u32 start_offload_tcp_sn)264232eeb1fSJakub Kicinski nfp_net_tls_add(struct net_device *netdev, struct sock *sk,
265232eeb1fSJakub Kicinski 		enum tls_offload_ctx_dir direction,
266232eeb1fSJakub Kicinski 		struct tls_crypto_info *crypto_info,
267232eeb1fSJakub Kicinski 		u32 start_offload_tcp_sn)
268232eeb1fSJakub Kicinski {
2691f35a56cSDirk van der Merwe 	struct tls12_crypto_info_aes_gcm_128 *tls_ci;
2701f35a56cSDirk van der Merwe 	struct nfp_net *nn = netdev_priv(netdev);
2711f35a56cSDirk van der Merwe 	struct nfp_crypto_req_add_front *front;
2721f35a56cSDirk van der Merwe 	struct nfp_net_tls_offload_ctx *ntls;
2731f35a56cSDirk van der Merwe 	struct nfp_crypto_req_add_back *back;
2741f35a56cSDirk van der Merwe 	struct nfp_crypto_reply_add *reply;
2751f35a56cSDirk van der Merwe 	struct sk_buff *skb;
2761f35a56cSDirk van der Merwe 	size_t req_sz;
27753601c68SJakub Kicinski 	void *req;
2781f35a56cSDirk van der Merwe 	bool ipv6;
2791f35a56cSDirk van der Merwe 	int err;
2801f35a56cSDirk van der Merwe 
2811f35a56cSDirk van der Merwe 	BUILD_BUG_ON(sizeof(struct nfp_net_tls_offload_ctx) >
2821f35a56cSDirk van der Merwe 		     TLS_DRIVER_STATE_SIZE_TX);
283c0a4948eSJakub Kicinski 	BUILD_BUG_ON(offsetof(struct nfp_net_tls_offload_ctx, rx_end) >
284c0a4948eSJakub Kicinski 		     TLS_DRIVER_STATE_SIZE_RX);
2851f35a56cSDirk van der Merwe 
2861f35a56cSDirk van der Merwe 	if (!nfp_net_cipher_supported(nn, crypto_info->cipher_type, direction))
287232eeb1fSJakub Kicinski 		return -EOPNOTSUPP;
2881f35a56cSDirk van der Merwe 
2891f35a56cSDirk van der Merwe 	switch (sk->sk_family) {
2901f35a56cSDirk van der Merwe #if IS_ENABLED(CONFIG_IPV6)
2911f35a56cSDirk van der Merwe 	case AF_INET6:
29281ee0eb6SKuniyuki Iwashima 		if (ipv6_only_sock(sk) ||
2931f35a56cSDirk van der Merwe 		    ipv6_addr_type(&sk->sk_v6_daddr) != IPV6_ADDR_MAPPED) {
2941f35a56cSDirk van der Merwe 			req_sz = sizeof(struct nfp_crypto_req_add_v6);
2951f35a56cSDirk van der Merwe 			ipv6 = true;
2961f35a56cSDirk van der Merwe 			break;
2971f35a56cSDirk van der Merwe 		}
298df561f66SGustavo A. R. Silva 		fallthrough;
299ed30aef3SGustavo A. R. Silva #endif
3001f35a56cSDirk van der Merwe 	case AF_INET:
3011f35a56cSDirk van der Merwe 		req_sz = sizeof(struct nfp_crypto_req_add_v4);
3021f35a56cSDirk van der Merwe 		ipv6 = false;
3031f35a56cSDirk van der Merwe 		break;
3041f35a56cSDirk van der Merwe 	default:
3051f35a56cSDirk van der Merwe 		return -EOPNOTSUPP;
3061f35a56cSDirk van der Merwe 	}
3071f35a56cSDirk van der Merwe 
3081f35a56cSDirk van der Merwe 	err = nfp_net_tls_conn_add(nn, direction);
3091f35a56cSDirk van der Merwe 	if (err)
3101f35a56cSDirk van der Merwe 		return err;
3111f35a56cSDirk van der Merwe 
312d7053e04SJakub Kicinski 	skb = nfp_ccm_mbox_msg_alloc(nn, req_sz, sizeof(*reply), GFP_KERNEL);
3131f35a56cSDirk van der Merwe 	if (!skb) {
3141f35a56cSDirk van der Merwe 		err = -ENOMEM;
3151f35a56cSDirk van der Merwe 		goto err_conn_remove;
3161f35a56cSDirk van der Merwe 	}
3171f35a56cSDirk van der Merwe 
3181f35a56cSDirk van der Merwe 	front = (void *)skb->data;
3191f35a56cSDirk van der Merwe 	front->ep_id = 0;
32053601c68SJakub Kicinski 	front->key_len = NFP_NET_TLS_NON_ADDR_KEY_LEN;
3211f35a56cSDirk van der Merwe 	front->opcode = nfp_tls_1_2_dir_to_opcode(direction);
3221f35a56cSDirk van der Merwe 	memset(front->resv, 0, sizeof(front->resv));
3231f35a56cSDirk van der Merwe 
324ff8869d5SJakub Kicinski 	nfp_net_tls_set_ipver_vlan(front, ipv6 ? 6 : 4);
325ff8869d5SJakub Kicinski 
32653601c68SJakub Kicinski 	req = (void *)skb->data;
3271f35a56cSDirk van der Merwe 	if (ipv6)
32853601c68SJakub Kicinski 		back = nfp_net_tls_set_ipv6(nn, req, sk, direction);
3291f35a56cSDirk van der Merwe 	else
33053601c68SJakub Kicinski 		back = nfp_net_tls_set_ipv4(nn, req, sk, direction);
3311f35a56cSDirk van der Merwe 
3321f35a56cSDirk van der Merwe 	nfp_net_tls_set_l4(front, back, sk, direction);
3331f35a56cSDirk van der Merwe 
3341f35a56cSDirk van der Merwe 	back->counter = 0;
3351f35a56cSDirk van der Merwe 	back->tcp_seq = cpu_to_be32(start_offload_tcp_sn);
3361f35a56cSDirk van der Merwe 
3371f35a56cSDirk van der Merwe 	tls_ci = (struct tls12_crypto_info_aes_gcm_128 *)crypto_info;
3381f35a56cSDirk van der Merwe 	memcpy(back->key, tls_ci->key, TLS_CIPHER_AES_GCM_128_KEY_SIZE);
3391f35a56cSDirk van der Merwe 	memset(&back->key[TLS_CIPHER_AES_GCM_128_KEY_SIZE / 4], 0,
3401f35a56cSDirk van der Merwe 	       sizeof(back->key) - TLS_CIPHER_AES_GCM_128_KEY_SIZE);
3411f35a56cSDirk van der Merwe 	memcpy(back->iv, tls_ci->iv, TLS_CIPHER_AES_GCM_128_IV_SIZE);
3421f35a56cSDirk van der Merwe 	memcpy(&back->salt, tls_ci->salt, TLS_CIPHER_AES_GCM_128_SALT_SIZE);
3431f35a56cSDirk van der Merwe 	memcpy(back->rec_no, tls_ci->rec_seq, sizeof(tls_ci->rec_seq));
3441f35a56cSDirk van der Merwe 
345c3b64911SJakub Kicinski 	/* Get an extra ref on the skb so we can wipe the key after */
346c3b64911SJakub Kicinski 	skb_get(skb);
347c3b64911SJakub Kicinski 
3481f35a56cSDirk van der Merwe 	err = nfp_ccm_mbox_communicate(nn, skb, NFP_CCM_TYPE_CRYPTO_ADD,
3491f35a56cSDirk van der Merwe 				       sizeof(*reply), sizeof(*reply));
350c3b64911SJakub Kicinski 	reply = (void *)skb->data;
351c3b64911SJakub Kicinski 
352c3b64911SJakub Kicinski 	/* We depend on CCM MBOX code not reallocating skb we sent
353c3b64911SJakub Kicinski 	 * so we can clear the key material out of the memory.
354c3b64911SJakub Kicinski 	 */
355c3b64911SJakub Kicinski 	if (!WARN_ON_ONCE((u8 *)back < skb->head ||
356c3b64911SJakub Kicinski 			  (u8 *)back > skb_end_pointer(skb)) &&
357c3b64911SJakub Kicinski 	    !WARN_ON_ONCE((u8 *)&reply[1] > (u8 *)back))
358c3b64911SJakub Kicinski 		memzero_explicit(back, sizeof(*back));
359c3b64911SJakub Kicinski 	dev_consume_skb_any(skb); /* the extra ref from skb_get() above */
360c3b64911SJakub Kicinski 
3611f35a56cSDirk van der Merwe 	if (err) {
36253601c68SJakub Kicinski 		nn_dp_warn(&nn->dp, "failed to add TLS: %d (%d)\n",
36353601c68SJakub Kicinski 			   err, direction == TLS_OFFLOAD_CTX_DIR_TX);
3641f35a56cSDirk van der Merwe 		/* communicate frees skb on error */
3651f35a56cSDirk van der Merwe 		goto err_conn_remove;
3661f35a56cSDirk van der Merwe 	}
3671f35a56cSDirk van der Merwe 
3681f35a56cSDirk van der Merwe 	err = -be32_to_cpu(reply->error);
3691f35a56cSDirk van der Merwe 	if (err) {
37051a5e563SJakub Kicinski 		if (err == -ENOSPC) {
37151a5e563SJakub Kicinski 			if (!atomic_fetch_inc(&nn->ktls_no_space))
37251a5e563SJakub Kicinski 				nn_info(nn, "HW TLS table full\n");
37351a5e563SJakub Kicinski 		} else {
3741f35a56cSDirk van der Merwe 			nn_dp_warn(&nn->dp,
3751f35a56cSDirk van der Merwe 				   "failed to add TLS, FW replied: %d\n", err);
37651a5e563SJakub Kicinski 		}
3771f35a56cSDirk van der Merwe 		goto err_free_skb;
3781f35a56cSDirk van der Merwe 	}
3791f35a56cSDirk van der Merwe 
3801f35a56cSDirk van der Merwe 	if (!reply->handle[0] && !reply->handle[1]) {
3811f35a56cSDirk van der Merwe 		nn_dp_warn(&nn->dp, "FW returned NULL handle\n");
38231d16664SWei Yongjun 		err = -EINVAL;
3831f35a56cSDirk van der Merwe 		goto err_fw_remove;
3841f35a56cSDirk van der Merwe 	}
3851f35a56cSDirk van der Merwe 
3861f35a56cSDirk van der Merwe 	ntls = tls_driver_ctx(sk, direction);
3871f35a56cSDirk van der Merwe 	memcpy(ntls->fw_handle, reply->handle, sizeof(ntls->fw_handle));
388c0a4948eSJakub Kicinski 	if (direction == TLS_OFFLOAD_CTX_DIR_TX)
3891f35a56cSDirk van der Merwe 		ntls->next_seq = start_offload_tcp_sn;
3901f35a56cSDirk van der Merwe 	dev_consume_skb_any(skb);
3911f35a56cSDirk van der Merwe 
392cad228a3SDirk van der Merwe 	if (direction == TLS_OFFLOAD_CTX_DIR_TX)
393cad228a3SDirk van der Merwe 		return 0;
394cad228a3SDirk van der Merwe 
3956a35ddc5SJakub Kicinski 	if (!nn->tlv_caps.tls_resync_ss)
3966a35ddc5SJakub Kicinski 		tls_offload_rx_resync_set_type(sk, TLS_OFFLOAD_SYNC_TYPE_CORE_NEXT_HINT);
3976a35ddc5SJakub Kicinski 
3981f35a56cSDirk van der Merwe 	return 0;
3991f35a56cSDirk van der Merwe 
4001f35a56cSDirk van der Merwe err_fw_remove:
4011f35a56cSDirk van der Merwe 	nfp_net_tls_del_fw(nn, reply->handle);
4021f35a56cSDirk van der Merwe err_free_skb:
4031f35a56cSDirk van der Merwe 	dev_consume_skb_any(skb);
4041f35a56cSDirk van der Merwe err_conn_remove:
4051f35a56cSDirk van der Merwe 	nfp_net_tls_conn_remove(nn, direction);
4061f35a56cSDirk van der Merwe 	return err;
407232eeb1fSJakub Kicinski }
408232eeb1fSJakub Kicinski 
409232eeb1fSJakub Kicinski static void
nfp_net_tls_del(struct net_device * netdev,struct tls_context * tls_ctx,enum tls_offload_ctx_dir direction)410232eeb1fSJakub Kicinski nfp_net_tls_del(struct net_device *netdev, struct tls_context *tls_ctx,
411232eeb1fSJakub Kicinski 		enum tls_offload_ctx_dir direction)
412232eeb1fSJakub Kicinski {
4131f35a56cSDirk van der Merwe 	struct nfp_net *nn = netdev_priv(netdev);
4141f35a56cSDirk van der Merwe 	struct nfp_net_tls_offload_ctx *ntls;
4151f35a56cSDirk van der Merwe 
4161f35a56cSDirk van der Merwe 	nfp_net_tls_conn_remove(nn, direction);
4171f35a56cSDirk van der Merwe 
4181f35a56cSDirk van der Merwe 	ntls = __tls_driver_ctx(tls_ctx, direction);
4191f35a56cSDirk van der Merwe 	nfp_net_tls_del_fw(nn, ntls->fw_handle);
420232eeb1fSJakub Kicinski }
421232eeb1fSJakub Kicinski 
422b5d9a834SDirk van der Merwe static int
nfp_net_tls_resync(struct net_device * netdev,struct sock * sk,u32 seq,u8 * rcd_sn,enum tls_offload_ctx_dir direction)423eeb2efafSJakub Kicinski nfp_net_tls_resync(struct net_device *netdev, struct sock *sk, u32 seq,
424eeb2efafSJakub Kicinski 		   u8 *rcd_sn, enum tls_offload_ctx_dir direction)
425cad228a3SDirk van der Merwe {
426cad228a3SDirk van der Merwe 	struct nfp_net *nn = netdev_priv(netdev);
427cad228a3SDirk van der Merwe 	struct nfp_net_tls_offload_ctx *ntls;
428cad228a3SDirk van der Merwe 	struct nfp_crypto_req_update *req;
4296a35ddc5SJakub Kicinski 	enum nfp_ccm_type type;
430cad228a3SDirk van der Merwe 	struct sk_buff *skb;
4319ed431c1SJakub Kicinski 	gfp_t flags;
432b5d9a834SDirk van der Merwe 	int err;
433cad228a3SDirk van der Merwe 
4349ed431c1SJakub Kicinski 	flags = direction == TLS_OFFLOAD_CTX_DIR_TX ? GFP_KERNEL : GFP_ATOMIC;
4359ed431c1SJakub Kicinski 	skb = nfp_net_tls_alloc_simple(nn, sizeof(*req), flags);
436cad228a3SDirk van der Merwe 	if (!skb)
437b5d9a834SDirk van der Merwe 		return -ENOMEM;
438cad228a3SDirk van der Merwe 
4399ed431c1SJakub Kicinski 	ntls = tls_driver_ctx(sk, direction);
440cad228a3SDirk van der Merwe 	req = (void *)skb->data;
441cad228a3SDirk van der Merwe 	req->ep_id = 0;
4429ed431c1SJakub Kicinski 	req->opcode = nfp_tls_1_2_dir_to_opcode(direction);
443cad228a3SDirk van der Merwe 	memset(req->resv, 0, sizeof(req->resv));
444cad228a3SDirk van der Merwe 	memcpy(req->handle, ntls->fw_handle, sizeof(ntls->fw_handle));
445cad228a3SDirk van der Merwe 	req->tcp_seq = cpu_to_be32(seq);
446cad228a3SDirk van der Merwe 	memcpy(req->rec_no, rcd_sn, sizeof(req->rec_no));
447cad228a3SDirk van der Merwe 
4486a35ddc5SJakub Kicinski 	type = NFP_CCM_TYPE_CRYPTO_UPDATE;
4499ed431c1SJakub Kicinski 	if (direction == TLS_OFFLOAD_CTX_DIR_TX) {
4506a35ddc5SJakub Kicinski 		err = nfp_net_tls_communicate_simple(nn, skb, "sync", type);
451b5d9a834SDirk van der Merwe 		if (err)
452b5d9a834SDirk van der Merwe 			return err;
4539ed431c1SJakub Kicinski 		ntls->next_seq = seq;
4549ed431c1SJakub Kicinski 	} else {
4556a35ddc5SJakub Kicinski 		if (nn->tlv_caps.tls_resync_ss)
4566a35ddc5SJakub Kicinski 			type = NFP_CCM_TYPE_CRYPTO_RESYNC;
4576a35ddc5SJakub Kicinski 		nfp_ccm_mbox_post(nn, skb, type,
458cad228a3SDirk van der Merwe 				  sizeof(struct nfp_crypto_reply_simple));
4596a35ddc5SJakub Kicinski 		atomic_inc(&nn->ktls_rx_resync_sent);
460cad228a3SDirk van der Merwe 	}
461b5d9a834SDirk van der Merwe 
462b5d9a834SDirk van der Merwe 	return 0;
4639ed431c1SJakub Kicinski }
464cad228a3SDirk van der Merwe 
465232eeb1fSJakub Kicinski static const struct tlsdev_ops nfp_net_tls_ops = {
466232eeb1fSJakub Kicinski 	.tls_dev_add = nfp_net_tls_add,
467232eeb1fSJakub Kicinski 	.tls_dev_del = nfp_net_tls_del,
468eeb2efafSJakub Kicinski 	.tls_dev_resync = nfp_net_tls_resync,
469232eeb1fSJakub Kicinski };
470232eeb1fSJakub Kicinski 
nfp_net_tls_rx_resync_req(struct net_device * netdev,struct nfp_net_tls_resync_req * req,void * pkt,unsigned int pkt_len)4716a35ddc5SJakub Kicinski int nfp_net_tls_rx_resync_req(struct net_device *netdev,
4726a35ddc5SJakub Kicinski 			      struct nfp_net_tls_resync_req *req,
4736a35ddc5SJakub Kicinski 			      void *pkt, unsigned int pkt_len)
4746a35ddc5SJakub Kicinski {
4756a35ddc5SJakub Kicinski 	struct nfp_net *nn = netdev_priv(netdev);
4766a35ddc5SJakub Kicinski 	struct nfp_net_tls_offload_ctx *ntls;
477*4461568aSKuniyuki Iwashima 	struct net *net = dev_net(netdev);
4786a35ddc5SJakub Kicinski 	struct ipv6hdr *ipv6h;
4796a35ddc5SJakub Kicinski 	struct tcphdr *th;
4806a35ddc5SJakub Kicinski 	struct iphdr *iph;
4816a35ddc5SJakub Kicinski 	struct sock *sk;
4826a35ddc5SJakub Kicinski 	__be32 tcp_seq;
4836a35ddc5SJakub Kicinski 	int err;
4846a35ddc5SJakub Kicinski 
4856a35ddc5SJakub Kicinski 	iph = pkt + req->l3_offset;
4866a35ddc5SJakub Kicinski 	ipv6h = pkt + req->l3_offset;
4876a35ddc5SJakub Kicinski 	th = pkt + req->l4_offset;
4886a35ddc5SJakub Kicinski 
4896a35ddc5SJakub Kicinski 	if ((u8 *)&th[1] > (u8 *)pkt + pkt_len) {
4906a35ddc5SJakub Kicinski 		netdev_warn_once(netdev, "invalid TLS RX resync request (l3_off: %hhu l4_off: %hhu pkt_len: %u)\n",
4916a35ddc5SJakub Kicinski 				 req->l3_offset, req->l4_offset, pkt_len);
4926a35ddc5SJakub Kicinski 		err = -EINVAL;
4936a35ddc5SJakub Kicinski 		goto err_cnt_ign;
4946a35ddc5SJakub Kicinski 	}
4956a35ddc5SJakub Kicinski 
496c0ead555SJakub Kicinski 	switch (ipv6h->version) {
4976a35ddc5SJakub Kicinski 	case 4:
498*4461568aSKuniyuki Iwashima 		sk = inet_lookup_established(net, net->ipv4.tcp_death_row.hashinfo,
4996a35ddc5SJakub Kicinski 					     iph->saddr, th->source, iph->daddr,
5006a35ddc5SJakub Kicinski 					     th->dest, netdev->ifindex);
5016a35ddc5SJakub Kicinski 		break;
5026a35ddc5SJakub Kicinski #if IS_ENABLED(CONFIG_IPV6)
5036a35ddc5SJakub Kicinski 	case 6:
504*4461568aSKuniyuki Iwashima 		sk = __inet6_lookup_established(net, net->ipv4.tcp_death_row.hashinfo,
5056a35ddc5SJakub Kicinski 						&ipv6h->saddr, th->source,
5066a35ddc5SJakub Kicinski 						&ipv6h->daddr, ntohs(th->dest),
5076a35ddc5SJakub Kicinski 						netdev->ifindex, 0);
5086a35ddc5SJakub Kicinski 		break;
5096a35ddc5SJakub Kicinski #endif
5106a35ddc5SJakub Kicinski 	default:
5116a35ddc5SJakub Kicinski 		netdev_warn_once(netdev, "invalid TLS RX resync request (l3_off: %hhu l4_off: %hhu ipver: %u)\n",
5126a35ddc5SJakub Kicinski 				 req->l3_offset, req->l4_offset, iph->version);
5136a35ddc5SJakub Kicinski 		err = -EINVAL;
5146a35ddc5SJakub Kicinski 		goto err_cnt_ign;
5156a35ddc5SJakub Kicinski 	}
5166a35ddc5SJakub Kicinski 
5176a35ddc5SJakub Kicinski 	err = 0;
5186a35ddc5SJakub Kicinski 	if (!sk)
5196a35ddc5SJakub Kicinski 		goto err_cnt_ign;
5206a35ddc5SJakub Kicinski 	if (!tls_is_sk_rx_device_offloaded(sk) ||
5216a35ddc5SJakub Kicinski 	    sk->sk_shutdown & RCV_SHUTDOWN)
5226a35ddc5SJakub Kicinski 		goto err_put_sock;
5236a35ddc5SJakub Kicinski 
5246a35ddc5SJakub Kicinski 	ntls = tls_driver_ctx(sk, TLS_OFFLOAD_CTX_DIR_RX);
5256a35ddc5SJakub Kicinski 	/* some FW versions can't report the handle and report 0s */
5266a35ddc5SJakub Kicinski 	if (memchr_inv(&req->fw_handle, 0, sizeof(req->fw_handle)) &&
5276a35ddc5SJakub Kicinski 	    memcmp(&req->fw_handle, &ntls->fw_handle, sizeof(ntls->fw_handle)))
5286a35ddc5SJakub Kicinski 		goto err_put_sock;
5296a35ddc5SJakub Kicinski 
5306a35ddc5SJakub Kicinski 	/* copy to ensure alignment */
5316a35ddc5SJakub Kicinski 	memcpy(&tcp_seq, &req->tcp_seq, sizeof(tcp_seq));
5326a35ddc5SJakub Kicinski 	tls_offload_rx_resync_request(sk, tcp_seq);
5336a35ddc5SJakub Kicinski 	atomic_inc(&nn->ktls_rx_resync_req);
5346a35ddc5SJakub Kicinski 
5356a35ddc5SJakub Kicinski 	sock_gen_put(sk);
5366a35ddc5SJakub Kicinski 	return 0;
5376a35ddc5SJakub Kicinski 
5386a35ddc5SJakub Kicinski err_put_sock:
5396a35ddc5SJakub Kicinski 	sock_gen_put(sk);
5406a35ddc5SJakub Kicinski err_cnt_ign:
5416a35ddc5SJakub Kicinski 	atomic_inc(&nn->ktls_rx_resync_ign);
5426a35ddc5SJakub Kicinski 	return err;
5436a35ddc5SJakub Kicinski }
5446a35ddc5SJakub Kicinski 
nfp_net_tls_reset(struct nfp_net * nn)545232eeb1fSJakub Kicinski static int nfp_net_tls_reset(struct nfp_net *nn)
546232eeb1fSJakub Kicinski {
547232eeb1fSJakub Kicinski 	struct nfp_crypto_req_reset *req;
548232eeb1fSJakub Kicinski 	struct sk_buff *skb;
549232eeb1fSJakub Kicinski 
550232eeb1fSJakub Kicinski 	skb = nfp_net_tls_alloc_simple(nn, sizeof(*req), GFP_KERNEL);
551232eeb1fSJakub Kicinski 	if (!skb)
552232eeb1fSJakub Kicinski 		return -ENOMEM;
553232eeb1fSJakub Kicinski 
554232eeb1fSJakub Kicinski 	req = (void *)skb->data;
555232eeb1fSJakub Kicinski 	req->ep_id = 0;
556232eeb1fSJakub Kicinski 
557232eeb1fSJakub Kicinski 	return nfp_net_tls_communicate_simple(nn, skb, "reset",
558232eeb1fSJakub Kicinski 					      NFP_CCM_TYPE_CRYPTO_RESET);
559232eeb1fSJakub Kicinski }
560232eeb1fSJakub Kicinski 
nfp_net_tls_init(struct nfp_net * nn)561232eeb1fSJakub Kicinski int nfp_net_tls_init(struct nfp_net *nn)
562232eeb1fSJakub Kicinski {
563232eeb1fSJakub Kicinski 	struct net_device *netdev = nn->dp.netdev;
564232eeb1fSJakub Kicinski 	int err;
565232eeb1fSJakub Kicinski 
566232eeb1fSJakub Kicinski 	if (!(nn->tlv_caps.crypto_ops & NFP_NET_TLS_OPCODE_MASK))
567232eeb1fSJakub Kicinski 		return 0;
568232eeb1fSJakub Kicinski 
569232eeb1fSJakub Kicinski 	if ((nn->tlv_caps.mbox_cmsg_types & NFP_NET_TLS_CCM_MBOX_OPS_MASK) !=
570232eeb1fSJakub Kicinski 	    NFP_NET_TLS_CCM_MBOX_OPS_MASK)
571232eeb1fSJakub Kicinski 		return 0;
572232eeb1fSJakub Kicinski 
573232eeb1fSJakub Kicinski 	if (!nfp_ccm_mbox_fits(nn, sizeof(struct nfp_crypto_req_add_v6))) {
574232eeb1fSJakub Kicinski 		nn_warn(nn, "disabling TLS offload - mbox too small: %d\n",
575232eeb1fSJakub Kicinski 			nn->tlv_caps.mbox_len);
576232eeb1fSJakub Kicinski 		return 0;
577232eeb1fSJakub Kicinski 	}
578232eeb1fSJakub Kicinski 
579232eeb1fSJakub Kicinski 	err = nfp_net_tls_reset(nn);
580232eeb1fSJakub Kicinski 	if (err)
581232eeb1fSJakub Kicinski 		return err;
582232eeb1fSJakub Kicinski 
583232eeb1fSJakub Kicinski 	nn_ctrl_bar_lock(nn);
584232eeb1fSJakub Kicinski 	nn_writel(nn, nn->tlv_caps.crypto_enable_off, 0);
585232eeb1fSJakub Kicinski 	err = __nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_CRYPTO);
586232eeb1fSJakub Kicinski 	nn_ctrl_bar_unlock(nn);
587232eeb1fSJakub Kicinski 	if (err)
588232eeb1fSJakub Kicinski 		return err;
589232eeb1fSJakub Kicinski 
590c0a4948eSJakub Kicinski 	if (nn->tlv_caps.crypto_ops & NFP_NET_TLS_OPCODE_MASK_RX) {
591c0a4948eSJakub Kicinski 		netdev->hw_features |= NETIF_F_HW_TLS_RX;
592c0a4948eSJakub Kicinski 		netdev->features |= NETIF_F_HW_TLS_RX;
593c0a4948eSJakub Kicinski 	}
5941f35a56cSDirk van der Merwe 	if (nn->tlv_caps.crypto_ops & NFP_NET_TLS_OPCODE_MASK_TX) {
5951f35a56cSDirk van der Merwe 		netdev->hw_features |= NETIF_F_HW_TLS_TX;
5961f35a56cSDirk van der Merwe 		netdev->features |= NETIF_F_HW_TLS_TX;
5971f35a56cSDirk van der Merwe 	}
5981f35a56cSDirk van der Merwe 
599232eeb1fSJakub Kicinski 	netdev->tlsdev_ops = &nfp_net_tls_ops;
600232eeb1fSJakub Kicinski 
601232eeb1fSJakub Kicinski 	return 0;
602232eeb1fSJakub Kicinski }
603