From 0430756e654bd27321eb655898f8506fdbba87e5 Mon Sep 17 00:00:00 2001 From: Matthew Wang Date: Tue, 21 Feb 2023 16:46:16 -0800 Subject: [PATCH] P2P: Optimize join scan frequency Allow clients to specify the BSSID of an auto GO. If the auto GO has been discovered on another interface, optimize scan frequency by performing a single channel scan first. Android and ChromeOS use this to streamline auto GO discovery. Signed-off-by: Matthew Wang --- wpa_supplicant/bss.c | 7 +++-- wpa_supplicant/ctrl_iface.c | 2 +- wpa_supplicant/dbus/dbus_new_handlers_p2p.c | 14 +++++++-- wpa_supplicant/events.c | 2 +- wpa_supplicant/p2p_supplicant.c | 23 +++++++++----- wpa_supplicant/p2p_supplicant.h | 3 +- wpa_supplicant/scan.c | 34 ++++++++++++++++++++- wpa_supplicant/wpa_supplicant_i.h | 1 + 8 files changed, 69 insertions(+), 17 deletions(-) diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c index 043ec3580..320441426 100644 --- a/wpa_supplicant/bss.c +++ b/wpa_supplicant/bss.c @@ -240,7 +240,7 @@ void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, /** * wpa_bss_get - Fetch a BSS table entry based on BSSID and SSID * @wpa_s: Pointer to wpa_supplicant data - * @bssid: BSSID + * @bssid: BSSID, or %NULL to match any BSSID * @ssid: SSID * @ssid_len: Length of @ssid * Returns: Pointer to the BSS entry or %NULL if not found @@ -249,10 +249,11 @@ struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid, const u8 *ssid, size_t ssid_len) { struct wpa_bss *bss; - if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid)) + + if (bssid && !wpa_supplicant_filter_bssid_match(wpa_s, bssid)) return NULL; dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { - if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 && + if ((!bssid || os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0) && bss->ssid_len == ssid_len && os_memcmp(bss->ssid, ssid, ssid_len) == 0) return bss; diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 6588fd47b..68a62da72 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -7128,7 +7128,7 @@ static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s, return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, vht_center_freq2, 0, ht40, vht, vht_chwidth, he, edmg, - NULL, 0, 0, allow_6ghz, 0); + NULL, 0, 0, allow_6ghz, 0, NULL); } diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c index 370aee278..a178d879e 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c +++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c @@ -359,6 +359,7 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message, char *iface = NULL; unsigned int group_id = 0; struct wpa_ssid *ssid; + u8 go_bssid_buf[ETH_ALEN], *go_bssid = NULL; dbus_message_iter_init(message, &iter); @@ -384,10 +385,16 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message, goto inv_args_clear; } else if (os_strcmp(entry.key, "persistent_group_object") == 0 && - entry.type == DBUS_TYPE_OBJECT_PATH) + entry.type == DBUS_TYPE_OBJECT_PATH) { pg_object_path = os_strdup(entry.str_value); - else + } else if (os_strcmp(entry.key, "go_bssid") == 0 && + entry.type == DBUS_TYPE_STRING) { + if (hwaddr_aton(entry.str_value, go_bssid_buf)) + goto inv_args_clear; + go_bssid = go_bssid_buf; + } else { goto inv_args_clear; + } wpa_dbus_dict_entry_clear(&entry); } @@ -432,7 +439,8 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message, if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, 0, 0, 0, 0, 0, 0, 0, NULL, 0, 0, - false, retry_limit)) { + false, retry_limit, + go_bssid)) { reply = wpas_dbus_error_unknown_error( message, "Failed to reinvoke a persistent group"); diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index e58a3da83..a9ff49133 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -1163,7 +1163,7 @@ static void owe_trans_ssid(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, } -static int disabled_freq(struct wpa_supplicant *wpa_s, int freq) +int disabled_freq(struct wpa_supplicant *wpa_s, int freq) { int i, j; diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index b906c7736..4263ee9f3 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -3373,7 +3373,8 @@ static void wpas_invitation_received(void *ctx, const u8 *sa, const u8 *bssid, wpa_s->conf->p2p_go_he, wpa_s->conf->p2p_go_edmg, NULL, go ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, - 1, is_p2p_allow_6ghz(wpa_s->global->p2p), 0); + 1, is_p2p_allow_6ghz(wpa_s->global->p2p), 0, + NULL); } else if (bssid) { wpa_s->user_initiated_pd = 0; wpa_msg_global(wpa_s, MSG_INFO, @@ -3603,7 +3604,8 @@ static void wpas_invitation_result(void *ctx, int status, const u8 *bssid, ssid->mode == WPAS_MODE_P2P_GO ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, 1, - is_p2p_allow_6ghz(wpa_s->global->p2p), 0); + is_p2p_allow_6ghz(wpa_s->global->p2p), 0, + NULL); } @@ -4689,7 +4691,7 @@ static void wpas_p2ps_prov_complete(void *ctx, u8 status, const u8 *dev, persistent_go->mode == WPAS_MODE_P2P_GO ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : - 0, 0, false, 0); + 0, 0, false, 0, NULL); } else if (response_done) { wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0, 0, 0, false); @@ -4812,7 +4814,7 @@ static int wpas_prov_disc_resp_cb(void *ctx) NULL, persistent_go->mode == WPAS_MODE_P2P_GO ? P2P_MAX_INITIAL_CONN_WAIT_GO_REINVOKE : 0, 0, - is_p2p_allow_6ghz(wpa_s->global->p2p), 0); + is_p2p_allow_6ghz(wpa_s->global->p2p), 0, NULL); } else { wpas_p2p_group_add(wpa_s, 1, freq, 0, 0, 0, 0, 0, 0, is_p2p_allow_6ghz(wpa_s->global->p2p)); @@ -6946,7 +6948,8 @@ int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group, static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s, struct wpa_ssid *params, int addr_allocated, - int freq, int force_scan, int retry_limit) + int freq, int force_scan, int retry_limit, + const u8 *go_bssid) { struct wpa_ssid *ssid; int other_iface_found = 0; @@ -6999,6 +7002,11 @@ static int wpas_start_p2p_client(struct wpa_supplicant *wpa_s, if (params->passphrase) ssid->passphrase = os_strdup(params->passphrase); + if (go_bssid) { + ssid->bssid_set = 1; + os_memcpy(ssid->bssid, go_bssid, ETH_ALEN); + } + wpa_s->show_group_started = 1; wpa_s->p2p_in_invitation = 1; wpa_s->p2p_retry_limit = retry_limit; @@ -7045,7 +7053,8 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, int edmg, const struct p2p_channels *channels, int connection_timeout, int force_scan, - bool allow_6ghz, int retry_limit) + bool allow_6ghz, int retry_limit, + const u8 *go_bssid) { struct p2p_go_neg_results params; int go = 0, freq; @@ -7113,7 +7122,7 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, } return wpas_start_p2p_client(wpa_s, ssid, addr_allocated, freq, - force_scan, retry_limit); + force_scan, retry_limit, go_bssid); } else { return -1; } diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h index 907ac8cca..d71f7701c 100644 --- a/wpa_supplicant/p2p_supplicant.h +++ b/wpa_supplicant/p2p_supplicant.h @@ -52,7 +52,8 @@ int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s, int max_oper_chwidth, int he, int edmg, const struct p2p_channels *channels, int connection_timeout, int force_scan, - bool allow_6ghz, int retry_limit); + bool allow_6ghz, int retry_limit, + const u8 *go_bssid); struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); enum wpas_p2p_prov_disc_use { diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index cc9faf2a8..c3984a40c 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -445,11 +445,43 @@ static void wpa_supplicant_optimize_freqs( } if (params->freqs == NULL && wpa_s->p2p_in_invitation) { + struct wpa_ssid *ssid = wpa_s->current_ssid; + + /* + * Perform a single-channel scan if the GO has already been + * discovered on another non-P2P interface. Note that a scan + * initiated by a P2P interface (e.g., the device interface) + * should already have sufficient IEs and scan results will be + * fetched on interface creation in that case. + */ + if (wpa_s->p2p_in_invitation == 1 && ssid) { + struct wpa_supplicant *ifs; + struct wpa_bss *bss = NULL; + const u8 *bssid = ssid->bssid_set ? ssid->bssid : NULL; + + dl_list_for_each(ifs, &wpa_s->radio->ifaces, + struct wpa_supplicant, radio_list) { + bss = wpa_bss_get(ifs, bssid, ssid->ssid, + ssid->ssid_len); + if (bss) + break; + } + if (bss && !disabled_freq(wpa_s, bss->freq)) { + params->freqs = os_calloc(2, sizeof(int)); + if (params->freqs) { + wpa_dbg(wpa_s, MSG_DEBUG, + "P2P: Scan only the known GO frequency %d MHz during invitation", + bss->freq); + params->freqs[0] = bss->freq; + } + } + } + /* * Optimize scan based on GO information during persistent * group reinvocation */ - if (wpa_s->p2p_in_invitation < 5 && + if (!params->freqs && wpa_s->p2p_in_invitation < 5 && wpa_s->p2p_invite_go_freq > 0) { if (wpa_s->p2p_invite_go_freq == 2 || wpa_s->p2p_invite_go_freq == 5) { diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index cb7d5f5a1..61d274a05 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1826,6 +1826,7 @@ int get_shared_radio_freqs_data(struct wpa_supplicant *wpa_s, int get_shared_radio_freqs(struct wpa_supplicant *wpa_s, int *freq_array, unsigned int len, bool exclude_current); +int disabled_freq(struct wpa_supplicant *wpa_s, int freq); void wpas_network_reenabled(void *eloop_ctx, void *timeout_ctx);