]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
nl80211: Define vendor interface functions to offload PASN authentication
authorVinay Gannevaram <quic_vganneva@quicinc.com>
Tue, 26 Jul 2022 10:56:25 +0000 (16:26 +0530)
committerJouni Malinen <j@w1.fi>
Fri, 2 Sep 2022 13:18:26 +0000 (16:18 +0300)
This defines the QCA vendor interface functions to offload PASN
authentication from the driver.

The driver sends the QCA_NL80211_VENDOR_SUBCMD_PASN event requesting to
perform PASN authentication with a list of peers with which the driver
needs to do ranging. wpa_supplicant performs PASN handshake with all the
peer devices and sets the required keys using the command
QCA_NL80211_VENDOR_SUBCMD_SECURE_RANGING_CONTEXT to the driver. After
PASN handshake is completed with all requested peers, wpa_supplicant
sends consolidated status for all peers to the driver.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
src/drivers/driver_nl80211.c
src/drivers/driver_nl80211.h
src/drivers/driver_nl80211_capa.c
src/drivers/driver_nl80211_event.c

index 85e28bc6273a79222db4a91cb97fed05711caaa7..a4b2d5219e153996ab1282c524bdef68e41afb88 100644 (file)
@@ -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,
index 6e40d555673ae9af786fc2f8b44f0ea826b117d3..9a9faf69820e133b53d1399a61c8dfca955adc6c 100644 (file)
@@ -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;
index 03ac9345bee084004aa63e24c6c5178bf627a79a..512bbb6de2915e889bc9606ca217cd13bade35b4 100644 (file)
@@ -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
index ca094e1e43d3614a7b3a25148016e6babca60e53..266c8c1e9edb977a0d1a1c555c91a00cc50cf434 100644 (file)
@@ -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,