dpp: scan to pick up extra frequencies when enrolling

The DPP-PKEX spec provides a very limited list of frequencies used
to discover configurators, only 3 on 2.4 and 5GHz bands. Since
configurators (at least in IWD's implementation) are only allowed
on the current operating frequency its very unlikely an enrollee
will find a configurator on these frequencies out of the entire
spectrum.

The spec does mention that the 3 default frequencies should be used
"In lieu of specific channel information obtained in a manner outside
the scope of this specification, ...". This allows the implementation
some flexibility in using a broader range of frequencies.

To increase the chances of finding a configurator shared code
enrollees will first issue a scan to determine what access points are
around, then iterate these frequencies. This is especially helpful
when the configurators are IWD-based since we know that they'll be
on the same channels as the APs in the area.
This commit is contained in:
James Prestwood 2023-11-13 09:54:01 -08:00 committed by Denis Kenzior
parent c8a86edffe
commit 3c02f387cb
1 changed files with 88 additions and 10 deletions

View File

@ -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: