162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 262306a36Sopenharmony_ci/* Copyright (C) 2019 Netronome Systems, Inc. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/bitfield.h> 562306a36Sopenharmony_ci#include <linux/ipv6.h> 662306a36Sopenharmony_ci#include <linux/skbuff.h> 762306a36Sopenharmony_ci#include <linux/string.h> 862306a36Sopenharmony_ci#include <net/inet6_hashtables.h> 962306a36Sopenharmony_ci#include <net/tls.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "../ccm.h" 1262306a36Sopenharmony_ci#include "../nfp_net.h" 1362306a36Sopenharmony_ci#include "crypto.h" 1462306a36Sopenharmony_ci#include "fw.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define NFP_NET_TLS_CCM_MBOX_OPS_MASK \ 1762306a36Sopenharmony_ci (BIT(NFP_CCM_TYPE_CRYPTO_RESET) | \ 1862306a36Sopenharmony_ci BIT(NFP_CCM_TYPE_CRYPTO_ADD) | \ 1962306a36Sopenharmony_ci BIT(NFP_CCM_TYPE_CRYPTO_DEL) | \ 2062306a36Sopenharmony_ci BIT(NFP_CCM_TYPE_CRYPTO_UPDATE)) 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define NFP_NET_TLS_OPCODE_MASK_RX \ 2362306a36Sopenharmony_ci BIT(NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_DEC) 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define NFP_NET_TLS_OPCODE_MASK_TX \ 2662306a36Sopenharmony_ci BIT(NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_ENC) 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define NFP_NET_TLS_OPCODE_MASK \ 2962306a36Sopenharmony_ci (NFP_NET_TLS_OPCODE_MASK_RX | NFP_NET_TLS_OPCODE_MASK_TX) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic void nfp_net_crypto_set_op(struct nfp_net *nn, u8 opcode, bool on) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci u32 off, val; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci off = nn->tlv_caps.crypto_enable_off + round_down(opcode / 8, 4); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci val = nn_readl(nn, off); 3862306a36Sopenharmony_ci if (on) 3962306a36Sopenharmony_ci val |= BIT(opcode & 31); 4062306a36Sopenharmony_ci else 4162306a36Sopenharmony_ci val &= ~BIT(opcode & 31); 4262306a36Sopenharmony_ci nn_writel(nn, off, val); 4362306a36Sopenharmony_ci} 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic bool 4662306a36Sopenharmony_ci__nfp_net_tls_conn_cnt_changed(struct nfp_net *nn, int add, 4762306a36Sopenharmony_ci enum tls_offload_ctx_dir direction) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci u8 opcode; 5062306a36Sopenharmony_ci int cnt; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci if (direction == TLS_OFFLOAD_CTX_DIR_TX) { 5362306a36Sopenharmony_ci opcode = NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_ENC; 5462306a36Sopenharmony_ci nn->ktls_tx_conn_cnt += add; 5562306a36Sopenharmony_ci cnt = nn->ktls_tx_conn_cnt; 5662306a36Sopenharmony_ci nn->dp.ktls_tx = !!nn->ktls_tx_conn_cnt; 5762306a36Sopenharmony_ci } else { 5862306a36Sopenharmony_ci opcode = NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_DEC; 5962306a36Sopenharmony_ci nn->ktls_rx_conn_cnt += add; 6062306a36Sopenharmony_ci cnt = nn->ktls_rx_conn_cnt; 6162306a36Sopenharmony_ci } 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci /* Care only about 0 -> 1 and 1 -> 0 transitions */ 6462306a36Sopenharmony_ci if (cnt > 1) 6562306a36Sopenharmony_ci return false; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci nfp_net_crypto_set_op(nn, opcode, cnt); 6862306a36Sopenharmony_ci return true; 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic int 7262306a36Sopenharmony_cinfp_net_tls_conn_cnt_changed(struct nfp_net *nn, int add, 7362306a36Sopenharmony_ci enum tls_offload_ctx_dir direction) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci int ret = 0; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* Use the BAR lock to protect the connection counts */ 7862306a36Sopenharmony_ci nn_ctrl_bar_lock(nn); 7962306a36Sopenharmony_ci if (__nfp_net_tls_conn_cnt_changed(nn, add, direction)) { 8062306a36Sopenharmony_ci ret = __nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_CRYPTO); 8162306a36Sopenharmony_ci /* Undo the cnt adjustment if failed */ 8262306a36Sopenharmony_ci if (ret) 8362306a36Sopenharmony_ci __nfp_net_tls_conn_cnt_changed(nn, -add, direction); 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci nn_ctrl_bar_unlock(nn); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci return ret; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic int 9162306a36Sopenharmony_cinfp_net_tls_conn_add(struct nfp_net *nn, enum tls_offload_ctx_dir direction) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci return nfp_net_tls_conn_cnt_changed(nn, 1, direction); 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic int 9762306a36Sopenharmony_cinfp_net_tls_conn_remove(struct nfp_net *nn, enum tls_offload_ctx_dir direction) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci return nfp_net_tls_conn_cnt_changed(nn, -1, direction); 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic struct sk_buff * 10362306a36Sopenharmony_cinfp_net_tls_alloc_simple(struct nfp_net *nn, size_t req_sz, gfp_t flags) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci return nfp_ccm_mbox_msg_alloc(nn, req_sz, 10662306a36Sopenharmony_ci sizeof(struct nfp_crypto_reply_simple), 10762306a36Sopenharmony_ci flags); 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic int 11162306a36Sopenharmony_cinfp_net_tls_communicate_simple(struct nfp_net *nn, struct sk_buff *skb, 11262306a36Sopenharmony_ci const char *name, enum nfp_ccm_type type) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci struct nfp_crypto_reply_simple *reply; 11562306a36Sopenharmony_ci int err; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci err = __nfp_ccm_mbox_communicate(nn, skb, type, 11862306a36Sopenharmony_ci sizeof(*reply), sizeof(*reply), 11962306a36Sopenharmony_ci type == NFP_CCM_TYPE_CRYPTO_DEL); 12062306a36Sopenharmony_ci if (err) { 12162306a36Sopenharmony_ci nn_dp_warn(&nn->dp, "failed to %s TLS: %d\n", name, err); 12262306a36Sopenharmony_ci return err; 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci reply = (void *)skb->data; 12662306a36Sopenharmony_ci err = -be32_to_cpu(reply->error); 12762306a36Sopenharmony_ci if (err) 12862306a36Sopenharmony_ci nn_dp_warn(&nn->dp, "failed to %s TLS, fw replied: %d\n", 12962306a36Sopenharmony_ci name, err); 13062306a36Sopenharmony_ci dev_consume_skb_any(skb); 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci return err; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic void nfp_net_tls_del_fw(struct nfp_net *nn, __be32 *fw_handle) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci struct nfp_crypto_req_del *req; 13862306a36Sopenharmony_ci struct sk_buff *skb; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci skb = nfp_net_tls_alloc_simple(nn, sizeof(*req), GFP_KERNEL); 14162306a36Sopenharmony_ci if (!skb) 14262306a36Sopenharmony_ci return; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci req = (void *)skb->data; 14562306a36Sopenharmony_ci req->ep_id = 0; 14662306a36Sopenharmony_ci memcpy(req->handle, fw_handle, sizeof(req->handle)); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci nfp_net_tls_communicate_simple(nn, skb, "delete", 14962306a36Sopenharmony_ci NFP_CCM_TYPE_CRYPTO_DEL); 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic void 15362306a36Sopenharmony_cinfp_net_tls_set_ipver_vlan(struct nfp_crypto_req_add_front *front, u8 ipver) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci front->ipver_vlan = cpu_to_be16(FIELD_PREP(NFP_NET_TLS_IPVER, ipver) | 15662306a36Sopenharmony_ci FIELD_PREP(NFP_NET_TLS_VLAN, 15762306a36Sopenharmony_ci NFP_NET_TLS_VLAN_UNUSED)); 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic void 16162306a36Sopenharmony_cinfp_net_tls_assign_conn_id(struct nfp_net *nn, 16262306a36Sopenharmony_ci struct nfp_crypto_req_add_front *front) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci u32 len; 16562306a36Sopenharmony_ci u64 id; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci id = atomic64_inc_return(&nn->ktls_conn_id_gen); 16862306a36Sopenharmony_ci len = front->key_len - NFP_NET_TLS_NON_ADDR_KEY_LEN; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci memcpy(front->l3_addrs, &id, sizeof(id)); 17162306a36Sopenharmony_ci memset(front->l3_addrs + sizeof(id), 0, len - sizeof(id)); 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic struct nfp_crypto_req_add_back * 17562306a36Sopenharmony_cinfp_net_tls_set_ipv4(struct nfp_net *nn, struct nfp_crypto_req_add_v4 *req, 17662306a36Sopenharmony_ci struct sock *sk, int direction) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci struct inet_sock *inet = inet_sk(sk); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci req->front.key_len += sizeof(__be32) * 2; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci if (direction == TLS_OFFLOAD_CTX_DIR_TX) { 18362306a36Sopenharmony_ci nfp_net_tls_assign_conn_id(nn, &req->front); 18462306a36Sopenharmony_ci } else { 18562306a36Sopenharmony_ci req->src_ip = inet->inet_daddr; 18662306a36Sopenharmony_ci req->dst_ip = inet->inet_saddr; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci return &req->back; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic struct nfp_crypto_req_add_back * 19362306a36Sopenharmony_cinfp_net_tls_set_ipv6(struct nfp_net *nn, struct nfp_crypto_req_add_v6 *req, 19462306a36Sopenharmony_ci struct sock *sk, int direction) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 19762306a36Sopenharmony_ci struct ipv6_pinfo *np = inet6_sk(sk); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci req->front.key_len += sizeof(struct in6_addr) * 2; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci if (direction == TLS_OFFLOAD_CTX_DIR_TX) { 20262306a36Sopenharmony_ci nfp_net_tls_assign_conn_id(nn, &req->front); 20362306a36Sopenharmony_ci } else { 20462306a36Sopenharmony_ci memcpy(req->src_ip, &sk->sk_v6_daddr, sizeof(req->src_ip)); 20562306a36Sopenharmony_ci memcpy(req->dst_ip, &np->saddr, sizeof(req->dst_ip)); 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci#endif 20962306a36Sopenharmony_ci return &req->back; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic void 21362306a36Sopenharmony_cinfp_net_tls_set_l4(struct nfp_crypto_req_add_front *front, 21462306a36Sopenharmony_ci struct nfp_crypto_req_add_back *back, struct sock *sk, 21562306a36Sopenharmony_ci int direction) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci struct inet_sock *inet = inet_sk(sk); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci front->l4_proto = IPPROTO_TCP; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci if (direction == TLS_OFFLOAD_CTX_DIR_TX) { 22262306a36Sopenharmony_ci back->src_port = 0; 22362306a36Sopenharmony_ci back->dst_port = 0; 22462306a36Sopenharmony_ci } else { 22562306a36Sopenharmony_ci back->src_port = inet->inet_dport; 22662306a36Sopenharmony_ci back->dst_port = inet->inet_sport; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic u8 nfp_tls_1_2_dir_to_opcode(enum tls_offload_ctx_dir direction) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci switch (direction) { 23362306a36Sopenharmony_ci case TLS_OFFLOAD_CTX_DIR_TX: 23462306a36Sopenharmony_ci return NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_ENC; 23562306a36Sopenharmony_ci case TLS_OFFLOAD_CTX_DIR_RX: 23662306a36Sopenharmony_ci return NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_DEC; 23762306a36Sopenharmony_ci default: 23862306a36Sopenharmony_ci WARN_ON_ONCE(1); 23962306a36Sopenharmony_ci return 0; 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic bool 24462306a36Sopenharmony_cinfp_net_cipher_supported(struct nfp_net *nn, u16 cipher_type, 24562306a36Sopenharmony_ci enum tls_offload_ctx_dir direction) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci u8 bit; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci switch (cipher_type) { 25062306a36Sopenharmony_ci case TLS_CIPHER_AES_GCM_128: 25162306a36Sopenharmony_ci if (direction == TLS_OFFLOAD_CTX_DIR_TX) 25262306a36Sopenharmony_ci bit = NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_ENC; 25362306a36Sopenharmony_ci else 25462306a36Sopenharmony_ci bit = NFP_NET_CRYPTO_OP_TLS_1_2_AES_GCM_128_DEC; 25562306a36Sopenharmony_ci break; 25662306a36Sopenharmony_ci default: 25762306a36Sopenharmony_ci return false; 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci return nn->tlv_caps.crypto_ops & BIT(bit); 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic int 26462306a36Sopenharmony_cinfp_net_tls_add(struct net_device *netdev, struct sock *sk, 26562306a36Sopenharmony_ci enum tls_offload_ctx_dir direction, 26662306a36Sopenharmony_ci struct tls_crypto_info *crypto_info, 26762306a36Sopenharmony_ci u32 start_offload_tcp_sn) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci struct tls12_crypto_info_aes_gcm_128 *tls_ci; 27062306a36Sopenharmony_ci struct nfp_net *nn = netdev_priv(netdev); 27162306a36Sopenharmony_ci struct nfp_crypto_req_add_front *front; 27262306a36Sopenharmony_ci struct nfp_net_tls_offload_ctx *ntls; 27362306a36Sopenharmony_ci struct nfp_crypto_req_add_back *back; 27462306a36Sopenharmony_ci struct nfp_crypto_reply_add *reply; 27562306a36Sopenharmony_ci struct sk_buff *skb; 27662306a36Sopenharmony_ci size_t req_sz; 27762306a36Sopenharmony_ci void *req; 27862306a36Sopenharmony_ci bool ipv6; 27962306a36Sopenharmony_ci int err; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct nfp_net_tls_offload_ctx) > 28262306a36Sopenharmony_ci TLS_DRIVER_STATE_SIZE_TX); 28362306a36Sopenharmony_ci BUILD_BUG_ON(offsetof(struct nfp_net_tls_offload_ctx, rx_end) > 28462306a36Sopenharmony_ci TLS_DRIVER_STATE_SIZE_RX); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci if (!nfp_net_cipher_supported(nn, crypto_info->cipher_type, direction)) 28762306a36Sopenharmony_ci return -EOPNOTSUPP; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci switch (sk->sk_family) { 29062306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 29162306a36Sopenharmony_ci case AF_INET6: 29262306a36Sopenharmony_ci if (ipv6_only_sock(sk) || 29362306a36Sopenharmony_ci ipv6_addr_type(&sk->sk_v6_daddr) != IPV6_ADDR_MAPPED) { 29462306a36Sopenharmony_ci req_sz = sizeof(struct nfp_crypto_req_add_v6); 29562306a36Sopenharmony_ci ipv6 = true; 29662306a36Sopenharmony_ci break; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci fallthrough; 29962306a36Sopenharmony_ci#endif 30062306a36Sopenharmony_ci case AF_INET: 30162306a36Sopenharmony_ci req_sz = sizeof(struct nfp_crypto_req_add_v4); 30262306a36Sopenharmony_ci ipv6 = false; 30362306a36Sopenharmony_ci break; 30462306a36Sopenharmony_ci default: 30562306a36Sopenharmony_ci return -EOPNOTSUPP; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci err = nfp_net_tls_conn_add(nn, direction); 30962306a36Sopenharmony_ci if (err) 31062306a36Sopenharmony_ci return err; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci skb = nfp_ccm_mbox_msg_alloc(nn, req_sz, sizeof(*reply), GFP_KERNEL); 31362306a36Sopenharmony_ci if (!skb) { 31462306a36Sopenharmony_ci err = -ENOMEM; 31562306a36Sopenharmony_ci goto err_conn_remove; 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci front = (void *)skb->data; 31962306a36Sopenharmony_ci front->ep_id = 0; 32062306a36Sopenharmony_ci front->key_len = NFP_NET_TLS_NON_ADDR_KEY_LEN; 32162306a36Sopenharmony_ci front->opcode = nfp_tls_1_2_dir_to_opcode(direction); 32262306a36Sopenharmony_ci memset(front->resv, 0, sizeof(front->resv)); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci nfp_net_tls_set_ipver_vlan(front, ipv6 ? 6 : 4); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci req = (void *)skb->data; 32762306a36Sopenharmony_ci if (ipv6) 32862306a36Sopenharmony_ci back = nfp_net_tls_set_ipv6(nn, req, sk, direction); 32962306a36Sopenharmony_ci else 33062306a36Sopenharmony_ci back = nfp_net_tls_set_ipv4(nn, req, sk, direction); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci nfp_net_tls_set_l4(front, back, sk, direction); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci back->counter = 0; 33562306a36Sopenharmony_ci back->tcp_seq = cpu_to_be32(start_offload_tcp_sn); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci tls_ci = (struct tls12_crypto_info_aes_gcm_128 *)crypto_info; 33862306a36Sopenharmony_ci memcpy(back->key, tls_ci->key, TLS_CIPHER_AES_GCM_128_KEY_SIZE); 33962306a36Sopenharmony_ci memset(&back->key[TLS_CIPHER_AES_GCM_128_KEY_SIZE / 4], 0, 34062306a36Sopenharmony_ci sizeof(back->key) - TLS_CIPHER_AES_GCM_128_KEY_SIZE); 34162306a36Sopenharmony_ci memcpy(back->iv, tls_ci->iv, TLS_CIPHER_AES_GCM_128_IV_SIZE); 34262306a36Sopenharmony_ci memcpy(&back->salt, tls_ci->salt, TLS_CIPHER_AES_GCM_128_SALT_SIZE); 34362306a36Sopenharmony_ci memcpy(back->rec_no, tls_ci->rec_seq, sizeof(tls_ci->rec_seq)); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci /* Get an extra ref on the skb so we can wipe the key after */ 34662306a36Sopenharmony_ci skb_get(skb); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci err = nfp_ccm_mbox_communicate(nn, skb, NFP_CCM_TYPE_CRYPTO_ADD, 34962306a36Sopenharmony_ci sizeof(*reply), sizeof(*reply)); 35062306a36Sopenharmony_ci reply = (void *)skb->data; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci /* We depend on CCM MBOX code not reallocating skb we sent 35362306a36Sopenharmony_ci * so we can clear the key material out of the memory. 35462306a36Sopenharmony_ci */ 35562306a36Sopenharmony_ci if (!WARN_ON_ONCE((u8 *)back < skb->head || 35662306a36Sopenharmony_ci (u8 *)back > skb_end_pointer(skb)) && 35762306a36Sopenharmony_ci !WARN_ON_ONCE((u8 *)&reply[1] > (u8 *)back)) 35862306a36Sopenharmony_ci memzero_explicit(back, sizeof(*back)); 35962306a36Sopenharmony_ci dev_consume_skb_any(skb); /* the extra ref from skb_get() above */ 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci if (err) { 36262306a36Sopenharmony_ci nn_dp_warn(&nn->dp, "failed to add TLS: %d (%d)\n", 36362306a36Sopenharmony_ci err, direction == TLS_OFFLOAD_CTX_DIR_TX); 36462306a36Sopenharmony_ci /* communicate frees skb on error */ 36562306a36Sopenharmony_ci goto err_conn_remove; 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci err = -be32_to_cpu(reply->error); 36962306a36Sopenharmony_ci if (err) { 37062306a36Sopenharmony_ci if (err == -ENOSPC) { 37162306a36Sopenharmony_ci if (!atomic_fetch_inc(&nn->ktls_no_space)) 37262306a36Sopenharmony_ci nn_info(nn, "HW TLS table full\n"); 37362306a36Sopenharmony_ci } else { 37462306a36Sopenharmony_ci nn_dp_warn(&nn->dp, 37562306a36Sopenharmony_ci "failed to add TLS, FW replied: %d\n", err); 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci goto err_free_skb; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci if (!reply->handle[0] && !reply->handle[1]) { 38162306a36Sopenharmony_ci nn_dp_warn(&nn->dp, "FW returned NULL handle\n"); 38262306a36Sopenharmony_ci err = -EINVAL; 38362306a36Sopenharmony_ci goto err_fw_remove; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci ntls = tls_driver_ctx(sk, direction); 38762306a36Sopenharmony_ci memcpy(ntls->fw_handle, reply->handle, sizeof(ntls->fw_handle)); 38862306a36Sopenharmony_ci if (direction == TLS_OFFLOAD_CTX_DIR_TX) 38962306a36Sopenharmony_ci ntls->next_seq = start_offload_tcp_sn; 39062306a36Sopenharmony_ci dev_consume_skb_any(skb); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (direction == TLS_OFFLOAD_CTX_DIR_TX) 39362306a36Sopenharmony_ci return 0; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (!nn->tlv_caps.tls_resync_ss) 39662306a36Sopenharmony_ci tls_offload_rx_resync_set_type(sk, TLS_OFFLOAD_SYNC_TYPE_CORE_NEXT_HINT); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci return 0; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cierr_fw_remove: 40162306a36Sopenharmony_ci nfp_net_tls_del_fw(nn, reply->handle); 40262306a36Sopenharmony_cierr_free_skb: 40362306a36Sopenharmony_ci dev_consume_skb_any(skb); 40462306a36Sopenharmony_cierr_conn_remove: 40562306a36Sopenharmony_ci nfp_net_tls_conn_remove(nn, direction); 40662306a36Sopenharmony_ci return err; 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic void 41062306a36Sopenharmony_cinfp_net_tls_del(struct net_device *netdev, struct tls_context *tls_ctx, 41162306a36Sopenharmony_ci enum tls_offload_ctx_dir direction) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci struct nfp_net *nn = netdev_priv(netdev); 41462306a36Sopenharmony_ci struct nfp_net_tls_offload_ctx *ntls; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci nfp_net_tls_conn_remove(nn, direction); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci ntls = __tls_driver_ctx(tls_ctx, direction); 41962306a36Sopenharmony_ci nfp_net_tls_del_fw(nn, ntls->fw_handle); 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic int 42362306a36Sopenharmony_cinfp_net_tls_resync(struct net_device *netdev, struct sock *sk, u32 seq, 42462306a36Sopenharmony_ci u8 *rcd_sn, enum tls_offload_ctx_dir direction) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci struct nfp_net *nn = netdev_priv(netdev); 42762306a36Sopenharmony_ci struct nfp_net_tls_offload_ctx *ntls; 42862306a36Sopenharmony_ci struct nfp_crypto_req_update *req; 42962306a36Sopenharmony_ci enum nfp_ccm_type type; 43062306a36Sopenharmony_ci struct sk_buff *skb; 43162306a36Sopenharmony_ci gfp_t flags; 43262306a36Sopenharmony_ci int err; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci flags = direction == TLS_OFFLOAD_CTX_DIR_TX ? GFP_KERNEL : GFP_ATOMIC; 43562306a36Sopenharmony_ci skb = nfp_net_tls_alloc_simple(nn, sizeof(*req), flags); 43662306a36Sopenharmony_ci if (!skb) 43762306a36Sopenharmony_ci return -ENOMEM; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci ntls = tls_driver_ctx(sk, direction); 44062306a36Sopenharmony_ci req = (void *)skb->data; 44162306a36Sopenharmony_ci req->ep_id = 0; 44262306a36Sopenharmony_ci req->opcode = nfp_tls_1_2_dir_to_opcode(direction); 44362306a36Sopenharmony_ci memset(req->resv, 0, sizeof(req->resv)); 44462306a36Sopenharmony_ci memcpy(req->handle, ntls->fw_handle, sizeof(ntls->fw_handle)); 44562306a36Sopenharmony_ci req->tcp_seq = cpu_to_be32(seq); 44662306a36Sopenharmony_ci memcpy(req->rec_no, rcd_sn, sizeof(req->rec_no)); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci type = NFP_CCM_TYPE_CRYPTO_UPDATE; 44962306a36Sopenharmony_ci if (direction == TLS_OFFLOAD_CTX_DIR_TX) { 45062306a36Sopenharmony_ci err = nfp_net_tls_communicate_simple(nn, skb, "sync", type); 45162306a36Sopenharmony_ci if (err) 45262306a36Sopenharmony_ci return err; 45362306a36Sopenharmony_ci ntls->next_seq = seq; 45462306a36Sopenharmony_ci } else { 45562306a36Sopenharmony_ci if (nn->tlv_caps.tls_resync_ss) 45662306a36Sopenharmony_ci type = NFP_CCM_TYPE_CRYPTO_RESYNC; 45762306a36Sopenharmony_ci nfp_ccm_mbox_post(nn, skb, type, 45862306a36Sopenharmony_ci sizeof(struct nfp_crypto_reply_simple)); 45962306a36Sopenharmony_ci atomic_inc(&nn->ktls_rx_resync_sent); 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci return 0; 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic const struct tlsdev_ops nfp_net_tls_ops = { 46662306a36Sopenharmony_ci .tls_dev_add = nfp_net_tls_add, 46762306a36Sopenharmony_ci .tls_dev_del = nfp_net_tls_del, 46862306a36Sopenharmony_ci .tls_dev_resync = nfp_net_tls_resync, 46962306a36Sopenharmony_ci}; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ciint nfp_net_tls_rx_resync_req(struct net_device *netdev, 47262306a36Sopenharmony_ci struct nfp_net_tls_resync_req *req, 47362306a36Sopenharmony_ci void *pkt, unsigned int pkt_len) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci struct nfp_net *nn = netdev_priv(netdev); 47662306a36Sopenharmony_ci struct nfp_net_tls_offload_ctx *ntls; 47762306a36Sopenharmony_ci struct net *net = dev_net(netdev); 47862306a36Sopenharmony_ci struct ipv6hdr *ipv6h; 47962306a36Sopenharmony_ci struct tcphdr *th; 48062306a36Sopenharmony_ci struct iphdr *iph; 48162306a36Sopenharmony_ci struct sock *sk; 48262306a36Sopenharmony_ci __be32 tcp_seq; 48362306a36Sopenharmony_ci int err; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci iph = pkt + req->l3_offset; 48662306a36Sopenharmony_ci ipv6h = pkt + req->l3_offset; 48762306a36Sopenharmony_ci th = pkt + req->l4_offset; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci if ((u8 *)&th[1] > (u8 *)pkt + pkt_len) { 49062306a36Sopenharmony_ci netdev_warn_once(netdev, "invalid TLS RX resync request (l3_off: %hhu l4_off: %hhu pkt_len: %u)\n", 49162306a36Sopenharmony_ci req->l3_offset, req->l4_offset, pkt_len); 49262306a36Sopenharmony_ci err = -EINVAL; 49362306a36Sopenharmony_ci goto err_cnt_ign; 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci switch (ipv6h->version) { 49762306a36Sopenharmony_ci case 4: 49862306a36Sopenharmony_ci sk = inet_lookup_established(net, net->ipv4.tcp_death_row.hashinfo, 49962306a36Sopenharmony_ci iph->saddr, th->source, iph->daddr, 50062306a36Sopenharmony_ci th->dest, netdev->ifindex); 50162306a36Sopenharmony_ci break; 50262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 50362306a36Sopenharmony_ci case 6: 50462306a36Sopenharmony_ci sk = __inet6_lookup_established(net, net->ipv4.tcp_death_row.hashinfo, 50562306a36Sopenharmony_ci &ipv6h->saddr, th->source, 50662306a36Sopenharmony_ci &ipv6h->daddr, ntohs(th->dest), 50762306a36Sopenharmony_ci netdev->ifindex, 0); 50862306a36Sopenharmony_ci break; 50962306a36Sopenharmony_ci#endif 51062306a36Sopenharmony_ci default: 51162306a36Sopenharmony_ci netdev_warn_once(netdev, "invalid TLS RX resync request (l3_off: %hhu l4_off: %hhu ipver: %u)\n", 51262306a36Sopenharmony_ci req->l3_offset, req->l4_offset, iph->version); 51362306a36Sopenharmony_ci err = -EINVAL; 51462306a36Sopenharmony_ci goto err_cnt_ign; 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci err = 0; 51862306a36Sopenharmony_ci if (!sk) 51962306a36Sopenharmony_ci goto err_cnt_ign; 52062306a36Sopenharmony_ci if (!tls_is_sk_rx_device_offloaded(sk) || 52162306a36Sopenharmony_ci sk->sk_shutdown & RCV_SHUTDOWN) 52262306a36Sopenharmony_ci goto err_put_sock; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci ntls = tls_driver_ctx(sk, TLS_OFFLOAD_CTX_DIR_RX); 52562306a36Sopenharmony_ci /* some FW versions can't report the handle and report 0s */ 52662306a36Sopenharmony_ci if (memchr_inv(&req->fw_handle, 0, sizeof(req->fw_handle)) && 52762306a36Sopenharmony_ci memcmp(&req->fw_handle, &ntls->fw_handle, sizeof(ntls->fw_handle))) 52862306a36Sopenharmony_ci goto err_put_sock; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci /* copy to ensure alignment */ 53162306a36Sopenharmony_ci memcpy(&tcp_seq, &req->tcp_seq, sizeof(tcp_seq)); 53262306a36Sopenharmony_ci tls_offload_rx_resync_request(sk, tcp_seq); 53362306a36Sopenharmony_ci atomic_inc(&nn->ktls_rx_resync_req); 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci sock_gen_put(sk); 53662306a36Sopenharmony_ci return 0; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cierr_put_sock: 53962306a36Sopenharmony_ci sock_gen_put(sk); 54062306a36Sopenharmony_cierr_cnt_ign: 54162306a36Sopenharmony_ci atomic_inc(&nn->ktls_rx_resync_ign); 54262306a36Sopenharmony_ci return err; 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_cistatic int nfp_net_tls_reset(struct nfp_net *nn) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci struct nfp_crypto_req_reset *req; 54862306a36Sopenharmony_ci struct sk_buff *skb; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci skb = nfp_net_tls_alloc_simple(nn, sizeof(*req), GFP_KERNEL); 55162306a36Sopenharmony_ci if (!skb) 55262306a36Sopenharmony_ci return -ENOMEM; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci req = (void *)skb->data; 55562306a36Sopenharmony_ci req->ep_id = 0; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci return nfp_net_tls_communicate_simple(nn, skb, "reset", 55862306a36Sopenharmony_ci NFP_CCM_TYPE_CRYPTO_RESET); 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ciint nfp_net_tls_init(struct nfp_net *nn) 56262306a36Sopenharmony_ci{ 56362306a36Sopenharmony_ci struct net_device *netdev = nn->dp.netdev; 56462306a36Sopenharmony_ci int err; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (!(nn->tlv_caps.crypto_ops & NFP_NET_TLS_OPCODE_MASK)) 56762306a36Sopenharmony_ci return 0; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci if ((nn->tlv_caps.mbox_cmsg_types & NFP_NET_TLS_CCM_MBOX_OPS_MASK) != 57062306a36Sopenharmony_ci NFP_NET_TLS_CCM_MBOX_OPS_MASK) 57162306a36Sopenharmony_ci return 0; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (!nfp_ccm_mbox_fits(nn, sizeof(struct nfp_crypto_req_add_v6))) { 57462306a36Sopenharmony_ci nn_warn(nn, "disabling TLS offload - mbox too small: %d\n", 57562306a36Sopenharmony_ci nn->tlv_caps.mbox_len); 57662306a36Sopenharmony_ci return 0; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci err = nfp_net_tls_reset(nn); 58062306a36Sopenharmony_ci if (err) 58162306a36Sopenharmony_ci return err; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci nn_ctrl_bar_lock(nn); 58462306a36Sopenharmony_ci nn_writel(nn, nn->tlv_caps.crypto_enable_off, 0); 58562306a36Sopenharmony_ci err = __nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_CRYPTO); 58662306a36Sopenharmony_ci nn_ctrl_bar_unlock(nn); 58762306a36Sopenharmony_ci if (err) 58862306a36Sopenharmony_ci return err; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci if (nn->tlv_caps.crypto_ops & NFP_NET_TLS_OPCODE_MASK_RX) { 59162306a36Sopenharmony_ci netdev->hw_features |= NETIF_F_HW_TLS_RX; 59262306a36Sopenharmony_ci netdev->features |= NETIF_F_HW_TLS_RX; 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci if (nn->tlv_caps.crypto_ops & NFP_NET_TLS_OPCODE_MASK_TX) { 59562306a36Sopenharmony_ci netdev->hw_features |= NETIF_F_HW_TLS_TX; 59662306a36Sopenharmony_ci netdev->features |= NETIF_F_HW_TLS_TX; 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci netdev->tlsdev_ops = &nfp_net_tls_ops; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci return 0; 60262306a36Sopenharmony_ci} 603