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