@@ -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,17 +4226,25 @@ 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)
- 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");
+ /*
+ * 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_start_offchannel(dpp, dpp->current_freq);
+ 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;
return true;