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@xxxxxxxxxx> --- 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@xxxxx> + * 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@xxxxx> + * 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 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap