diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 85e28bc62..a4b2d5219 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -31,6 +31,8 @@ #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" #include "common/wpa_common.h" +#include "crypto/sha256.h" +#include "crypto/sha384.h" #include "netlink.h" #include "linux_defines.h" #include "linux_ioctl.h" @@ -11957,6 +11959,169 @@ fail: #endif /* CONFIG_MBO */ + +#ifdef CONFIG_PASN + +static int nl80211_send_pasn_resp(void *priv, struct pasn_auth *params) +{ + unsigned int i; + struct i802_bss *bss = priv; + struct nl_msg *msg = NULL; + struct nlattr *nlpeers, *attr, *attr1; + struct wpa_driver_nl80211_data *drv = bss->drv; + + wpa_dbg(drv->ctx, MSG_DEBUG, + "nl80211: PASN authentication response for %d entries", + params->num_peers); + msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR); + if (!msg || + nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) || + nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, + QCA_NL80211_VENDOR_SUBCMD_PASN)) + goto fail; + + attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA); + if (!attr) + goto fail; + + nlpeers = nla_nest_start(msg, QCA_WLAN_VENDOR_ATTR_PASN_PEERS); + if (!nlpeers) + goto fail; + + for (i = 0; i < params->num_peers; i++) { + attr1 = nla_nest_start(msg, i); + if (!attr1 || + nla_put(msg, QCA_WLAN_VENDOR_ATTR_PASN_PEER_SRC_ADDR, + ETH_ALEN, params->peer[i].own_addr) || + nla_put(msg, QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR, + ETH_ALEN, params->peer[i].peer_addr)) + goto fail; + + if (params->peer[i].status == 0) + nla_put_flag(msg, + QCA_WLAN_VENDOR_ATTR_PASN_PEER_STATUS_SUCCESS); + + wpa_printf(MSG_DEBUG, + "nl80211: Own address[%u]: " MACSTR + " Peer address[%u]: " MACSTR " Status: %s", + i, MAC2STR(params->peer[i].own_addr), i, + MAC2STR(params->peer[i].peer_addr), + params->peer[i].status ? "Fail" : "Success"); + nla_nest_end(msg, attr1); + } + + nla_nest_end(msg, nlpeers); + nla_nest_end(msg, attr); + + return send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + +fail: + nlmsg_free(msg); + return -1; +} + + +static u32 wpa_ltf_keyseed_len_to_sha_type(size_t len) +{ + if (len == SHA384_MAC_LEN) + return QCA_WLAN_VENDOR_SHA_384; + if (len == SHA256_MAC_LEN) + return QCA_WLAN_VENDOR_SHA_256; + + wpa_printf(MSG_ERROR, "nl80211: Unexpected LTF keyseed len %zu", len); + return (u32) -1; +} + + +static int nl80211_set_secure_ranging_ctx(void *priv, + struct secure_ranging_params *params) +{ + int ret; + u32 suite; + struct nlattr *attr; + struct nl_msg *msg = NULL; + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + + /* Configure secure ranging context only to the drivers that support it. + */ + if (!drv->secure_ranging_ctx_vendor_cmd_avail) + return 0; + + if (!params->peer_addr || !params->own_addr) + return -1; + + wpa_dbg(drv->ctx, MSG_DEBUG, + "nl80211: Secure ranging context for " MACSTR, + MAC2STR(params->peer_addr)); + + msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR); + if (!msg || + nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) || + nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, + QCA_NL80211_VENDOR_SUBCMD_SECURE_RANGING_CONTEXT)) + goto fail; + + attr = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA); + if (!attr) + goto fail; + + if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_PEER_MAC_ADDR, + ETH_ALEN, params->peer_addr) || + nla_put(msg, QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SRC_ADDR, + ETH_ALEN, params->own_addr) || + nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_ACTION, + params->action)) + goto fail; + + if (params->cipher) { + suite = wpa_cipher_to_cipher_suite(params->cipher); + if (!suite || + nla_put_u32(msg, + QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_CIPHER, + suite)) + goto fail; + } + + if (params->tk_len && params->tk) { + if (nla_put(msg, QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_TK, + params->tk_len, params->tk)) + goto fail; + wpa_hexdump_key(MSG_DEBUG, "nl80211: TK", + params->tk, params->tk_len); + } + + if (params->ltf_keyseed_len && params->ltf_keyseed) { + u32 sha_type = wpa_ltf_keyseed_len_to_sha_type( + params->ltf_keyseed_len); + + if (sha_type == (u32) -1 || + nla_put_u32( + msg, + QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SHA_TYPE, + sha_type) || + nla_put(msg, + QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_LTF_KEYSEED, + params->ltf_keyseed_len, params->ltf_keyseed)) + goto fail; + wpa_hexdump_key(MSG_DEBUG, "nl80211: LTF keyseed", + params->ltf_keyseed, params->ltf_keyseed_len); + } + nla_nest_end(msg, attr); + + ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL); + if (ret) + wpa_printf(MSG_DEBUG, + "nl80211: Set secure ranging context failed: ret=%d (%s)", + ret, strerror(-ret)); + return ret; +fail: + nlmsg_free(msg); + return -1; +} + +#endif /* CONFIG_PASN */ + #endif /* CONFIG_DRIVER_NL80211_QCA */ @@ -12525,6 +12690,10 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { #endif /* CONFIG_MBO */ .set_bssid_tmp_disallow = nl80211_set_bssid_tmp_disallow, .add_sta_node = nl80211_add_sta_node, +#ifdef CONFIG_PASN + .send_pasn_resp = nl80211_send_pasn_resp, + .set_secure_ranging_ctx = nl80211_set_secure_ranging_ctx, +#endif /* CONFIG_PASN */ #endif /* CONFIG_DRIVER_NL80211_QCA */ .do_acs = nl80211_do_acs, .configure_data_frame_filters = nl80211_configure_data_frame_filters, diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h index 6e40d5556..9a9faf698 100644 --- a/src/drivers/driver_nl80211.h +++ b/src/drivers/driver_nl80211.h @@ -181,6 +181,7 @@ struct wpa_driver_nl80211_data { unsigned int qca_do_acs:1; unsigned int brcm_do_acs:1; unsigned int uses_6ghz:1; + unsigned int secure_ranging_ctx_vendor_cmd_avail:1; u64 vendor_scan_cookie; u64 remain_on_chan_cookie; diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c index 03ac9345b..512bbb6de 100644 --- a/src/drivers/driver_nl80211_capa.c +++ b/src/drivers/driver_nl80211_capa.c @@ -1055,6 +1055,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) case QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO: drv->get_sta_info_vendor_cmd_avail = 1; break; + case QCA_NL80211_VENDOR_SUBCMD_SECURE_RANGING_CONTEXT: + drv->secure_ranging_ctx_vendor_cmd_avail = 1; + break; #endif /* CONFIG_DRIVER_NL80211_QCA */ } #ifdef CONFIG_DRIVER_NL80211_BRCM diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index ca094e1e4..266c8c1e9 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -2401,6 +2401,82 @@ static void qca_nl80211_p2p_lo_stop_event(struct wpa_driver_nl80211_data *drv, wpa_supplicant_event(drv->ctx, EVENT_P2P_LO_STOP, &event); } + +#ifdef CONFIG_PASN + +static void qca_nl80211_pasn_auth(struct wpa_driver_nl80211_data *drv, + u8 *data, size_t len) +{ + int ret = -EINVAL; + struct nlattr *attr; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1]; + struct nlattr *cfg[QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAX + 1]; + unsigned int n_peers = 0, idx = 0; + int rem_conf; + enum qca_wlan_vendor_pasn_action action; + union wpa_event_data event; + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PASN_MAX, + (struct nlattr *) data, len, NULL) || + !tb[QCA_WLAN_VENDOR_ATTR_PASN_PEERS] || + !tb[QCA_WLAN_VENDOR_ATTR_PASN_ACTION]) { + return; + } + + os_memset(&event, 0, sizeof(event)); + action = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_PASN_ACTION]); + switch (action) { + case QCA_WLAN_VENDOR_PASN_ACTION_AUTH: + event.pasn_auth.action = PASN_ACTION_AUTH; + break; + case QCA_WLAN_VENDOR_PASN_ACTION_DELETE_SECURE_RANGING_CONTEXT: + event.pasn_auth.action = + PASN_ACTION_DELETE_SECURE_RANGING_CONTEXT; + break; + default: + return; + } + + nla_for_each_nested(attr, tb[QCA_WLAN_VENDOR_ATTR_PASN_PEERS], rem_conf) + n_peers++; + + if (n_peers > WPAS_MAX_PASN_PEERS) { + wpa_printf(MSG_DEBUG, "nl80211: PASN auth: too many peers (%d)", + n_peers); + return; + } + + nla_for_each_nested(attr, tb[QCA_WLAN_VENDOR_ATTR_PASN_PEERS], + rem_conf) { + struct nlattr *nl_src, *nl_peer; + + ret = nla_parse_nested(cfg, QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAX, + attr, NULL); + if (ret) + return; + nl_src = cfg[QCA_WLAN_VENDOR_ATTR_PASN_PEER_SRC_ADDR]; + nl_peer = cfg[QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR]; + if (nl_src) + os_memcpy(event.pasn_auth.peer[idx].own_addr, nl_src, + ETH_ALEN); + if (nl_peer) + os_memcpy(event.pasn_auth.peer[idx].peer_addr, nl_peer, + ETH_ALEN); + if (cfg[QCA_WLAN_VENDOR_ATTR_PASN_PEER_LTF_KEYSEED_REQUIRED]) + event.pasn_auth.peer[idx].ltf_keyseed_required = true; + idx++; + } + event.pasn_auth.num_peers = n_peers; + + wpa_printf(MSG_DEBUG, + "nl80211: PASN auth action: %u, num_bssids: %d", + event.pasn_auth.action, + event.pasn_auth.num_peers); + wpa_supplicant_event(drv->ctx, EVENT_PASN_AUTH, &event); +} + +#endif /* CONFIG_PASN */ + #endif /* CONFIG_DRIVER_NL80211_QCA */ @@ -2437,6 +2513,11 @@ static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv, case QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP: qca_nl80211_p2p_lo_stop_event(drv, data, len); break; +#ifdef CONFIG_PASN + case QCA_NL80211_VENDOR_SUBCMD_PASN: + qca_nl80211_pasn_auth(drv, data, len); + break; +#endif /* CONFIG_PASN */ #endif /* CONFIG_DRIVER_NL80211_QCA */ default: wpa_printf(MSG_DEBUG,