diff --git a/src/dpp.c b/src/dpp.c index a95f93e2..41b7c70e 100644 --- a/src/dpp.c +++ b/src/dpp.c @@ -183,6 +183,7 @@ struct dpp_sm { size_t z_len; uint8_t u[L_ECC_SCALAR_MAX_BYTES]; size_t u_len; + uint32_t pkex_scan_id; bool mcast_support : 1; bool roc_started : 1; @@ -508,6 +509,11 @@ static void dpp_reset(struct dpp_sm *dpp) dpp->retry_timeout = NULL; } + if (dpp->pkex_scan_id) { + scan_cancel(dpp->wdev_id, dpp->pkex_scan_id); + dpp->pkex_scan_id = 0; + } + dpp->state = DPP_STATE_NOTHING; dpp->new_freq = 0; dpp->frame_retry = 0; @@ -4073,6 +4079,14 @@ static struct l_dbus_message *dpp_dbus_stop(struct l_dbus *dbus, return l_dbus_message_new_method_return(message); } +static void dpp_pkex_scan_trigger(int err, void *user_data) +{ + struct dpp_sm *dpp = user_data; + + if (err < 0) + dpp_reset(dpp); +} + /* * Section 5.6.1 * In lieu of specific channel information obtained in a manner outside @@ -4111,6 +4125,62 @@ static uint32_t *dpp_default_freqs(struct dpp_sm *dpp, size_t *out_len) return freqs_out; } +static bool dpp_pkex_scan_notify(int err, struct l_queue *bss_list, + const struct scan_freq_set *freqs, + void *user_data) +{ + struct dpp_sm *dpp = user_data; + const struct l_queue_entry *e; + _auto_(scan_freq_set_free) struct scan_freq_set *freq_set = NULL; + + if (err < 0) + goto failed; + + freq_set = scan_freq_set_new(); + + if (!bss_list || l_queue_isempty(bss_list)) { + dpp->freqs = dpp_default_freqs(dpp, &dpp->freqs_len); + if (!dpp->freqs) + goto failed; + + l_debug("No BSS's seen, using default frequency list"); + goto start; + } + + for (e = l_queue_get_entries(bss_list); e; e = e->next) { + const struct scan_bss *bss = e->data; + + scan_freq_set_add(freq_set, bss->frequency); + } + + l_debug("Found %u frequencies to search for configurator", + l_queue_length(bss_list)); + + dpp->freqs = scan_freq_set_to_fixed_array(freq_set, &dpp->freqs_len); + +start: + dpp->current_freq = dpp->freqs[0]; + + dpp_reset_protocol_timer(dpp, DPP_PKEX_PROTO_TIMEOUT); + + l_debug("PKEX start enrollee (id=%s)", dpp->pkex_id ?: "unset"); + + dpp_start_offchannel(dpp, dpp->current_freq); + + return false; + +failed: + dpp_reset(dpp); + return false; +} + +static void dpp_pkex_scan_destroy(void *user_data) +{ + struct dpp_sm *dpp = user_data; + + dpp->pkex_scan_id = 0; +} + static bool dpp_start_pkex_enrollee(struct dpp_sm *dpp, const char *key, const char *identifier) { @@ -4156,18 +4226,26 @@ static bool dpp_start_pkex_enrollee(struct dpp_sm *dpp, const char *key, dpp_property_changed_notify(dpp); - dpp->freqs = dpp_default_freqs(dpp, &dpp->freqs_len); - if (!dpp->freqs) + /* + * The 'dpp_default_freqs' function returns the default frequencies + * outlined in section 5.6.1. For 2.4/5GHz this is only 3 frequencies + * which is unlikely to result in discovery of a configurator. The spec + * does allow frequencies to be "obtained in a manner outside the scope + * of this specification" which is what is being done here. + * + * This is mainly geared towards IWD-based configurators; banking on the + * fact that they are currently connected to nearby APs. Scanning lets + * us see nearby BSS's which should be the same frequencies as our + * target configurator. + */ + l_debug("Performing scan for frequencies to start PKEX"); + + dpp->pkex_scan_id = scan_active(dpp->wdev_id, NULL, 0, + dpp_pkex_scan_trigger, dpp_pkex_scan_notify, + dpp, dpp_pkex_scan_destroy); + if (!dpp->pkex_scan_id) goto failed; - dpp->current_freq = dpp->freqs[dpp->freqs_idx]; - - dpp_reset_protocol_timer(dpp, DPP_PKEX_PROTO_TIMEOUT); - - l_debug("PKEX start enrollee (id=%s)", dpp->pkex_id ?: "unset"); - - dpp_start_offchannel(dpp, dpp->current_freq); - return true; failed: