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