[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