// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) #include "funeth.h" #include "funeth_ktls.h" static int fun_admin_ktls_create(struct funeth_priv *fp, unsigned int id) { struct fun_admin_ktls_create_req req = { .common = FUN_ADMIN_REQ_COMMON_INIT2(FUN_ADMIN_OP_KTLS, sizeof(req)), .subop = FUN_ADMIN_SUBOP_CREATE, .id = cpu_to_be32(id), }; return fun_submit_admin_sync_cmd(fp->fdev, &req.common, NULL, 0, 0); } static int fun_ktls_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) { struct funeth_priv *fp = netdev_priv(netdev); struct fun_admin_ktls_modify_req req = { .common = FUN_ADMIN_REQ_COMMON_INIT2(FUN_ADMIN_OP_KTLS, sizeof(req)), .subop = FUN_ADMIN_SUBOP_MODIFY, .id = cpu_to_be32(fp->ktls_id), .tcp_seq = cpu_to_be32(start_offload_tcp_sn), }; struct fun_admin_ktls_modify_rsp rsp; struct fun_ktls_tx_ctx *tx_ctx; int rc; if (direction != TLS_OFFLOAD_CTX_DIR_TX) return -EOPNOTSUPP; if (crypto_info->version == TLS_1_2_VERSION) req.version = FUN_KTLS_TLSV2; else return -EOPNOTSUPP; switch (crypto_info->cipher_type) { case TLS_CIPHER_AES_GCM_128: { struct tls12_crypto_info_aes_gcm_128 *c = (void *)crypto_info; req.cipher = FUN_KTLS_CIPHER_AES_GCM_128; memcpy(req.key, c->key, sizeof(c->key)); memcpy(req.iv, c->iv, sizeof(c->iv)); memcpy(req.salt, c->salt, sizeof(c->salt)); memcpy(req.record_seq, c->rec_seq, sizeof(c->rec_seq)); break; } default: return -EOPNOTSUPP; } rc = fun_submit_admin_sync_cmd(fp->fdev, &req.common, &rsp, sizeof(rsp), 0); memzero_explicit(&req, sizeof(req)); if (rc) return rc; tx_ctx = tls_driver_ctx(sk, direction); tx_ctx->tlsid = rsp.tlsid; tx_ctx->next_seq = start_offload_tcp_sn; atomic64_inc(&fp->tx_tls_add); return 0; } static void fun_ktls_del(struct net_device *netdev, struct tls_context *tls_ctx, enum tls_offload_ctx_dir direction) { struct funeth_priv *fp = netdev_priv(netdev); struct fun_admin_ktls_modify_req req; struct fun_ktls_tx_ctx *tx_ctx; if (direction != TLS_OFFLOAD_CTX_DIR_TX) return; tx_ctx = __tls_driver_ctx(tls_ctx, direction); req.common = FUN_ADMIN_REQ_COMMON_INIT2(FUN_ADMIN_OP_KTLS, offsetof(struct fun_admin_ktls_modify_req, tcp_seq)); req.subop = FUN_ADMIN_SUBOP_MODIFY; req.flags = cpu_to_be16(FUN_KTLS_MODIFY_REMOVE); req.id = cpu_to_be32(fp->ktls_id); req.tlsid = tx_ctx->tlsid; fun_submit_admin_sync_cmd(fp->fdev, &req.common, NULL, 0, 0); atomic64_inc(&fp->tx_tls_del); } static int fun_ktls_resync(struct net_device *netdev, struct sock *sk, u32 seq, u8 *rcd_sn, enum tls_offload_ctx_dir direction) { struct funeth_priv *fp = netdev_priv(netdev); struct fun_admin_ktls_modify_req req; struct fun_ktls_tx_ctx *tx_ctx; int rc; if (direction != TLS_OFFLOAD_CTX_DIR_TX) return -EOPNOTSUPP; tx_ctx = tls_driver_ctx(sk, direction); req.common = FUN_ADMIN_REQ_COMMON_INIT2(FUN_ADMIN_OP_KTLS, offsetof(struct fun_admin_ktls_modify_req, key)); req.subop = FUN_ADMIN_SUBOP_MODIFY; req.flags = 0; req.id = cpu_to_be32(fp->ktls_id); req.tlsid = tx_ctx->tlsid; req.tcp_seq = cpu_to_be32(seq); req.version = 0; req.cipher = 0; memcpy(req.record_seq, rcd_sn, sizeof(req.record_seq)); atomic64_inc(&fp->tx_tls_resync); rc = fun_submit_admin_sync_cmd(fp->fdev, &req.common, NULL, 0, 0); if (!rc) tx_ctx->next_seq = seq; return rc; } static const struct tlsdev_ops fun_ktls_ops = { .tls_dev_add = fun_ktls_add, .tls_dev_del = fun_ktls_del, .tls_dev_resync = fun_ktls_resync, }; int fun_ktls_init(struct net_device *netdev) { struct funeth_priv *fp = netdev_priv(netdev); int rc; rc = fun_admin_ktls_create(fp, netdev->dev_port); if (rc) return rc; fp->ktls_id = netdev->dev_port; netdev->tlsdev_ops = &fun_ktls_ops; netdev->hw_features |= NETIF_F_HW_TLS_TX; netdev->features |= NETIF_F_HW_TLS_TX; return 0; } void fun_ktls_cleanup(struct funeth_priv *fp) { if (fp->ktls_id == FUN_HCI_ID_INVALID) return; fun_res_destroy(fp->fdev, FUN_ADMIN_OP_KTLS, 0, fp->ktls_id); fp->ktls_id = FUN_HCI_ID_INVALID; }