[PATCH] Add macsec_nv driver wrapper
Mahesh Patil
maheshp at nvidia.com
Mon Sep 26 16:37:24 PDT 2022
This is based on driver_wired.c and provides driver interface for the
NVIDIA MACSec Driver.
Change-Id: I7385e78633af94175ed4d097bb22f244d32c31b4
Signed-off-by: Mahesh Patil <maheshp at nvidia.com>
---
src/drivers/driver.h | 5 +
src/drivers/driver_macsec_nv.c | 1422 ++++++++++++++++++++++++++++++++
src/drivers/drivers.c | 4 +
src/drivers/drivers.mak | 8 +
src/drivers/nv_macsec_drv.h | 122 +++
wpa_supplicant/defconfig | 3 +
6 files changed, 1564 insertions(+)
create mode 100644 src/drivers/driver_macsec_nv.c
create mode 100644 src/drivers/nv_macsec_drv.h
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 36ecf72f6..7d4ecc989 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1,6 +1,7 @@
/*
* Driver interface definition
* Copyright (c) 2003-2017, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2021-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -6488,6 +6489,10 @@ extern const struct wpa_driver_ops wpa_driver_macsec_qca_ops;
/* driver_macsec_linux.c */
extern const struct wpa_driver_ops wpa_driver_macsec_linux_ops;
#endif /* CONFIG_DRIVER_MACSEC_LINUX */
+#ifdef CONFIG_DRIVER_NVMACSEC_LINUX
+/* driver_macsec_nv.c */
+extern const struct wpa_driver_ops wpa_driver_macsec_nv_ops;
+#endif /* CONFIG_DRIVER_NVMACSEC_LINUX */
#ifdef CONFIG_DRIVER_ROBOSWITCH
/* driver_roboswitch.c */
extern const struct wpa_driver_ops wpa_driver_roboswitch_ops;
diff --git a/src/drivers/driver_macsec_nv.c b/src/drivers/driver_macsec_nv.c
new file mode 100644
index 000000000..a404bc0d2
--- /dev/null
+++ b/src/drivers/driver_macsec_nv.c
@@ -0,0 +1,1422 @@
+/*
+ * hostapd / Driver interaction with NVIDIA macsec driver
+ *
+ * Copyright (c) 2021-2022, NVIDIA CORPORATION.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netpacket/packet.h>
+#include <net/if_arp.h>
+#include <net/if.h>
+#include <netlink/netlink.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/route/link.h>
+#include <netlink/route/link/macsec.h>
+#include <linux/if_macsec.h>
+#include <inttypes.h>
+#include <pthread.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/eapol_common.h"
+#include "pae/ieee802_1x_kay.h"
+#include "driver.h"
+#include "driver_wired_common.h"
+#include "nv_macsec_drv.h"
+#include <macsec_client.h>
+
+static int nlmsg_callback(struct nl_msg *msg, void *argp);
+
+
+/**
+ * nv_macsec_drv_handle_read - check for any receive msgs
+ *
+ * @sock: socket fd
+ * @eloop: pointer netlink eloop struct
+ * @priv: pointger to nv_macsec_drv_data struct
+ *
+ * Returns: 0 on success, non-zero on failure
+ */
+static void nv_macsec_drv_handle_read(int sock, void *eloop,
+ void *priv)
+{
+ struct nv_macsec_drv_data *drv = priv;
+ struct nv_macsec_genl_ctx *ctx = &drv->ctx;
+ int ret;
+
+ ret = nl_recvmsgs_default(ctx->sk);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "%s: failed to recv: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ }
+}
+
+
+/**
+ * nl_send_msg_recv - send netlink messages and check for any receive msgs
+ *
+ * @sk: pointer netlink socket struct
+ * @msg: nelink message
+ *
+ * Returns: 0 on success, non-zero on failure
+ */
+static int nl_send_msg_recv(struct nl_sock *sk, struct nl_msg *msg)
+{
+ int ret;
+
+ ret = nl_send_auto(sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "%s: failed to send: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ return ret;
+ }
+
+ ret = nl_recvmsgs_default(sk);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "%s: failed to recv: %d (%s)",
+ __func__, ret, nl_geterror(-ret));
+ }
+
+ return ret;
+}
+
+
+/**
+ * msg_prepare - prepare netlink message for sending
+ *
+ * @cmd: Nvidia driver netlink cmd
+ * @drv: Private driver interface data
+ *
+ * Returns: Pointer to prepared netlink message or NULL on failure
+ */
+static struct nl_msg *msg_prepare(enum nv_macsec_nl_commands cmd,
+ const struct nv_macsec_drv_data *drv)
+{
+ struct nl_msg *msg;
+ const struct nv_macsec_genl_ctx *ctx = &drv->ctx;
+
+ msg = nlmsg_alloc();
+ if (!msg) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "failed to alloc message");
+ return NULL;
+ }
+
+ if (!genlmsg_put(msg, 0, 0, ctx->nv_macsec_genl_id, 0, 0, cmd, 0)) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "failed to put header");
+ goto nla_put_failure;
+ }
+
+ NLA_PUT_STRING(msg, NV_MACSEC_ATTR_IFNAME, drv->ifname);
+
+ return msg;
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return NULL;
+}
+
+
+/**
+ * init_genl_ctx - create generic netlink socket and initializes netlink
+ * context
+ *
+ * @drv: Private driver interface data
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+static int init_genl_ctx(struct nv_macsec_drv_data *drv)
+{
+ struct nv_macsec_genl_ctx *ctx = &drv->ctx;
+
+ PRINT_ENTRY();
+ ctx->sk = nl_socket_alloc();
+ if (!ctx->sk) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "failed to alloc genl socket");
+ return -1;
+ }
+
+ if (genl_connect(ctx->sk) < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "connection to genl socket failed");
+ goto out_free;
+ }
+
+ ctx->nv_macsec_genl_id = genl_ctrl_resolve(ctx->sk, drv->ifname);
+ if (ctx->nv_macsec_genl_id < 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "genl resolve failed");
+ goto out_free;
+ }
+
+ memset(&ctx->cb_arg, 0, sizeof(ctx->cb_arg));
+ ctx->cb_arg.drv = drv;
+
+ nl_socket_modify_cb(ctx->sk, NL_CB_VALID, NL_CB_CUSTOM, nlmsg_callback,
+ &ctx->cb_arg);
+
+ PRINT_EXIT();
+ return 0;
+
+out_free:
+ nl_socket_free(ctx->sk);
+ ctx->sk = NULL;
+ PRINT_EXIT();
+ return -1;
+}
+
+
+/**
+ * macsec_drv_wpa_deinit - Deinitializes wpa driver
+ *
+ * @priv: Private driver interface data
+ *
+ * Returns: none
+ */
+static void macsec_drv_wpa_deinit(void *priv)
+{
+ struct nv_macsec_drv_data *drv = priv;
+
+ PRINT_ENTRY();
+ driver_wired_deinit_common(&drv->common);
+ os_free(drv);
+ PRINT_EXIT();
+}
+
+
+/**
+ * macsec_check_macsec - Checks for nvidia macsec drier registered by kernel
+ * or not
+ *
+ * @ifname: Pointer to interface name
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+static int macsec_check_macsec(const char *ifname)
+{
+ struct nl_sock *sk;
+ int err = -1;
+
+ PRINT_ENTRY();
+ sk = nl_socket_alloc();
+ if (!sk) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX "failed to alloc genl socket");
+ return -1;
+ }
+
+ if (genl_connect(sk) < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "connection to genl socket failed");
+ goto out_free;
+ }
+
+ if (genl_ctrl_resolve(sk, ifname) < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "genl resolve failed"
+ " - nv_macsec kernel module not present?");
+ goto out_free;
+ }
+
+ err = 0;
+
+out_free:
+ nl_socket_free(sk);
+ PRINT_EXIT();
+ return err;
+}
+
+
+/**
+ * macsec_drv_wpa_init - Initializes wpa driver
+ *
+ * @ctx: Netlink socket context data
+ * @ifname: Interface name
+ *
+ * Returns: Pointer to private driver interface data or NULL
+ */
+static void *macsec_drv_wpa_init(void *ctx, const char *ifname)
+{
+ struct nv_macsec_drv_data *drv = NULL;
+
+ PRINT_ENTRY();
+ if (macsec_check_macsec(ifname) < 0)
+ goto exit;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (!drv) {
+ drv = NULL;
+ goto exit;
+ }
+
+ if (driver_wired_init_common(&drv->common, ifname, ctx) < 0) {
+ os_free(drv);
+ drv = NULL;
+ goto exit;
+ }
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+
+exit:
+ PRINT_EXIT();
+ return drv;
+}
+
+
+/**
+ * nv_macsec_drv_macsec_init - Initializes macsec driver
+ *
+ * @priv: private driver interface data
+ * @params: Initialization parameters
+ *
+ * Returns: 0 on success, non-zero on failure
+ */
+static int nv_macsec_drv_macsec_init(void *priv,
+ struct macsec_init_params *params)
+{
+ struct nv_macsec_drv_data *drv = priv;
+ struct nv_macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ int ret = 0;
+
+ PRINT_ENTRY();
+ ret = init_genl_ctx(drv);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "Failed to initialize genl\n");
+ return ret;
+ }
+
+ ret = eloop_register_read_sock(nl_socket_get_fd(ctx->sk),
+ nv_macsec_drv_handle_read,
+ NULL, drv);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "Could not register read socket");
+ return ret;
+ }
+
+ msg = msg_prepare(NV_MACSEC_CMD_INIT, drv);
+ if (!msg)
+ return -1;
+
+ ret = nl_send_msg_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "failed to communicate: %d (%s)",
+ ret, nl_geterror(-ret));
+ }
+
+ nlmsg_free(msg);
+
+ PRINT_EXIT();
+ return ret;
+}
+
+
+/**
+ * nv_macsec_drv_macsec_deinit - Deinitializes macsec driver
+ *
+ * @priv: private driver interface data
+ *
+ * Returns: 0 on success, non-zero on failure
+ */
+static int nv_macsec_drv_macsec_deinit(void *priv)
+{
+ struct nv_macsec_drv_data *drv = priv;
+ struct nv_macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ int ret;
+
+ PRINT_ENTRY();
+ msg = msg_prepare(NV_MACSEC_CMD_DEINIT, drv);
+ if (!msg)
+ return -1;
+
+ ret = nl_send_msg_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "failed to communicate: %d (%s)",
+ ret, nl_geterror(-ret));
+ }
+ eloop_unregister_read_sock(nl_socket_get_fd(ctx->sk));
+
+ if (drv->ctx.sk)
+ nl_socket_free(drv->ctx.sk);
+
+ nlmsg_free(msg);
+
+ PRINT_EXIT();
+ return ret;
+}
+
+
+/**
+ * nv_macsec_drv_get_capability - Gets the capability of macsec driver
+ *
+ * @priv: private driver interface data
+ * @cap: supported macsec capability
+ *
+ * Returns: 0 on success
+ */
+static int nv_macsec_drv_get_capability(void *priv, enum macsec_cap *cap)
+{
+ PRINT_ENTRY();
+
+ *cap = MACSEC_CAP_INTEGRITY;
+
+ PRINT_EXIT();
+ return 0;
+}
+
+
+/**
+ * nv_macsec_drv_enable_protect_frames - Set protect frames status
+ *
+ * @priv: Private driver interface data
+ * @enabled: TRUE = protect frames enabled
+ * FALSE = protect frames disabled
+ *
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int nv_macsec_drv_enable_protect_frames(void *priv, bool enabled)
+{
+ struct nv_macsec_drv_data *drv = priv;
+ struct nv_macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ int ret = 0;
+
+ PRINT_ENTRY();
+ wpa_printf(MSG_DEBUG, "%s -> %s", __func__, enabled ? "TRUE" : "FALSE");
+
+ msg = msg_prepare(NV_MACSEC_CMD_SET_PROT_FRAMES, drv);
+ if (!msg)
+ return -1;
+
+ NLA_PUT_U32(msg, NV_MACSEC_ATTR_PROT_FRAMES_EN, enabled ? 1 : 0);
+
+ ret = nl_send_msg_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "failed to communicate: %d (%s)",
+ ret, nl_geterror(-ret));
+ ret = -1;
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+
+ PRINT_EXIT();
+ return ret;
+}
+
+
+/**
+ * nv_macsec_drv_set_replay_protect - Set replay protect status and window size
+ *
+ * @priv: Private driver interface data
+ * @enabled: TRUE = replay protect enabled
+ * FALSE = replay protect disabled
+ * @window: replay window size, valid only when replay protect enabled
+ *
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int nv_macsec_drv_set_replay_protect(void *priv,
+ bool enabled, u32 window)
+{
+ struct nv_macsec_drv_data *drv = priv;
+ struct nv_macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ int ret = 0;
+
+ PRINT_ENTRY();
+ wpa_printf(MSG_DEBUG, "%s -> %s, %u", __func__,
+ enabled ? "TRUE" : "FALSE", window);
+
+ msg = msg_prepare(NV_MACSEC_CMD_SET_REPLAY_PROT, drv);
+ if (!msg)
+ return -1;
+
+ NLA_PUT_U32(msg, NV_MACSEC_ATTR_REPLAY_PROT_EN, enabled ? 1 : 0);
+ NLA_PUT_U32(msg, NV_MACSEC_ATTR_REPLAY_WINDOW, window);
+
+ ret = nl_send_msg_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "failed to communicate: %d (%s)",
+ ret, nl_geterror(-ret));
+ ret = -1;
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+
+ PRINT_EXIT();
+ return ret;
+}
+
+
+/**
+ * nv_macsec_drv_set_current_cipher_suite - Set current cipher suite
+ &
+ * @priv: Private driver interface data
+ * @cs: EUI64 identifier
+ *
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int nv_macsec_drv_set_current_cipher_suite(void *priv, u64 cs)
+{
+ struct nv_macsec_drv_data *drv = priv;
+ struct nv_macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ int ret = 0;
+
+ PRINT_ENTRY();
+ if (cs != CS_ID_GCM_AES_128 && cs != CS_ID_GCM_AES_256) {
+ wpa_printf(MSG_ERROR,
+ "%s: NOT supported CipherSuite: %016" PRIx64,
+ __func__, cs);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s -> %016" PRIx64, __func__, cs);
+ msg = msg_prepare(NV_MACSEC_CMD_SET_CIPHER, drv);
+ if (!msg)
+ return -1;
+
+ NLA_PUT_U32(msg, NV_MACSEC_ATTR_CIPHER_SUITE,
+ cs == CS_ID_GCM_AES_128 ? 0 : 1);
+
+ ret = nl_send_msg_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "failed to communicate: %d (%s)",
+ ret, nl_geterror(-ret));
+ ret = -1;
+ }
+ drv->cipher = (cs == CS_ID_GCM_AES_128 ? 0 : 1);
+
+nla_put_failure:
+ nlmsg_free(msg);
+ PRINT_EXIT();
+ return ret;
+}
+
+
+/**
+ * nv_macsec_drv_enable_controlled_port - Set controlled port status
+ *
+ * @priv: Private driver interface data
+ * @enabled: TRUE = controlled port enabled
+ * FALSE = controlled port disabled
+ *
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int nv_macsec_drv_enable_controlled_port(void *priv, bool enabled)
+{
+ struct nv_macsec_drv_data *drv = priv;
+ struct nv_macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ int ret = 0;
+
+ PRINT_ENTRY();
+ wpa_printf(MSG_DEBUG, "%s -> %s", __func__, enabled ? "TRUE" : "FALSE");
+
+ msg = msg_prepare(NV_MACSEC_CMD_SET_CONTROLLED_PORT, drv);
+ if (!msg)
+ return -1;
+
+ NLA_PUT_U32(msg, NV_MACSEC_ATTR_CTRL_PORT_EN, enabled ? 1 : 0);
+
+ ret = nl_send_msg_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "failed to communicate: %d (%s)",
+ ret, nl_geterror(-ret));
+ ret = -1;
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+ PRINT_EXIT();
+ return ret;
+}
+
+static const struct nla_policy
+ nv_macsec_sa_genl_policy[NUM_NV_MACSEC_SA_ATTR] = {
+ [NV_MACSEC_SA_ATTR_SCI] = { .type = NLA_BINARY },
+ [NV_MACSEC_SA_ATTR_AN] = { .type = NLA_U8 },
+ [NV_MACSEC_SA_ATTR_PN] = { .type = NLA_U32 },
+ [NV_MACSEC_SA_ATTR_KEY] = { .type = NLA_BINARY },
+ };
+
+static struct nla_policy nv_macsec_genl_policy[NUM_NV_MACSEC_ATTR] = {
+ [NV_MACSEC_ATTR_IFNAME] = { .type = NLA_STRING },
+ [NV_MACSEC_ATTR_TXSC_PORT] = { .type = NLA_U16 },
+ [NV_MACSEC_ATTR_REPLAY_PROT_EN] = { .type = NLA_U32 },
+ [NV_MACSEC_ATTR_REPLAY_WINDOW] = { .type = NLA_U32 },
+ [NV_MACSEC_ATTR_SA_CONFIG] = { .type = NLA_NESTED },
+ [NV_MACSEC_ATTR_TZ_CONFIG] = { .type = NLA_NESTED },
+};
+
+static struct nla_policy nv_macsec_tz_genl_policy[NUM_NV_MACSEC_TZ_ATTR] = {
+ [NV_MACSEC_TZ_INSTANCE_ID] = { .type = NLA_U32 },
+ [NV_MACSEC_TZ_ATTR_CTRL] = { .type = NLA_U8 }, /* controller Tx or Rx */
+ [NV_MACSEC_TZ_ATTR_RW] = { .type = NLA_U8 },
+ [NV_MACSEC_TZ_ATTR_INDEX] = { .type = NLA_U8 },
+ [NV_MACSEC_TZ_ATTR_KEY] = { .type = NLA_BINARY },
+ [NV_MACSEC_TZ_ATTR_FLAG] = { .type = NLA_U32 },
+};
+
+static struct nla_policy
+ nv_macsec_tz_kt_reset_genl_policy[NUM_NV_MACSEC_TZ_KT_RESET_ATTR] = {
+ [NV_MACSEC_TZ_KT_RESET_INSTANCE_ID] = { .type = NLA_U32 },
+};
+
+
+/**
+ * set_next_pn_for_sci_an - Store Next PN in private Int Data for a given SCI/AN
+ *
+ * @priv: Private driver interface data
+ * @sci: Secure Channel Identifier
+ * @an: Association Number
+ * @next_pn: Next PN used by driver for a given SCI/AN
+ *
+ * Returns: Void
+ */
+static void set_next_pn_for_sci_an(void *priv, struct ieee802_1x_mka_sci *sci,
+ u8 an, int next_pn)
+{
+ struct nv_macsec_drv_data *drv = priv;
+ static int idx;
+
+ /* Once Next PN is received from driver, storing the set of sci,
+ * AN and next PN to drv structure
+ */
+ memcpy(&drv->sci_pn_info[idx].sci, sci, sizeof(*sci));
+ drv->sci_pn_info[idx].an = an;
+ drv->sci_pn_info[idx].next_pn = next_pn;
+
+ if (idx == 0)
+ idx = 1;
+ else
+ idx = 0;
+}
+
+
+static int nlmsg_callback(struct nl_msg *msg, void *argp)
+{
+ struct nlmsghdr *ret_hdr = nlmsg_hdr(msg);
+ struct nlattr *tb_msg[NV_MACSEC_ATTR_MAX + 1];
+ struct nlattr *tz_attr[NV_MACSEC_TZ_ATTR_MAX + 1];
+ struct nlattr *pn_attr[NV_MACSEC_SA_ATTR_MAX + 1];
+ struct cb_arg *arg = (struct cb_arg *) argp;
+ struct genlmsghdr *gnlh = (struct genlmsghdr *) nlmsg_data(ret_hdr);
+ MacsecKTConfig ktConfig = {0};
+ unsigned int macsec_ret;
+ int err;
+ unsigned int instance_id;
+ unsigned int pn_received;
+ struct ieee802_1x_mka_sci *sci;
+ int an;
+
+ PRINT_ENTRY();
+
+#ifdef MACSEC_DRV_KEY_PROGRAM
+ goto ret;
+#endif
+ if (ret_hdr->nlmsg_type != arg->drv->ctx.nv_macsec_genl_id) {
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: nv_macsec_genl_id %d",
+ __func__, arg->drv->ctx.nv_macsec_genl_id);
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s(): Got a valid reply: cmd: %d",
+ __func__, gnlh->cmd);
+ if (gnlh->cmd == NV_MACSEC_CMD_TZ_KT_RESET) {
+ err = nla_parse(tb_msg, NV_MACSEC_ATTR_MAX,
+ genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), nv_macsec_genl_policy);
+ if (err < 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX
+ "failed to parse attr: %d (%s)",
+ err, nl_geterror(-err));
+ goto ret;
+ }
+
+ if (!tb_msg[NV_MACSEC_ATTR_TZ_KT_RESET]) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX
+ "no attr NV_MACSEC_ATTR_TZ_KT_RESET");
+ goto ret;
+ }
+
+ err = nla_parse_nested(tz_attr, NV_MACSEC_TZ_KT_RESET_ATTR_MAX,
+ tb_msg[NV_MACSEC_ATTR_TZ_KT_RESET],
+ nv_macsec_tz_kt_reset_genl_policy);
+ if (err < 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX
+ "failed to parse nested attr: %d (%s)",
+ err, nl_geterror(-err));
+ goto ret;
+ }
+ if (!tz_attr[NV_MACSEC_TZ_KT_RESET_INSTANCE_ID]) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX
+ "no NV_MACSEC_TZ_KT_RESET_INSTANCE_ID");
+ goto ret;
+ }
+
+ instance_id = nla_get_u32(tz_attr[NV_MACSEC_TZ_INSTANCE_ID]);
+ macsec_ret = MacsecKTReset(instance_id);
+ if (macsec_ret != MACSEC_SUCCESS) {
+ wpa_printf(MSG_ERROR, "%s(): MacsecKTReset failed %u",
+ __func__, macsec_ret);
+ }
+ } else if (gnlh->cmd == NV_MACSEC_CMD_TZ_CONFIG) {
+ err = nla_parse(tb_msg, NV_MACSEC_ATTR_MAX,
+ genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), nv_macsec_genl_policy);
+ if (err < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "failed to parse attr: %d (%s)",
+ err, nl_geterror(-err));
+ goto ret;
+ }
+
+ if (!tb_msg[NV_MACSEC_ATTR_TZ_CONFIG]) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX
+ "no attr NV_MACSEC_ATTR_TZ_CONFIG");
+ goto ret;
+ }
+
+ err = nla_parse_nested(tz_attr, NV_MACSEC_TZ_ATTR_MAX,
+ tb_msg[NV_MACSEC_ATTR_TZ_CONFIG],
+ nv_macsec_tz_genl_policy);
+ if (err < 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX
+ "failed to parse nested attr: %d (%s)",
+ err, nl_geterror(-err));
+ goto ret;
+ }
+
+ if (!tz_attr[NV_MACSEC_TZ_INSTANCE_ID]) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "no attr NV_MACSEC_TZ_INSTANCE_ID");
+ goto ret;
+ }
+ if (!tz_attr[NV_MACSEC_TZ_ATTR_CTRL]) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "no attr NV_MACSEC_TZ_ATTR_CTRL");
+ goto ret;
+ }
+ if (!tz_attr[NV_MACSEC_TZ_ATTR_RW]) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "no attr NV_MACSEC_TZ_ATTR_RW");
+ goto ret;
+ }
+ if (!tz_attr[NV_MACSEC_TZ_ATTR_INDEX]) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "no attr NV_MACSEC_TZ_ATTR_INDEX");
+ goto ret;
+ }
+
+ if (!tz_attr[NV_MACSEC_TZ_ATTR_KEY]) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "no attr NV_MACSEC_TZ_ATTR_KEY");
+ goto ret;
+ }
+
+ if (!tz_attr[NV_MACSEC_TZ_ATTR_FLAG]) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "no attr NV_MACSEC_TZ_ATTR_FLAG");
+ goto ret;
+ }
+ instance_id = nla_get_u32(tz_attr[NV_MACSEC_TZ_INSTANCE_ID]);
+ ktConfig.ctlrSel = nla_get_u8(tz_attr[NV_MACSEC_TZ_ATTR_CTRL]);
+ ktConfig.rw = nla_get_u8(tz_attr[NV_MACSEC_TZ_ATTR_RW]);
+ ktConfig.index = nla_get_u8(tz_attr[NV_MACSEC_TZ_ATTR_INDEX]);
+ ktConfig.key.flags = nla_get_u32(tz_attr[NV_MACSEC_TZ_ATTR_FLAG]);
+ ktConfig.key.cipher = arg->drv->cipher;
+ memcpy(ktConfig.key.sak, nla_data(tz_attr[NV_MACSEC_TZ_ATTR_KEY]),
+ KEY_LEN_256_BIT);
+ macsec_ret = MacsecKeyConfig(instance_id, &ktConfig);
+ if (macsec_ret != MACSEC_SUCCESS) {
+ wpa_printf(MSG_ERROR, "%s(): MacsecKTReset failed %u",
+ __func__, macsec_ret);
+ goto ret;
+ }
+ } else if (gnlh->cmd == NV_MACSEC_CMD_GET_TX_NEXT_PN) {
+ err = nla_parse(tb_msg, NV_MACSEC_ATTR_MAX,
+ genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), nv_macsec_genl_policy);
+ if (err < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "failed to parse attr: %d (%s)",
+ err, nl_geterror(-err));
+ goto ret;
+ }
+
+ if (!tb_msg[NV_MACSEC_ATTR_SA_CONFIG]) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "no attr NV_MACSEC_ATTR_SA_CONFIG");
+ goto ret;
+ }
+
+ err = nla_parse_nested(pn_attr, NV_MACSEC_SA_ATTR_MAX,
+ tb_msg[NV_MACSEC_ATTR_SA_CONFIG],
+ nv_macsec_sa_genl_policy);
+ if (err < 0) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX
+ "failed to parse nested attr: %d (%s)",
+ err, nl_geterror(-err));
+ goto ret;
+ }
+ if (!pn_attr[NV_MACSEC_SA_ATTR_PN]) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX
+ "no attr NV_MACSEC_SA_ATTR_PN");
+ goto ret;
+ }
+ if (!pn_attr[NV_MACSEC_SA_ATTR_SCI]) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX
+ "no attr NV_MACSEC_SA_ATTR_SCI");
+ goto ret;
+ }
+ if (!pn_attr[NV_MACSEC_SA_ATTR_AN]) {
+ wpa_printf(MSG_ERROR, DRV_PREFIX
+ "no attr NV_MACSEC_SA_ATTR_AN");
+ goto ret;
+ }
+ pn_received = nla_get_u32(pn_attr[NV_MACSEC_SA_ATTR_PN]);
+ sci = nla_data(pn_attr[NV_MACSEC_SA_ATTR_SCI]);
+ an = nla_get_u8(pn_attr[NV_MACSEC_SA_ATTR_AN]);
+ set_next_pn_for_sci_an(arg->drv, sci, an, pn_received);
+
+ }
+ret:
+ PRINT_EXIT();
+ return 0;
+}
+
+
+/**
+ * nv_macsec_drv_get_receive_lowest_pn - Get receive lowest PN
+ *
+ * @priv: Private driver interface data
+ * @sa: secure association
+ *
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int nv_macsec_drv_get_receive_lowest_pn(void *priv,
+ struct receive_sa *sa)
+{
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: Not supported", __func__);
+
+ return -1;
+}
+
+
+/**
+ * nv_macsec_drv_set_receive_lowest_pn - Set receive lowest PN
+ *
+ * @priv: Private driver interface data
+ * @sa: secure association
+ *
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int nv_macsec_drv_set_receive_lowest_pn(void *priv,
+ struct receive_sa *sa)
+{
+ wpa_printf(MSG_DEBUG, DRV_PREFIX "%s: Not supported", __func__);
+
+ return -1;
+}
+
+
+/**
+ * get_next_pn_for_sci_an - Get next PN used for a given SCI and AN
+ *
+ * @priv: Private driver interface data
+ * @sci: Secure CHannel Identifier
+ * @an: Association Number
+ *
+ * Returns: Next PN used by driver if found else will return 1
+ */
+static int get_next_pn_for_sci_an(void *priv, struct ieee802_1x_mka_sci *sci,
+ u8 an)
+{
+ struct nv_macsec_drv_data *drv = priv;
+ int i = 0;
+
+ for (i = 0; i < SCI_PN_INFO_SIZE; i++) {
+ if ((mka_sci_u64(&drv->sci_pn_info[i].sci) ==
+ mka_sci_u64(sci)) &&
+ (drv->sci_pn_info[i].an == an))
+ return drv->sci_pn_info[i].next_pn;
+ }
+ wpa_printf(MSG_DEBUG, DRV_PREFIX
+ "No match for sci_pn_info is found to get PN");
+ return 1;
+}
+
+
+/**
+ * nv_macsec_drv_get_transmit_next_pn - Get transmit next PN
+ *
+ * @priv: Private driver interface data
+ * @sa: secure association
+ *
+ * Returns: Returns next PN used if not returns 1
+ */
+static int nv_macsec_drv_get_transmit_next_pn(void *priv,
+ struct transmit_sa *sa)
+{
+ struct nv_macsec_drv_data *drv = priv;
+ struct nv_macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ struct nlattr *nest;
+ u64 sci;
+ int ret = -1;
+
+ PRINT_ENTRY();
+
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+ sci = mka_sci_u64(&sa->sc->sci);
+ msg = msg_prepare(NV_MACSEC_CMD_GET_TX_NEXT_PN, drv);
+ if (!msg)
+ return -1;
+ nest = nla_nest_start(msg, NV_MACSEC_ATTR_SA_CONFIG);
+ if (!nest)
+ goto nla_put_failure;
+ NLA_PUT(msg, NV_MACSEC_SA_ATTR_SCI, sizeof(sci), &sa->sc->sci);
+ NLA_PUT_U8(msg, NV_MACSEC_SA_ATTR_AN, sa->an);
+ NLA_PUT_U32(msg, NV_MACSEC_SA_ATTR_PN, sa->next_pn);
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_msg_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "failed to communicate: %d (%s)",
+ ret, nl_geterror(-ret));
+ }
+
+ sa->next_pn = get_next_pn_for_sci_an(drv, &sa->sc->sci, sa->an);
+nla_put_failure:
+ nlmsg_free(msg);
+
+ PRINT_EXIT();
+ return sa->next_pn;
+}
+
+
+/**
+ * nv_macsec_drv_set_transmit_next_pn - Set transmit next pn
+ *
+ * @priv: Private driver interface data
+ * @sa: secure association
+ *
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int nv_macsec_drv_set_transmit_next_pn(void *priv,
+ struct transmit_sa *sa)
+{
+ wpa_printf(MSG_DEBUG, "%s: Not supported", __func__);
+
+ return -1;
+}
+
+
+/**
+ * nv_macsec_drv_create_receive_sc - Create secure channel for receiving
+ *
+ * @priv: Private driver interface data
+ * @sc: secure channel
+ * @sci_addr: secure channel identifier - address
+ * @sci_port: secure channel identifier - port
+ * @conf_offset: confidentiality offset (0, 30, or 50)
+ * @validation: frame validation policy (0 = Disabled, 1 = Checked,
+ * 2 = Strict)
+ *
+ * Returns: 0 on success, -1 on failure (or if not supported)
+ */
+static int nv_macsec_drv_create_receive_sc(void *priv, struct receive_sc *sc,
+ unsigned int conf_offset,
+ int validation)
+{
+ wpa_printf(MSG_ERROR, DRV_PREFIX
+ "create_receive_sc - handled in enable_receive_sa");
+ return 0;
+}
+
+
+/**
+ * nv_macsec_drv_delete_receive_sc - Delete secure connection for receiving
+ *
+ * @priv: private driver interface data from init()
+ * @sc: secure channel
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+static int nv_macsec_drv_delete_receive_sc(void *priv, struct receive_sc *sc)
+{
+ wpa_printf(MSG_ERROR, DRV_PREFIX
+ "delete_receive_sc - handled in disable_receive_sa");
+ return 0;
+}
+
+
+/**
+ * nv_macsec_drv_create_receive_sa - Create secure association for receive
+ *
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+static int nv_macsec_drv_create_receive_sa(void *priv, struct receive_sa *sa)
+{
+ struct nv_macsec_drv_data *drv = priv;
+ struct nv_macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ struct nlattr *nest;
+ u64 sci;
+ int ret = -1;
+
+ PRINT_ENTRY();
+
+ wpa_printf(MSG_DEBUG, DRV_PREFIX
+ "create_receive_sa for " SCISTR
+ "\tAN: %hu\n"
+ "\tnext_pn: %u\n"
+ "\tlowest_pn: %u\n"
+ "\tkey_len: %d\n",
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port),
+ sa->an, sa->next_pn, sa->lowest_pn, sa->pkey->key_len);
+ wpa_hexdump(MSG_DEBUG, DRV_PREFIX "SA key", sa->pkey->key,
+ sa->pkey->key_len);
+
+ sci = mka_sci_u64(&sa->sc->sci);
+
+ msg = msg_prepare(NV_MACSEC_CMD_CREATE_RX_SA, drv);
+ if (!msg)
+ return -1;
+
+ nest = nla_nest_start(msg, NV_MACSEC_ATTR_SA_CONFIG);
+ if (!nest)
+ goto nla_put_failure;
+
+ NLA_PUT(msg, NV_MACSEC_SA_ATTR_SCI, sizeof(sci), &sa->sc->sci);
+ NLA_PUT_U8(msg, NV_MACSEC_SA_ATTR_AN, sa->an);
+ NLA_PUT_U32(msg, NV_MACSEC_SA_ATTR_PN, sa->next_pn);
+ NLA_PUT(msg, NV_MACSEC_SA_ATTR_KEY, sa->pkey->key_len, sa->pkey->key);
+
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_msg_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "failed to communicate: %d (%s)",
+ ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+
+ PRINT_EXIT();
+ return ret;
+}
+
+
+/**
+ * nv_macsec_drv_delete_receive_sa - Delete secure association for receive
+ *
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+static int nv_macsec_drv_delete_receive_sa(void *priv, struct receive_sa *sa)
+{
+ wpa_printf(MSG_INFO, DRV_PREFIX
+ "delete_receive_sa - handled in disable_receive_sa");
+ return 0;
+}
+
+
+/**
+ * nv_macsec_drv_enable_receive_sa - Enable the SA for receive
+ *
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+static int nv_macsec_drv_enable_receive_sa(void *priv, struct receive_sa *sa)
+{
+ struct nv_macsec_drv_data *drv = priv;
+ struct nv_macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ struct nlattr *nest;
+ u64 sci;
+ int ret = -1;
+
+ PRINT_ENTRY();
+
+ sci = mka_sci_u64(&sa->sc->sci);
+
+ msg = msg_prepare(NV_MACSEC_CMD_EN_RX_SA, drv);
+ if (!msg)
+ return -1;
+
+ nest = nla_nest_start(msg, NV_MACSEC_ATTR_SA_CONFIG);
+ if (!nest)
+ goto nla_put_failure;
+
+ NLA_PUT(msg, NV_MACSEC_SA_ATTR_SCI, sizeof(sci), &sa->sc->sci);
+ NLA_PUT_U8(msg, NV_MACSEC_SA_ATTR_AN, sa->an);
+ NLA_PUT_U32(msg, NV_MACSEC_SA_ATTR_PN, sa->next_pn);
+ NLA_PUT_U32(msg, NV_MACSEC_SA_ATTR_LOWEST_PN, sa->lowest_pn);
+ NLA_PUT(msg, NV_MACSEC_SA_ATTR_KEY, sa->pkey->key_len, sa->pkey->key);
+
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_msg_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "failed to communicate: %d (%s)",
+ ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+
+ PRINT_EXIT();
+ return ret;
+}
+
+
+/**
+ * nv_macsec_drv_disable_receive_sa - Disable SA for receive
+ *
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+static int nv_macsec_drv_disable_receive_sa(void *priv, struct receive_sa *sa)
+{
+ struct nv_macsec_drv_data *drv = priv;
+ struct nv_macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ struct nlattr *nest;
+ u64 sci;
+ int ret = -1;
+
+ PRINT_ENTRY();
+
+ wpa_printf(MSG_DEBUG, DRV_PREFIX
+ "disable_receive_sa for " SCISTR
+ "\tAN: %hu\n"
+ "\tnext_pn: %u\n"
+ "\tlowest_pn: %u\n"
+ "\tkey_len: %d\n",
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port),
+ sa->an, sa->next_pn, sa->lowest_pn, sa->pkey->key_len);
+ wpa_hexdump(MSG_DEBUG, DRV_PREFIX "SA key", sa->pkey->key,
+ sa->pkey->key_len);
+
+ sci = mka_sci_u64(&sa->sc->sci);
+
+ msg = msg_prepare(NV_MACSEC_CMD_DIS_RX_SA, drv);
+ if (!msg)
+ return -1;
+
+ nest = nla_nest_start(msg, NV_MACSEC_ATTR_SA_CONFIG);
+
+ if (!nest)
+ goto nla_put_failure;
+
+ NLA_PUT(msg, NV_MACSEC_SA_ATTR_SCI, sizeof(sci), &sa->sc->sci);
+ NLA_PUT_U8(msg, NV_MACSEC_SA_ATTR_AN, sa->an);
+ NLA_PUT_U32(msg, NV_MACSEC_SA_ATTR_PN, sa->next_pn);
+ NLA_PUT(msg, NV_MACSEC_SA_ATTR_KEY, sa->pkey->key_len, sa->pkey->key);
+
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_msg_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "failed to communicate: %d (%s)",
+ ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+
+ PRINT_EXIT();
+ return ret;
+}
+
+
+/**
+ * nv_macsec_drv_create_transmit_sc - Create secure connection for transmit
+ *
+ * @priv: private driver interface data from init()
+ * @sc: secure channel
+ * @conf_offset: confidentiality offset
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+static int nv_macsec_drv_create_transmit_sc(void *priv,
+ struct transmit_sc *sc, unsigned int conf_offset)
+{
+ wpa_printf(MSG_ERROR, DRV_PREFIX
+ "create_transmit_sc - handled in enable_transmit_sa");
+ return 0;
+}
+
+
+/**
+ * nv_macsec_drv_delete_transmit_sc - Delete secure connection for transmit
+ *
+ * @priv: private driver interface data from init()
+ * @sc: secure channel
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+static int nv_macsec_drv_delete_transmit_sc(void *priv, struct transmit_sc *sc)
+{
+ int i = 0;
+ struct nv_macsec_drv_data *drv = priv;
+
+ wpa_printf(MSG_INFO, DRV_PREFIX
+ "delete_transmit_sc - handled in disable_transmit_sa");
+ for (i = 0; i < SCI_PN_INFO_SIZE ; i++) {
+ memset(&drv->sci_pn_info[i].sci, 0,
+ sizeof(drv->sci_pn_info[i].sci));
+ }
+ return 0;
+}
+
+
+/**
+ * nv_macsec_drv_create_transmit_sa - Create secure association for transmit
+ *
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+static int nv_macsec_drv_create_transmit_sa(void *priv, struct transmit_sa *sa)
+{
+ struct nv_macsec_drv_data *drv = priv;
+ struct nv_macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ struct nlattr *nest;
+ u64 sci;
+ int ret = -1;
+
+ PRINT_ENTRY();
+
+ wpa_printf(MSG_DEBUG, DRV_PREFIX
+ "create_transmit_sa for " SCISTR
+ "\tAN: %hu\n"
+ "\tnext_pn: %u\n"
+ "\tkey_len: %d\n",
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port),
+ sa->an, sa->next_pn, sa->pkey->key_len);
+ wpa_hexdump(MSG_DEBUG, DRV_PREFIX "SA key", sa->pkey->key,
+ sa->pkey->key_len);
+
+ sci = mka_sci_u64(&sa->sc->sci);
+
+ msg = msg_prepare(NV_MACSEC_CMD_CREATE_TX_SA, drv);
+ if (!msg)
+ return -1;
+
+ nest = nla_nest_start(msg, NV_MACSEC_ATTR_SA_CONFIG);
+ if (!nest)
+ goto nla_put_failure;
+
+ NLA_PUT(msg, NV_MACSEC_SA_ATTR_SCI, sizeof(sci), &sa->sc->sci);
+ NLA_PUT_U8(msg, NV_MACSEC_SA_ATTR_AN, sa->an);
+ NLA_PUT_U32(msg, NV_MACSEC_SA_ATTR_PN, sa->next_pn);
+ NLA_PUT(msg, NV_MACSEC_SA_ATTR_KEY, sa->pkey->key_len, sa->pkey->key);
+
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_msg_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "failed to communicate: %d (%s)",
+ ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+
+ PRINT_EXIT();
+ return ret;
+}
+
+
+/**
+ * nv_macsec_drv_delete_transmit_sa - Delete secure association for transmit
+ *
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+static int nv_macsec_drv_delete_transmit_sa(void *priv, struct transmit_sa *sa)
+{
+ wpa_printf(MSG_INFO, DRV_PREFIX
+ "delete_transmit_sa - handled in disable_transmit_sa");
+ return 0;
+}
+
+
+/**
+ * nv_macsec_drv_enable_transmit_sa - Enable SA for transmit
+ *
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+static int nv_macsec_drv_enable_transmit_sa(void *priv, struct transmit_sa *sa)
+{
+ struct nv_macsec_drv_data *drv = priv;
+ struct nv_macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ struct nlattr *nest;
+ u64 sci;
+ int ret = -1;
+
+ PRINT_ENTRY();
+
+ sci = mka_sci_u64(&sa->sc->sci);
+
+ msg = msg_prepare(NV_MACSEC_CMD_EN_TX_SA, drv);
+ if (!msg)
+ return -1;
+
+ nest = nla_nest_start(msg, NV_MACSEC_ATTR_SA_CONFIG);
+ if (!nest)
+ goto nla_put_failure;
+
+ NLA_PUT(msg, NV_MACSEC_SA_ATTR_SCI, sizeof(sci), &sa->sc->sci);
+ NLA_PUT_U8(msg, NV_MACSEC_SA_ATTR_AN, sa->an);
+ NLA_PUT_U32(msg, NV_MACSEC_SA_ATTR_PN, sa->next_pn);
+ NLA_PUT(msg, NV_MACSEC_SA_ATTR_KEY, sa->pkey->key_len, sa->pkey->key);
+
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_msg_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "failed to communicate: %d (%s)",
+ ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+
+ PRINT_EXIT();
+ return ret;
+}
+
+
+/**
+ * nv_macsec_drv_disable_transmit_sa - Disable SA for transmit
+ *
+ * @priv: private driver interface data from init()
+ * @sa: secure association
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+static int nv_macsec_drv_disable_transmit_sa(void *priv,
+ struct transmit_sa *sa)
+{
+ struct nv_macsec_drv_data *drv = priv;
+ struct nv_macsec_genl_ctx *ctx = &drv->ctx;
+ struct nl_msg *msg;
+ struct nlattr *nest;
+ u64 sci;
+ int ret = -1;
+
+ PRINT_ENTRY();
+
+ wpa_printf(MSG_DEBUG, DRV_PREFIX
+ "disable_transmit_sa for " SCISTR
+ "\tAN: %hu\n"
+ "\tnext_pn: %u\n"
+ "\tkey_len: %d\n",
+ SCI2STR(sa->sc->sci.addr, sa->sc->sci.port),
+ sa->an, sa->next_pn, sa->pkey->key_len);
+ wpa_hexdump(MSG_DEBUG, DRV_PREFIX "SA key", sa->pkey->key,
+ sa->pkey->key_len);
+
+ sci = mka_sci_u64(&sa->sc->sci);
+
+ msg = msg_prepare(NV_MACSEC_CMD_DIS_TX_SA, drv);
+ if (!msg)
+ return -1;
+
+ nest = nla_nest_start(msg, NV_MACSEC_ATTR_SA_CONFIG);
+ if (!nest)
+ goto nla_put_failure;
+
+ NLA_PUT(msg, NV_MACSEC_SA_ATTR_SCI, sizeof(sci), &sa->sc->sci);
+ NLA_PUT_U8(msg, NV_MACSEC_SA_ATTR_AN, sa->an);
+ NLA_PUT_U32(msg, NV_MACSEC_SA_ATTR_PN, sa->next_pn);
+ NLA_PUT(msg, NV_MACSEC_SA_ATTR_KEY, sa->pkey->key_len, sa->pkey->key);
+
+ nla_nest_end(msg, nest);
+
+ ret = nl_send_msg_recv(ctx->sk, msg);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR,
+ DRV_PREFIX "failed to communicate: %d (%s)",
+ ret, nl_geterror(-ret));
+ }
+
+nla_put_failure:
+ nlmsg_free(msg);
+
+ PRINT_EXIT();
+ return ret;
+}
+
+
+const struct wpa_driver_ops wpa_driver_macsec_nv_ops = {
+ .name = "nv_macsec",
+ .desc = "Nvidia MACsec driver interface for Linux",
+ .get_ssid = driver_wired_get_ssid,
+ .get_bssid = driver_wired_get_bssid,
+ .get_capa = driver_wired_get_capa,
+ .init = macsec_drv_wpa_init,
+ .deinit = macsec_drv_wpa_deinit,
+
+ .macsec_init = nv_macsec_drv_macsec_init,
+ .macsec_deinit = nv_macsec_drv_macsec_deinit,
+ .macsec_get_capability = nv_macsec_drv_get_capability,
+ .enable_protect_frames = nv_macsec_drv_enable_protect_frames,
+ .set_replay_protect = nv_macsec_drv_set_replay_protect,
+ .set_current_cipher_suite = nv_macsec_drv_set_current_cipher_suite,
+ .enable_controlled_port = nv_macsec_drv_enable_controlled_port,
+ .get_receive_lowest_pn = nv_macsec_drv_get_receive_lowest_pn,
+ .set_receive_lowest_pn = nv_macsec_drv_set_receive_lowest_pn,
+ .get_transmit_next_pn = nv_macsec_drv_get_transmit_next_pn,
+ .set_transmit_next_pn = nv_macsec_drv_set_transmit_next_pn,
+ .create_receive_sc = nv_macsec_drv_create_receive_sc,
+ .delete_receive_sc = nv_macsec_drv_delete_receive_sc,
+ .create_receive_sa = nv_macsec_drv_create_receive_sa,
+ .delete_receive_sa = nv_macsec_drv_delete_receive_sa,
+ .enable_receive_sa = nv_macsec_drv_enable_receive_sa,
+ .disable_receive_sa = nv_macsec_drv_disable_receive_sa,
+ .create_transmit_sc = nv_macsec_drv_create_transmit_sc,
+ .delete_transmit_sc = nv_macsec_drv_delete_transmit_sc,
+ .create_transmit_sa = nv_macsec_drv_create_transmit_sa,
+ .delete_transmit_sa = nv_macsec_drv_delete_transmit_sa,
+ .enable_transmit_sa = nv_macsec_drv_enable_transmit_sa,
+ .disable_transmit_sa = nv_macsec_drv_disable_transmit_sa,
+};
diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c
index e95df6ddb..333be6c9d 100644
--- a/src/drivers/drivers.c
+++ b/src/drivers/drivers.c
@@ -1,6 +1,7 @@
/*
* Driver interface list
* Copyright (c) 2004-2005, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -37,6 +38,9 @@ const struct wpa_driver_ops *const wpa_drivers[] =
#ifdef CONFIG_DRIVER_MACSEC_LINUX
&wpa_driver_macsec_linux_ops,
#endif /* CONFIG_DRIVER_MACSEC_LINUX */
+#ifdef CONFIG_DRIVER_NVMACSEC_LINUX
+ &wpa_driver_macsec_nv_ops,
+#endif /* CONFIG_DRIVER_NVMACSEC_LINUX */
#ifdef CONFIG_DRIVER_MACSEC_QCA
&wpa_driver_macsec_qca_ops,
#endif /* CONFIG_DRIVER_MACSEC_QCA */
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index a03d4a034..8b13aadd7 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -30,6 +30,14 @@ ifdef CONFIG_DRIVER_NL80211_BRCM
DRV_CFLAGS += -DCONFIG_DRIVER_NL80211_BRCM
endif
+ifdef CONFIG_DRIVER_NVMACSEC_LINUX
+DRV_CFLAGS += -DCONFIG_DRIVER_NVMACSEC_LINUX
+DRV_OBJS += ../src/drivers/driver_macsec_nv.o
+NEED_DRV_WIRED_COMMON=1
+NEED_LIBNL=y
+CONFIG_LIBNL3_ROUTE=y
+endif
+
ifdef CONFIG_DRIVER_MACSEC_QCA
DRV_CFLAGS += -DCONFIG_DRIVER_MACSEC_QCA
DRV_OBJS += ../src/drivers/driver_macsec_qca.o
diff --git a/src/drivers/nv_macsec_drv.h b/src/drivers/nv_macsec_drv.h
new file mode 100644
index 000000000..8e55d78be
--- /dev/null
+++ b/src/drivers/nv_macsec_drv.h
@@ -0,0 +1,122 @@
+/*
+ * NVIDIA macsec driver interface
+ *
+ * Copyright (c) 2021-2022, NVIDIA CORPORATION.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef NV_MACSEC_DRV_H
+#define NV_MACSEC_DRV_H
+#if NVMACSEC_DEBUG
+#define PRINT_ENTRY() (wpa_printf(MSG_DEBUG, DRV_PREFIX"-->%s()\n", __func__))
+#define PRINT_EXIT() (wpa_printf(MSG_DEBUG, DRV_PREFIX"<--%s()\n", __func__))
+#else
+#define PRINT_ENTRY()
+#define PRINT_EXIT()
+#endif /* NVMACSEC_DEBUG */
+
+#define NV_MACSEC_GENL_VERSION 1
+
+#define KEY_LEN_128 16
+#define DRV_PREFIX "nv_macsec_drv: "
+#define UNUSED_SCI 0xffffffffffffffff
+#define SCISTR MACSTR "::%hx"
+#define SCI2STR(addr, port) MAC2STR(addr), htons(port)
+#define SCI_PN_INFO_SIZE 2
+
+
+struct cb_arg {
+ struct nv_macsec_drv_data *drv;
+};
+
+struct nv_macsec_genl_ctx {
+ struct nl_sock *sk;
+ int nv_macsec_genl_id;
+ struct cb_arg cb_arg;
+};
+
+enum nv_macsec_sa_attrs {
+ NV_MACSEC_SA_ATTR_UNSPEC,
+ NV_MACSEC_SA_ATTR_SCI,
+ NV_MACSEC_SA_ATTR_AN,
+ NV_MACSEC_SA_ATTR_PN,
+ NV_MACSEC_SA_ATTR_LOWEST_PN,
+ NV_MACSEC_SA_ATTR_KEY,
+ __NV_MACSEC_SA_ATTR_END,
+ NUM_NV_MACSEC_SA_ATTR = __NV_MACSEC_SA_ATTR_END,
+ NV_MACSEC_SA_ATTR_MAX = __NV_MACSEC_SA_ATTR_END - 1,
+};
+
+enum nv_macsec_tz_attrs {
+ NV_MACSEC_TZ_ATTR_UNSPEC,
+ NV_MACSEC_TZ_INSTANCE_ID,
+ NV_MACSEC_TZ_ATTR_CTRL,
+ NV_MACSEC_TZ_ATTR_RW,
+ NV_MACSEC_TZ_ATTR_INDEX,
+ NV_MACSEC_TZ_ATTR_KEY,
+ NV_MACSEC_TZ_ATTR_FLAG,
+ __NV_MACSEC_TZ_ATTR_END,
+ NUM_NV_MACSEC_TZ_ATTR = __NV_MACSEC_TZ_ATTR_END,
+ NV_MACSEC_TZ_ATTR_MAX = __NV_MACSEC_TZ_ATTR_END - 1,
+};
+
+enum nv_macsec_tz_kt_reset_attrs {
+ NV_MACSEC_TZ_KT_RESET_ATTR_UNSPEC,
+ NV_MACSEC_TZ_KT_RESET_INSTANCE_ID,
+ __NV_MACSEC_TZ_KT_RESET_ATTR_END,
+ NUM_NV_MACSEC_TZ_KT_RESET_ATTR = __NV_MACSEC_TZ_KT_RESET_ATTR_END,
+ NV_MACSEC_TZ_KT_RESET_ATTR_MAX = __NV_MACSEC_TZ_KT_RESET_ATTR_END - 1,
+};
+
+enum nv_macsec_attrs {
+ NV_MACSEC_ATTR_UNSPEC,
+ NV_MACSEC_ATTR_IFNAME,
+ NV_MACSEC_ATTR_TXSC_PORT,
+ NV_MACSEC_ATTR_PROT_FRAMES_EN,
+ NV_MACSEC_ATTR_REPLAY_PROT_EN,
+ NV_MACSEC_ATTR_REPLAY_WINDOW,
+ NV_MACSEC_ATTR_CIPHER_SUITE,
+ NV_MACSEC_ATTR_CTRL_PORT_EN,
+ NV_MACSEC_ATTR_SA_CONFIG, /* Nested SA config */
+ NV_MACSEC_ATTR_TZ_CONFIG, /* Nested TZ config */
+ NV_MACSEC_ATTR_TZ_KT_RESET, /* Nested TZ KT config */
+ __NV_MACSEC_ATTR_END,
+ NUM_NV_MACSEC_ATTR = __NV_MACSEC_ATTR_END,
+ NV_MACSEC_ATTR_MAX = __NV_MACSEC_ATTR_END - 1,
+};
+
+enum nv_macsec_nl_commands {
+ NV_MACSEC_CMD_INIT,
+ NV_MACSEC_CMD_GET_TX_NEXT_PN,
+ NV_MACSEC_CMD_SET_PROT_FRAMES,
+ NV_MACSEC_CMD_SET_REPLAY_PROT,
+ NV_MACSEC_CMD_SET_CIPHER,
+ NV_MACSEC_CMD_SET_CONTROLLED_PORT,
+ NV_MACSEC_CMD_CREATE_TX_SA,
+ NV_MACSEC_CMD_EN_TX_SA,
+ NV_MACSEC_CMD_DIS_TX_SA,
+ NV_MACSEC_CMD_CREATE_RX_SA,
+ NV_MACSEC_CMD_EN_RX_SA,
+ NV_MACSEC_CMD_DIS_RX_SA,
+ NV_MACSEC_CMD_TZ_CONFIG,
+ NV_MACSEC_CMD_TZ_KT_RESET,
+ NV_MACSEC_CMD_DEINIT,
+};
+
+struct sci_pn_info {
+ struct ieee802_1x_mka_sci sci;
+ u8 an;
+ u32 next_pn;
+};
+
+struct nv_macsec_drv_data {
+ struct driver_wired_common_data common;
+ struct nl_sock *sk;
+ struct nv_macsec_genl_ctx ctx;
+ char ifname[IFNAMSIZ + 1];
+ struct sci_pn_info sci_pn_info[SCI_PN_INFO_SIZE];
+ u8 cipher;
+};
+#endif /* !NV_MACSEC_DRV_H */
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index a4f20d439..222c35286 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -76,6 +76,9 @@ CONFIG_DRIVER_WIRED=y
# Driver interface for MACsec capable Qualcomm Atheros drivers
#CONFIG_DRIVER_MACSEC_QCA=y
+# Driver interface for MACsec capable NVIDIA drivers
+CONFIG_DRIVER_NVMACSEC_LINUX=y
+
# Driver interface for Linux MACsec drivers
CONFIG_DRIVER_MACSEC_LINUX=y
--
2.25.1
More information about the Hostap
mailing list