[PATCH] network: reply to pending messages on network_unregister
by James Prestwood
If there is a connect_after_* message for ANQP or OWE hidden networks
reply to these before unregistering the network.
---
src/network.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/src/network.c b/src/network.c
index 711fb296..7240b029 100644
--- a/src/network.c
+++ b/src/network.c
@@ -1745,6 +1745,14 @@ static void network_unregister(struct network *network, int reason)
{
struct l_dbus *dbus = dbus_get_bus();
+ if (network->connect_after_anqp)
+ dbus_pending_reply(&network->connect_after_anqp,
+ dbus_error_aborted(network->connect_after_anqp));
+
+ if (network->connect_after_owe_hidden)
+ dbus_pending_reply(&network->connect_after_owe_hidden,
+ dbus_error_aborted(network->connect_after_owe_hidden));
+
agent_request_cancel(network->agent_request, reason);
network_settings_close(network);
--
2.31.1
8 months
[PATCH v7 1/5] scan: add scan API specifically for OWE transition networks
by James Prestwood
Specifically OWE networks with multiple open/hidden BSS's are troublesome
to scan for with the current APIs. The scan parameters are limited to a
single SSID and even if that was changed we have the potential of hitting
the max SSID's per scan limit. In all, it puts the burden onto the caller
to sort out the SSIDs/frequencies to scan for.
Rather than requiring station to handle this a new scan API was added,
scan_owe_hidden() which takes a list of open BSS's and will automatically
scan for the SSIDs in the OWE transition IE for each.
It is slightly optimized to first check if all the hidden SSID's are the
same. This is the most likely case (e.g. single pair or single network)
and a single scan command can be used. Otherwise individual scan commands
are queued for each SSID/frequency combo.
---
src/scan.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++---
src/scan.h | 3 ++
2 files changed, 134 insertions(+), 8 deletions(-)
diff --git a/src/scan.c b/src/scan.c
index b2f199e5..7d6e46e9 100644
--- a/src/scan.c
+++ b/src/scan.c
@@ -583,6 +583,27 @@ static const struct wiphy_radio_work_item_ops work_ops = {
.destroy = scan_request_free,
};
+static struct scan_request *scan_request_new(struct scan_context *sc,
+ bool passive,
+ scan_trigger_func_t trigger,
+ scan_notify_func_t notify,
+ void *userdata,
+ scan_destroy_func_t destroy)
+{
+ struct scan_request *sr;
+
+ sr = l_new(struct scan_request, 1);
+ sr->sc = sc;
+ sr->trigger = trigger;
+ sr->callback = notify;
+ sr->userdata = userdata;
+ sr->destroy = destroy;
+ sr->passive = passive;
+ sr->cmds = l_queue_new();
+
+ return sr;
+}
+
static uint32_t scan_common(uint64_t wdev_id, bool passive,
const struct scan_parameters *params,
scan_trigger_func_t trigger,
@@ -597,14 +618,7 @@ static uint32_t scan_common(uint64_t wdev_id, bool passive,
if (!sc)
return 0;
- sr = l_new(struct scan_request, 1);
- sr->sc = sc;
- sr->trigger = trigger;
- sr->callback = notify;
- sr->userdata = userdata;
- sr->destroy = destroy;
- sr->passive = passive;
- sr->cmds = l_queue_new();
+ sr = scan_request_new(sc, passive, trigger, notify, userdata, destroy);
scan_cmds_add(sr->cmds, sc, passive, params);
@@ -656,6 +670,115 @@ uint32_t scan_active_full(uint64_t wdev_id,
trigger, notify, userdata, destroy);
}
+static void add_owe_scan_cmd(struct scan_context *sc, struct scan_request *sr,
+ bool ignore_flush,
+ struct scan_freq_set *freqs,
+ const struct scan_bss *bss)
+{
+ struct l_genl_msg *cmd;
+ struct scan_parameters params = {};
+ struct scan_freq_set *tmp;
+
+ if (!freqs) {
+ tmp = scan_freq_set_new();
+ scan_freq_set_add(tmp, bss->frequency);
+ params.freqs = tmp;
+ } else
+ params.freqs = freqs;
+
+ params.ssid = bss->owe_trans_ssid;
+ params.ssid_len = bss->owe_trans_ssid_len;
+ params.flush = true;
+
+ cmd = scan_build_cmd(sc, ignore_flush, false, ¶ms);
+
+ l_genl_msg_enter_nested(cmd, NL80211_ATTR_SCAN_SSIDS);
+ l_genl_msg_append_attr(cmd, 0, params.ssid_len, params.ssid);
+ l_genl_msg_leave_nested(cmd);
+
+ l_queue_push_tail(sr->cmds, cmd);
+
+ if (!freqs)
+ scan_freq_set_free(tmp);
+}
+
+uint32_t scan_owe_hidden(uint64_t wdev_id, struct l_queue *list,
+ scan_trigger_func_t trigger, scan_notify_func_t notify,
+ void *userdata, scan_destroy_func_t destroy)
+{
+ struct scan_context *sc;
+ struct scan_request *sr;
+ struct scan_freq_set *freqs;
+ const struct l_queue_entry *entry;
+ const uint8_t *ssid = NULL;
+ size_t ssid_len;
+ bool same_ssid = true;
+ struct scan_bss *bss;
+ bool ignore_flush = false;
+
+ sc = l_queue_find(scan_contexts, scan_context_match, &wdev_id);
+
+ if (!sc)
+ return 0;
+
+ sr = scan_request_new(sc, false, trigger, notify, userdata, destroy);
+
+ freqs = scan_freq_set_new();
+
+ /*
+ * Start building up a frequency list if all SSIDs are the same. This
+ * is hopefully the common case and will allow a single scan command.
+ */
+ for (entry = l_queue_get_entries(list); entry; entry = entry->next) {
+ bss = entry->data;
+
+ scan_freq_set_add(freqs, bss->frequency);
+
+ /* First */
+ if (!ssid) {
+ ssid = bss->owe_trans_ssid;
+ ssid_len = bss->owe_trans_ssid_len;
+ continue;
+ }
+
+ if (ssid_len == bss->owe_trans_ssid_len &&
+ !memcmp(ssid, bss->owe_trans_ssid,
+ bss->owe_trans_ssid_len))
+ continue;
+
+ same_ssid = false;
+ break;
+ }
+
+ if (same_ssid) {
+ bss = l_queue_peek_head(list);
+
+ add_owe_scan_cmd(sc, sr, ignore_flush, freqs, bss);
+
+ scan_freq_set_free(freqs);
+
+ goto done;
+ }
+
+ scan_freq_set_free(freqs);
+
+ /* SSIDs differed, use separate scan commands. */
+ for (entry = l_queue_get_entries(list); entry; entry = entry->next) {
+ bss = entry->data;
+
+ add_owe_scan_cmd(sc, sr, ignore_flush, NULL, bss);
+
+ /* Ignore flush on all subsequent commands */
+ if (!ignore_flush)
+ ignore_flush = true;
+ }
+
+done:
+ l_queue_push_tail(sc->requests, sr);
+
+ return wiphy_radio_work_insert(sc->wiphy, &sr->work, 2, &work_ops);
+}
+
bool scan_cancel(uint64_t wdev_id, uint32_t id)
{
struct scan_context *sc;
diff --git a/src/scan.h b/src/scan.h
index 99c66bb8..8f481f10 100644
--- a/src/scan.h
+++ b/src/scan.h
@@ -147,6 +147,9 @@ uint32_t scan_active_full(uint64_t wdev_id,
const struct scan_parameters *params,
scan_trigger_func_t trigger, scan_notify_func_t notify,
void *userdata, scan_destroy_func_t destroy);
+uint32_t scan_owe_hidden(uint64_t wdev_id, struct l_queue *list,
+ scan_trigger_func_t trigger, scan_notify_func_t notify,
+ void *userdata, scan_destroy_func_t destroy);
bool scan_cancel(uint64_t wdev_id, uint32_t id);
void scan_periodic_start(uint64_t wdev_id, scan_trigger_func_t trigger,
--
2.31.1
8 months
[PATCH v6 1/5] scan: add scan API specifically for OWE transition networks
by James Prestwood
Specifically OWE networks with multiple open/hidden BSS's are troublesome
to scan for with the current APIs. The scan parameters are limited to a
single SSID and even if that was changed we have the potential of hitting
the max SSID's per scan limit. In all, it puts the burden onto the caller
to sort out the SSIDs/frequencies to scan for.
Rather than requiring station to handle this a new scan API was added,
scan_owe_hidden() which takes a list of open BSS's and will automatically
scan for the SSIDs in the OWE transition IE for each.
It is slightly optimized to first check if all the hidden SSID's are the
same. This is the most likely case (e.g. single pair or single network)
and a single scan command can be used. Otherwise individual scan commands
are queued for each SSID/frequency combo.
---
src/scan.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++---
src/scan.h | 3 ++
2 files changed, 134 insertions(+), 8 deletions(-)
diff --git a/src/scan.c b/src/scan.c
index b2f199e5..7d6e46e9 100644
--- a/src/scan.c
+++ b/src/scan.c
@@ -583,6 +583,27 @@ static const struct wiphy_radio_work_item_ops work_ops = {
.destroy = scan_request_free,
};
+static struct scan_request *scan_request_new(struct scan_context *sc,
+ bool passive,
+ scan_trigger_func_t trigger,
+ scan_notify_func_t notify,
+ void *userdata,
+ scan_destroy_func_t destroy)
+{
+ struct scan_request *sr;
+
+ sr = l_new(struct scan_request, 1);
+ sr->sc = sc;
+ sr->trigger = trigger;
+ sr->callback = notify;
+ sr->userdata = userdata;
+ sr->destroy = destroy;
+ sr->passive = passive;
+ sr->cmds = l_queue_new();
+
+ return sr;
+}
+
static uint32_t scan_common(uint64_t wdev_id, bool passive,
const struct scan_parameters *params,
scan_trigger_func_t trigger,
@@ -597,14 +618,7 @@ static uint32_t scan_common(uint64_t wdev_id, bool passive,
if (!sc)
return 0;
- sr = l_new(struct scan_request, 1);
- sr->sc = sc;
- sr->trigger = trigger;
- sr->callback = notify;
- sr->userdata = userdata;
- sr->destroy = destroy;
- sr->passive = passive;
- sr->cmds = l_queue_new();
+ sr = scan_request_new(sc, passive, trigger, notify, userdata, destroy);
scan_cmds_add(sr->cmds, sc, passive, params);
@@ -656,6 +670,115 @@ uint32_t scan_active_full(uint64_t wdev_id,
trigger, notify, userdata, destroy);
}
+static void add_owe_scan_cmd(struct scan_context *sc, struct scan_request *sr,
+ bool ignore_flush,
+ struct scan_freq_set *freqs,
+ const struct scan_bss *bss)
+{
+ struct l_genl_msg *cmd;
+ struct scan_parameters params = {};
+ struct scan_freq_set *tmp;
+
+ if (!freqs) {
+ tmp = scan_freq_set_new();
+ scan_freq_set_add(tmp, bss->frequency);
+ params.freqs = tmp;
+ } else
+ params.freqs = freqs;
+
+ params.ssid = bss->owe_trans_ssid;
+ params.ssid_len = bss->owe_trans_ssid_len;
+ params.flush = true;
+
+ cmd = scan_build_cmd(sc, ignore_flush, false, ¶ms);
+
+ l_genl_msg_enter_nested(cmd, NL80211_ATTR_SCAN_SSIDS);
+ l_genl_msg_append_attr(cmd, 0, params.ssid_len, params.ssid);
+ l_genl_msg_leave_nested(cmd);
+
+ l_queue_push_tail(sr->cmds, cmd);
+
+ if (!freqs)
+ scan_freq_set_free(tmp);
+}
+
+uint32_t scan_owe_hidden(uint64_t wdev_id, struct l_queue *list,
+ scan_trigger_func_t trigger, scan_notify_func_t notify,
+ void *userdata, scan_destroy_func_t destroy)
+{
+ struct scan_context *sc;
+ struct scan_request *sr;
+ struct scan_freq_set *freqs;
+ const struct l_queue_entry *entry;
+ const uint8_t *ssid = NULL;
+ size_t ssid_len;
+ bool same_ssid = true;
+ struct scan_bss *bss;
+ bool ignore_flush = false;
+
+ sc = l_queue_find(scan_contexts, scan_context_match, &wdev_id);
+
+ if (!sc)
+ return 0;
+
+ sr = scan_request_new(sc, false, trigger, notify, userdata, destroy);
+
+ freqs = scan_freq_set_new();
+
+ /*
+ * Start building up a frequency list if all SSIDs are the same. This
+ * is hopefully the common case and will allow a single scan command.
+ */
+ for (entry = l_queue_get_entries(list); entry; entry = entry->next) {
+ bss = entry->data;
+
+ scan_freq_set_add(freqs, bss->frequency);
+
+ /* First */
+ if (!ssid) {
+ ssid = bss->owe_trans_ssid;
+ ssid_len = bss->owe_trans_ssid_len;
+ continue;
+ }
+
+ if (ssid_len == bss->owe_trans_ssid_len &&
+ !memcmp(ssid, bss->owe_trans_ssid,
+ bss->owe_trans_ssid_len))
+ continue;
+
+ same_ssid = false;
+ break;
+ }
+
+ if (same_ssid) {
+ bss = l_queue_peek_head(list);
+
+ add_owe_scan_cmd(sc, sr, ignore_flush, freqs, bss);
+
+ scan_freq_set_free(freqs);
+
+ goto done;
+ }
+
+ scan_freq_set_free(freqs);
+
+ /* SSIDs differed, use separate scan commands. */
+ for (entry = l_queue_get_entries(list); entry; entry = entry->next) {
+ bss = entry->data;
+
+ add_owe_scan_cmd(sc, sr, ignore_flush, NULL, bss);
+
+ /* Ignore flush on all subsequent commands */
+ if (!ignore_flush)
+ ignore_flush = true;
+ }
+
+done:
+ l_queue_push_tail(sc->requests, sr);
+
+ return wiphy_radio_work_insert(sc->wiphy, &sr->work, 2, &work_ops);
+}
+
bool scan_cancel(uint64_t wdev_id, uint32_t id)
{
struct scan_context *sc;
diff --git a/src/scan.h b/src/scan.h
index 99c66bb8..8f481f10 100644
--- a/src/scan.h
+++ b/src/scan.h
@@ -147,6 +147,9 @@ uint32_t scan_active_full(uint64_t wdev_id,
const struct scan_parameters *params,
scan_trigger_func_t trigger, scan_notify_func_t notify,
void *userdata, scan_destroy_func_t destroy);
+uint32_t scan_owe_hidden(uint64_t wdev_id, struct l_queue *list,
+ scan_trigger_func_t trigger, scan_notify_func_t notify,
+ void *userdata, scan_destroy_func_t destroy);
bool scan_cancel(uint64_t wdev_id, uint32_t id);
void scan_periodic_start(uint64_t wdev_id, scan_trigger_func_t trigger,
--
2.31.1
8 months
[PATCH v5 1/4] scan: add scan API specifically for OWE transition networks
by James Prestwood
Specifically OWE networks with multiple open/hidden BSS's are troublesome
to scan for with the current APIs. The scan parameters are limited to a
single SSID and even if that was changed we have the potential of hitting
the max SSID's per scan limit. In all, it puts the burden onto the caller
to sort out the SSIDs/frequencies to scan for.
Rather than requiring station to handle this a new scan API was added,
scan_owe_hidden() which takes a list of open BSS's and will automatically
scan for the SSIDs in the OWE transition IE for each.
It is slightly optimized to first check if all the hidden SSID's are the
same. This is the most likely case (e.g. single pair or single network)
and a single scan command can be used. Otherwise individual scan commands
are queued for each SSID/frequency combo.
---
src/scan.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++---
src/scan.h | 3 ++
2 files changed, 134 insertions(+), 8 deletions(-)
diff --git a/src/scan.c b/src/scan.c
index b2f199e5..b9978a7c 100644
--- a/src/scan.c
+++ b/src/scan.c
@@ -583,6 +583,27 @@ static const struct wiphy_radio_work_item_ops work_ops = {
.destroy = scan_request_free,
};
+static struct scan_request *scan_request_new(struct scan_context *sc,
+ bool passive,
+ scan_trigger_func_t trigger,
+ scan_notify_func_t notify,
+ void *userdata,
+ scan_destroy_func_t destroy)
+{
+ struct scan_request *sr;
+
+ sr = l_new(struct scan_request, 1);
+ sr->sc = sc;
+ sr->trigger = trigger;
+ sr->callback = notify;
+ sr->userdata = userdata;
+ sr->destroy = destroy;
+ sr->passive = passive;
+ sr->cmds = l_queue_new();
+
+ return sr;
+}
+
static uint32_t scan_common(uint64_t wdev_id, bool passive,
const struct scan_parameters *params,
scan_trigger_func_t trigger,
@@ -597,14 +618,7 @@ static uint32_t scan_common(uint64_t wdev_id, bool passive,
if (!sc)
return 0;
- sr = l_new(struct scan_request, 1);
- sr->sc = sc;
- sr->trigger = trigger;
- sr->callback = notify;
- sr->userdata = userdata;
- sr->destroy = destroy;
- sr->passive = passive;
- sr->cmds = l_queue_new();
+ sr = scan_request_new(sc, passive, trigger, notify, userdata, destroy);
scan_cmds_add(sr->cmds, sc, passive, params);
@@ -656,6 +670,115 @@ uint32_t scan_active_full(uint64_t wdev_id,
trigger, notify, userdata, destroy);
}
+static void add_owe_scan_cmd(struct scan_context *sc, struct scan_request *sr,
+ bool ignore_flush,
+ struct scan_freq_set *freqs,
+ const struct scan_bss *bss)
+{
+ struct l_genl_msg *cmd;
+ struct scan_parameters params = {};
+ struct scan_freq_set *tmp;
+
+ if (!freqs) {
+ tmp = scan_freq_set_new();
+ scan_freq_set_add(tmp, bss->frequency);
+ params.freqs = tmp;
+ } else
+ params.freqs = freqs;
+
+ params.ssid = bss->owe_trans_ssid;
+ params.ssid_len = bss->owe_trans_ssid_len;
+ params.flush = true;
+
+ cmd = scan_build_cmd(sc, ignore_flush, false, ¶ms);
+
+ l_genl_msg_enter_nested(cmd, NL80211_ATTR_SCAN_SSIDS);
+ l_genl_msg_append_attr(cmd, 0, params.ssid_len, params.ssid);
+ l_genl_msg_leave_nested(cmd);
+
+ l_queue_push_tail(sr->cmds, cmd);
+
+ if (!freqs)
+ scan_freq_set_free(tmp);
+}
+
+uint32_t scan_owe_hidden(uint64_t wdev_id, struct l_queue *list,
+ scan_trigger_func_t trigger, scan_notify_func_t notify,
+ void *userdata, scan_destroy_func_t destroy)
+{
+ struct scan_context *sc;
+ struct scan_request *sr;
+ struct scan_freq_set *freqs;
+ const struct l_queue_entry *entry;
+ const uint8_t *ssid = NULL;
+ size_t ssid_len;
+ bool same_ssid = true;
+ const struct scan_bss *bss;
+ bool ignore_flush = false;
+
+ sc = l_queue_find(scan_contexts, scan_context_match, &wdev_id);
+
+ if (!sc)
+ return 0;
+
+ sr = scan_request_new(sc, false, trigger, notify, userdata, destroy);
+
+ freqs = scan_freq_set_new();
+
+ /*
+ * Start building up a frequency list if all SSIDs are the same. This
+ * is hopefully the common case and will allow a single scan command.
+ */
+ for (entry = l_queue_get_entries(list); entry; entry = entry->next) {
+ struct scan_bss *bss = entry->data;
+
+ scan_freq_set_add(freqs, bss->frequency);
+
+ /* First */
+ if (!ssid) {
+ ssid = bss->owe_trans_ssid;
+ ssid_len = bss->owe_trans_ssid_len;
+ continue;
+ }
+
+ if (ssid_len == bss->owe_trans_ssid_len &&
+ !memcmp(ssid, bss->owe_trans_ssid,
+ bss->owe_trans_ssid_len))
+ continue;
+
+ same_ssid = false;
+ break;
+ }
+
+ if (same_ssid) {
+ bss = l_queue_peek_head(list);
+
+ add_owe_scan_cmd(sc, sr, ignore_flush, freqs, bss);
+
+ scan_freq_set_free(freqs);
+
+ goto done;
+ }
+
+ scan_freq_set_free(freqs);
+
+ /* SSIDs differed, use separate scan commands. */
+ for (entry = l_queue_get_entries(list); entry; entry = entry->next) {
+ struct scan_bss *bss = entry->data;
+
+ add_owe_scan_cmd(sc, sr, ignore_flush, NULL, bss);
+
+ /* Ignore flush on all subsequent commands */
+ if (!ignore_flush)
+ ignore_flush = true;
+ }
+
+done:
+ l_queue_push_tail(sc->requests, sr);
+
+ return wiphy_radio_work_insert(sc->wiphy, &sr->work, 2, &work_ops);
+}
+
bool scan_cancel(uint64_t wdev_id, uint32_t id)
{
struct scan_context *sc;
diff --git a/src/scan.h b/src/scan.h
index 99c66bb8..8f481f10 100644
--- a/src/scan.h
+++ b/src/scan.h
@@ -147,6 +147,9 @@ uint32_t scan_active_full(uint64_t wdev_id,
const struct scan_parameters *params,
scan_trigger_func_t trigger, scan_notify_func_t notify,
void *userdata, scan_destroy_func_t destroy);
+uint32_t scan_owe_hidden(uint64_t wdev_id, struct l_queue *list,
+ scan_trigger_func_t trigger, scan_notify_func_t notify,
+ void *userdata, scan_destroy_func_t destroy);
bool scan_cancel(uint64_t wdev_id, uint32_t id);
void scan_periodic_start(uint64_t wdev_id, scan_trigger_func_t trigger,
--
2.31.1
8 months
[PATCH v4 1/3] station: handle OWE Transition procedure
by James Prestwood
OWE Transition is described in the WiFi Alliance OWE Specification
version 1.1. The idea behind it is to support both legacy devices
without any concept of OWE as well as modern ones which support the
OWE protocol.
OWE is a somewhat special type of network. Where it advertises an
RSN element but is still "open". This apparently confuses older
devices so the OWE transition procedure was created.
The idea is simple: have two BSS's, one open, and one as a hidden
OWE network. Each network advertises a vendor IE which points to the
other. A device sees the open network and can connect (legacy) or
parse the IE, scan for the hidden OWE network, and connect to that
instead.
Care was taken to handle connections to hidden networks directly.
The policy is being set that any hidden network with the WFA OWE IE
is not connectable via ConnectHiddenNetwork(). These networks are
special, and can only be connected to via the network object for
the paired open network.
When scan results come in from any source (DBus, quick, autoconnect)
each BSS is checked for the OWE Transition IE. A few paths can be
taken here when the IE is found:
1. The BSS is open. The BSSID in the IE is checked against the
current scan results (excluding hidden networks). If a match is
found we should already have the hidden OWE BSS and nothing
else needs to be done (3).
2. The BSS is open. The BSSID in the IE is not found in the
current scan results, and the open network also has no OWE BSS
in it. Add this network to a list to scan for the hidden OWE
BSS.
3. The BSS is not open and contains the OWE IE. This BSS will
automatically get added to the network object and nothing else
needs to be done.
After processing and networks added to this hidden OWE scan list
are processed. Each network should contain a single open BSS with
the OWE IE. The SSID from the IEs are added to the scan parameters
and the scan is started.
The scan results should contain only the (previously hidden) OWE
BSS's. These BSS's should contain the OWE IE which is used to look
up the original open networks. If found the OWE BSS's are added to
their respective networks.
From here network.c can detect that this is an OWE transition
network and connect to the OWE BSS rather than the open one.
---
src/station.c | 354 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 351 insertions(+), 3 deletions(-)
v4:
* Added logic for handling multiple OWE BSS's with the same
and different hidden SSIDs.
diff --git a/src/station.c b/src/station.c
index 2bd9ecfe..be8f49c3 100644
--- a/src/station.c
+++ b/src/station.c
@@ -87,6 +87,8 @@ struct station {
uint32_t dbus_scan_id;
uint32_t quick_scan_id;
uint32_t hidden_network_scan_id;
+ uint32_t owe_transition_scan_id;
+ struct l_queue* owe_network_list;
/* Roaming related members */
struct timespec roam_min_time;
@@ -361,6 +363,44 @@ static struct network *station_add_seen_bss(struct station *station,
if (station_parse_bss_security(station, bss, &security) < 0)
return NULL;
+ /* Hidden OWE transition network */
+ if (security == SECURITY_NONE && bss->rsne &&
+ !l_memeqzero(bss->owe_trans_bssid, 6)) {
+ /*
+ * WiFi Alliance OWE Specification v1.1 - Section 2.2.1:
+ *
+ * "2. An OWE AP shall use two different SSIDs, one for OWE
+ * and one for Open"
+ *
+ * "4. The OWE BSS shall include the OWE Transition Mode element
+ * in all Beacon and Probe Response frames to encapsulate
+ * the BSSID and SSID of the Open BSS"
+ *
+ * Meaning the hidden SSID should not match the SSID in the
+ * hidden network's OWE IE. Might as well restrict BSSID as well
+ * to be safe.
+ *
+ * In addition this SSID must be a valid utf8 string otherwise
+ * we could not look up the network. Note that this is not true
+ * for the open BSS IE, it can be non-utf8.
+ */
+ if (!util_ssid_is_utf8(bss->owe_trans_ssid_len,
+ bss->owe_trans_ssid))
+ return NULL;
+
+ if (!memcmp(bss->owe_trans_ssid, bss->ssid, bss->ssid_len))
+ return NULL;
+
+ if (!memcmp(bss->owe_trans_bssid, bss->addr, 6))
+ return NULL;
+
+ memcpy(ssid, bss->owe_trans_ssid, sizeof(bss->owe_trans_ssid));
+ ssid[bss->owe_trans_ssid_len] = '\0';
+
+ l_debug("Found hidden OWE network, using %s for network lookup",
+ ssid);
+ }
+
path = iwd_network_get_path(station, ssid, security);
network = l_hashmap_lookup(station->networks, path);
@@ -625,6 +665,168 @@ static bool station_start_anqp(struct station *station, struct network *network,
return true;
}
+static int station_owe_scan(struct station *station, struct network *network);
+
+static bool station_owe_transition_results(int err, struct l_queue *bss_list,
+ const struct scan_freq_set *freqs,
+ void *userdata)
+{
+ struct station *station = userdata;
+ struct network *network = l_queue_peek_head(station->owe_network_list);
+ struct scan_bss *bss;
+
+ station->owe_transition_scan_id = 0;
+
+ station_property_set_scanning(station, false);
+
+ if (err)
+ return err == 0;
+
+ /*
+ * Insert all BSS's into station/network BSS list but don't create a
+ * network for them. The idea here is for the user to connect to the
+ * open network and IWD will transition them to the OWE network
+ * automatically.
+ */
+ while ((bss = l_queue_pop_head(bss_list))) {
+ struct scan_bss *open;
+
+ /*
+ * Don't parse the open BSS, hidden BSS, or BSS with
+ * no OWE Transition IE
+ */
+ if (!bss->rsne || l_memeqzero(bss->owe_trans_bssid, 6) ||
+ util_ssid_is_hidden(bss->ssid_len, bss->ssid))
+ goto free;
+
+ /* Check if the Open network IE matches the BSS we have */
+ open = network_bss_find_by_addr(network, bss->owe_trans_bssid);
+ if (!open)
+ goto free;
+
+ if (memcmp(open->owe_trans_bssid, bss->addr, 6)) {
+ l_warn("BSS in results did not match Open OWE IE!");
+ goto free;
+ }
+
+ l_debug("Adding OWE transition network "MAC" to %s",
+ MAC_STR(bss->addr), network_get_ssid(network));
+
+ l_queue_push_tail(station->bss_list, bss);
+ network_bss_add(network, bss);
+
+ continue;
+
+free:
+ scan_bss_free(bss);
+ }
+
+ l_queue_destroy(bss_list, NULL);
+
+ return true;
+}
+
+static void station_owe_transition_triggered(int err, void *user_data)
+{
+ struct station *station = user_data;
+
+ if (err < 0) {
+ l_debug("OWE transition scan trigger failed: %i", err);
+ return;
+ }
+
+ l_debug("OWE transition scan triggered");
+
+ station_property_set_scanning(station, true);
+}
+
+static bool network_match_ssid(const void *a, const void *b)
+{
+ const struct network *network = a;
+
+ return !strcmp(network_get_ssid(network), (const char *)b);
+}
+
+static void station_notify_network(struct station *station,
+ struct network *network)
+{
+ /*
+ * If this network still exists in the list (duplicate) don't notify
+ * yet since we may need to scan more.
+ */
+ if (!l_queue_find(station->owe_network_list, network_match_ssid,
+ network_get_ssid(network)))
+ WATCHLIST_NOTIFY(&event_watches, station_event_watch_func_t,
+ STATION_EVENT_OWE_HIDDEN_FINISHED,
+ network);
+}
+
+/*
+ * Handling multiple BSS pairs (open/OWE) per network gets a bit nasty if the
+ * hidden BSS's also have the same SSID. In this case only one scan needs to be
+ * triggered but detecting this gets complicated trying to do so in
+ * station_set_scan_results. Further we only want to notify these networks once
+ * rather than for each scan_bss we find (this is also true for OWE BSS with
+ * different SSIDs).
+ *
+ * Its somewhat easier sorting this out here because we can detect this case by
+ * the presense of duplicate network objects in the queue in addition to the
+ * logic in station_owe_scan which will return -EALREADY if there is no scan
+ * needed.
+ *
+ * We first pop/save save off the network associated with this current scan
+ * destructor. Then move onto the next and attempt to scan. Both for a scanning
+ * error and -EALREADY nothing else needs to be done, just pop, notify if needed
+ * and continue to the next. On a successful scan set the scan ID, notify, and
+ * wait for the next scan results.
+ */
+static void station_owe_transition_destroy(void *userdata)
+{
+ struct station *station = userdata;
+ struct network *last = l_queue_pop_head(station->owe_network_list);
+ struct network *network = l_queue_peek_head(station->owe_network_list);
+ int ret;
+
+ while (network) {
+ ret = station_owe_scan(station, network);
+ /*
+ * Error, or this network already has its hidden OWE BSS's. In
+ * This case pop this network, notify, and move onto the next.
+ */
+ if (ret == -EALREADY || ret == 0) {
+ l_queue_pop_head(station->owe_network_list);
+
+ /* The 'last' network gets notified below */
+ if (network != last)
+ station_notify_network(station, network);
+
+ network = l_queue_peek_head(station->owe_network_list);
+ continue;
+ }
+
+ station->owe_transition_scan_id = ret;
+
+ break;
+ }
+
+ station_notify_network(station, last);
+
+ if (station->owe_transition_scan_id > 0)
+ return;
+
+ /*
+ * Must resume autoconnect here regardless of an error since this logic
+ * was bypassed in station_set_scan_results
+ */
+ l_queue_destroy(station->autoconnect_list, NULL);
+ station->autoconnect_list = l_queue_new();
+
+ if (station_is_autoconnecting(station)) {
+ station_network_foreach(station, network_add_foreach, station);
+ station_autoconnect_next(station);
+ }
+}
+
static bool bss_free_if_ssid_not_utf8(void *data, void *user_data)
{
struct scan_bss *bss = data;
@@ -641,6 +843,132 @@ static bool bss_free_if_ssid_not_utf8(void *data, void *user_data)
return true;
}
+static bool match_bssid_not_hidden(const void *a, const void *b)
+{
+ const struct scan_bss *bss = a;
+ const uint8_t *bssid = b;
+
+ if (util_ssid_is_hidden(bss->ssid_len, bss->ssid))
+ return false;
+
+ return !memcmp(bss->addr, bssid, sizeof(bss->addr));
+}
+
+static int station_owe_scan(struct station *station, struct network *network)
+{
+ unsigned int id;
+ struct scan_freq_set *freqs = NULL;
+ struct scan_parameters params = {
+ .flush = true,
+ };
+ const struct l_queue_entry *entry;
+ struct scan_bss *open = NULL;
+
+ /*
+ * Special case here for networks with multiple Open BSS's. We need to
+ * find any open BSS's which have not yet been scanned for, i.e. they
+ * do not have a paired OWE BSS in the network list.
+ */
+ for (entry = network_bss_list_get_entries(network); entry;
+ entry = entry->next) {
+ struct scan_bss *bss = entry->data;
+
+ if (bss->rsne)
+ continue;
+
+ /* If network already has the OWE BSS */
+ if (network_bss_find_by_addr(network, bss->owe_trans_bssid))
+ continue;
+
+ open = bss;
+ }
+
+ if (!open)
+ return -EALREADY;
+
+ /* TODO: Add support for different channel/band info */
+ freqs = scan_freq_set_new();
+ scan_freq_set_add(freqs, open->frequency);
+
+ params.freqs = freqs;
+ params.ssid = open->owe_trans_ssid;
+ params.ssid_len = open->owe_trans_ssid_len;
+
+ id = scan_active_full(netdev_get_wdev_id(station->netdev),
+ ¶ms, station_owe_transition_triggered,
+ station_owe_transition_results, station,
+ station_owe_transition_destroy);
+
+ scan_freq_set_free(freqs);
+
+ return id;
+}
+
+static bool station_start_owe_scan(struct station *station,
+ struct l_queue *bss_list,
+ struct scan_bss *bss,
+ struct network *network)
+{
+ int ret;
+
+ if (l_memeqzero(bss->owe_trans_bssid, 6))
+ return false;
+
+ /* only want the open networks with WFA OWE IE */
+ if (bss->rsne)
+ return false;
+
+ /* BSS already in network object */
+ if (network_bss_find_by_addr(network, bss->owe_trans_bssid))
+ return false;
+
+ /*
+ * If the BSSID of the Open OWE IE is in the results we
+ * are done. station_add_seen_bss will add this to the
+ * network object.
+ *
+ * This is required if the Open BSS appears first in the
+ * new_bss_list and the OWE network hasn't had a chance
+ * to get added to the network.
+ */
+ if (l_queue_find(bss_list, match_bssid_not_hidden,
+ bss->owe_trans_bssid))
+ return false;
+
+ if (!station->owe_transition_scan_id) {
+ ret = station_owe_scan(station, network);
+ /* Already have the OWE BSS */
+ if (ret == -EALREADY)
+ return false;
+
+ station->owe_transition_scan_id = ret;
+ }
+
+ if (!station->owe_transition_scan_id) {
+ l_error("Could not scan for hidden OWE network %s",
+ util_ssid_to_utf8(bss->owe_trans_ssid_len,
+ bss->owe_trans_ssid));
+ return false;
+ }
+
+ if (!station->owe_network_list)
+ station->owe_network_list = l_queue_new();
+
+ /*
+ * Network may have already been added in the case of multiple Open
+ * BSS's. We do still want to push the network here but only notify
+ * this network once.
+ */
+ if (!l_queue_find(station->owe_network_list, network_match_ssid,
+ network_get_ssid(network)))
+ WATCHLIST_NOTIFY(&event_watches, station_event_watch_func_t,
+ STATION_EVENT_OWE_HIDDEN_STARTED, network);
+
+ l_queue_push_tail(station->owe_network_list, network);
+
+ return true;
+}
+
/*
* Used when scan results were obtained; either from scan running
* inside station module or scans running in other state machines, e.g. wsc
@@ -652,7 +980,7 @@ void station_set_scan_results(struct station *station,
{
const struct l_queue_entry *bss_entry;
struct network *network;
- bool wait_for_anqp = false;
+ bool wait = false;
l_queue_foreach_remove(new_bss_list, bss_free_if_ssid_not_utf8, NULL);
@@ -699,15 +1027,22 @@ void station_set_scan_results(struct station *station,
if (!network)
continue;
+ /* Cached BSS entry, this should be handled already */
+ if (!scan_freq_set_contains(freqs, bss->frequency))
+ continue;
+
if (station_start_anqp(station, network, bss))
- wait_for_anqp = true;
+ wait = true;
+
+ if (station_start_owe_scan(station, new_bss_list, bss, network))
+ wait = true;
}
station->bss_list = new_bss_list;
l_hashmap_foreach_remove(station->networks, process_network, station);
- if (!wait_for_anqp && add_to_autoconnect) {
+ if (!wait && add_to_autoconnect) {
station_network_foreach(station, network_add_foreach, station);
station_autoconnect_next(station);
}
@@ -2812,6 +3147,9 @@ static bool station_hidden_network_scan_results(int err,
memcmp(bss->ssid, ssid, ssid_len))
goto next;
+ if (!l_memeqzero(bss->owe_trans_bssid, 6))
+ goto next;
+
/*
* Override time_stamp so that this entry is removed on
* the next scan
@@ -2905,6 +3243,10 @@ static struct l_dbus_message *station_dbus_connect_hidden_network(
l_queue_get_entries(station->hidden_bss_list_sorted);
struct scan_bss *target = network_bss_select(network, true);
+ /* Treat OWE transition networks special */
+ if (!l_memeqzero(target->owe_trans_bssid, 6))
+ goto not_hidden;
+
for (; entry; entry = entry->next) {
struct scan_bss *bss = entry->data;
@@ -2916,6 +3258,7 @@ static struct l_dbus_message *station_dbus_connect_hidden_network(
message);
}
+not_hidden:
return dbus_error_not_hidden(message);
}
@@ -3677,9 +4020,14 @@ static void station_free(struct station *station)
scan_cancel(netdev_get_wdev_id(station->netdev),
station->hidden_network_scan_id);
+ if (station->owe_transition_scan_id)
+ scan_cancel(netdev_get_wdev_id(station->netdev),
+ station->owe_transition_scan_id);
+
station_roam_state_clear(station);
l_queue_destroy(station->networks_sorted, NULL);
+ l_queue_destroy(station->owe_network_list, NULL);
l_hashmap_destroy(station->networks, network_free);
l_queue_destroy(station->bss_list, bss_free);
l_queue_destroy(station->hidden_bss_list_sorted, NULL);
--
2.31.1
8 months
[PATCH v3 1/7] ie: add ie_parse_owe_transition_from_data
by James Prestwood
This is a parser for the WFA OWE Transition element. For now the
optional band/channel bytes will not be parsed as hostapd does not
yet support these and would also require the 802.11 appendix E-1
to be added to IWD. Because of this OWE Transition networks are
assumed to be on the same channel as their open counterpart.
---
src/ie.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
src/ie.h | 5 +++++
2 files changed, 50 insertions(+)
v3:
* Changed to handle non-utf8 SSIDs
diff --git a/src/ie.c b/src/ie.c
index 1ce1d8a5..3b4564b2 100644
--- a/src/ie.c
+++ b/src/ie.c
@@ -1343,6 +1343,8 @@ bool is_ie_wfa_ie(const uint8_t *data, uint8_t len, uint8_t oi_type)
return false;
else if (oi_type == IE_WFA_OI_HS20_INDICATION && len != 5 && len != 7)
return false;
+ else if (oi_type == IE_WFA_OI_OWE_TRANSITION && len < 12)
+ return false;
else if (len < 4) /* OI not handled, but at least check length */
return false;
@@ -2492,3 +2494,46 @@ int ie_parse_network_cost(const void *data, size_t len,
*flags = l_get_le16(ie + 8);
return 0;
}
+
+int ie_parse_owe_transition(const void *data, size_t len,
+ uint8_t bssid[static 6],
+ uint8_t ssid[static 32],
+ size_t *ssid_len)
+{
+ const uint8_t *ie = data;
+ size_t slen;
+
+ if (len < 14 || ie[0] != IE_TYPE_VENDOR_SPECIFIC)
+ return -ENOMSG;
+
+ if (!is_ie_wfa_ie(ie + 2, len - 2, IE_WFA_OI_OWE_TRANSITION))
+ return -ENOMSG;
+
+ slen = l_get_u8(ie + 12);
+ if (slen > 32)
+ return -ENOMSG;
+
+ /*
+ * WFA OWE Specification 2.3.1
+ *
+ * "Band Info and Channel Info are optional fields. If configured,
+ * both fields shall be included in an OWE Transition Mode element"
+ *
+ * TODO: Support Band/Channel bytes:
+ * For the time being the OWE transition AP is assumed to be on the same
+ * channel as the open AP. This means there should be no band/channel
+ * bytes at the end of the IE. Currently hostapd has no support for this
+ * so it can be skipped. In addition 802.11 Appendix E-1 needs to be
+ * encoded as a table to map Country/operating class to channels to make
+ * any sense of it.
+ */
+ if (len != slen + 13)
+ return -ENOMSG;
+
+ memcpy(bssid, ie + 6, 6);
+
+ memcpy(ssid, ie + 13, slen);
+ *ssid_len = slen;
+
+ return 0;
+}
diff --git a/src/ie.h b/src/ie.h
index 4e1c5433..6d8fb9ca 100644
--- a/src/ie.h
+++ b/src/ie.h
@@ -630,3 +630,8 @@ void ie_build_fils_ip_addr_response(
int ie_parse_network_cost(const void *data, size_t len,
uint16_t *flags, uint16_t *level);
+
+int ie_parse_owe_transition(const void *data, size_t len,
+ uint8_t bssid[static 6],
+ uint8_t ssid[static 32],
+ size_t *ssid_len);
--
2.31.1
8 months
[PATCH] netconfig: Remove usage of in6_addr.__in6_u
by Andrew Zaborowski
in6_addr.__in6_u.__u6_addr8 is glibc-specific and named differently in
the headers shipped with musl libc for example. The POSIX compliant and
universal way of accessing it is in6_addr.s6_addr.
---
src/netconfig.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/netconfig.c b/src/netconfig.c
index ce95db0b..421270c9 100644
--- a/src/netconfig.c
+++ b/src/netconfig.c
@@ -171,7 +171,7 @@ static inline char *netconfig_ipv6_to_string(const uint8_t *addr)
struct in6_addr in6_addr;
char *addr_str = l_malloc(INET6_ADDRSTRLEN);
- memcpy(in6_addr.__in6_u.__u6_addr8, addr, 16);
+ memcpy(in6_addr.s6_addr, addr, 16);
if (L_WARN_ON(unlikely(!inet_ntop(AF_INET6, &in6_addr, addr_str,
INET6_ADDRSTRLEN)))) {
--
2.30.2
8 months
[PATCH v2 1/7] ie: add ie_parse_owe_transition_from_data
by James Prestwood
This is a parser for the WFA OWE Transition element. For now the
optional band/channel bytes will not be parsed as hostapd does not
yet support these and would also require the 802.11 appendix E-1
to be added to IWD. Because of this OWE Transition networks are
assumed to be on the same channel as their open counterpart.
---
src/ie.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
src/ie.h | 4 ++++
2 files changed, 48 insertions(+)
v2:
* Changed to [static #] to enforce length
diff --git a/src/ie.c b/src/ie.c
index 1ce1d8a5..7f5b33e5 100644
--- a/src/ie.c
+++ b/src/ie.c
@@ -1343,6 +1343,8 @@ bool is_ie_wfa_ie(const uint8_t *data, uint8_t len, uint8_t oi_type)
return false;
else if (oi_type == IE_WFA_OI_HS20_INDICATION && len != 5 && len != 7)
return false;
+ else if (oi_type == IE_WFA_OI_OWE_TRANSITION && len < 12)
+ return false;
else if (len < 4) /* OI not handled, but at least check length */
return false;
@@ -2492,3 +2494,45 @@ int ie_parse_network_cost(const void *data, size_t len,
*flags = l_get_le16(ie + 8);
return 0;
}
+
+int ie_parse_owe_transition(const void *data, size_t len,
+ uint8_t bssid[static 6],
+ char ssid[static 33])
+{
+ const uint8_t *ie = data;
+ size_t slen;
+
+ if (len < 14 || ie[0] != IE_TYPE_VENDOR_SPECIFIC)
+ return -ENOMSG;
+
+ if (!is_ie_wfa_ie(ie + 2, len - 2, IE_WFA_OI_OWE_TRANSITION))
+ return -ENOMSG;
+
+ slen = l_get_u8(ie + 12);
+ if (slen > 32)
+ return -ENOMSG;
+
+ /*
+ * WFA OWE Specification 2.3.1
+ *
+ * "Band Info and Channel Info are optional fields. If configured,
+ * both fields shall be included in an OWE Transition Mode element"
+ *
+ * TODO: Support Band/Channel bytes:
+ * For the time being the OWE transition AP is assumed to be on the same
+ * channel as the open AP. This means there should be no band/channel
+ * bytes at the end of the IE. Currently hostapd has no support for this
+ * so it can be skipped. In addition 802.11 Appendix E-1 needs to be
+ * encoded as a table to map Country/operating class to channels to make
+ * any sense of it.
+ */
+ if (len != slen + 13)
+ return -ENOMSG;
+
+ memcpy(bssid, ie + 6, 6);
+
+ memcpy(ssid, ie + 13, slen);
+ ssid[slen] = '\0';
+
+ return 0;
+}
diff --git a/src/ie.h b/src/ie.h
index 4e1c5433..830d6de0 100644
--- a/src/ie.h
+++ b/src/ie.h
@@ -630,3 +630,7 @@ void ie_build_fils_ip_addr_response(
int ie_parse_network_cost(const void *data, size_t len,
uint16_t *flags, uint16_t *level);
+
+int ie_parse_owe_transition(const void *data, size_t len,
+ uint8_t bssid[static 6],
+ char ssid[static 33]);
--
2.31.1
8 months
[PATCH 01/13] ie: add WFA OWE Transition element type
by James Prestwood
---
src/ie.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/ie.h b/src/ie.h
index a2fdc2e3..4e1c5433 100644
--- a/src/ie.h
+++ b/src/ie.h
@@ -290,6 +290,7 @@ enum ie_type {
enum ie_vendor_wfa_oi_type {
IE_WFA_OI_HS20_INDICATION = 0x10,
IE_WFA_OI_OSEN = 0x12,
+ IE_WFA_OI_OWE_TRANSITION = 0x1c,
IE_WFA_OI_ROAMING_SELECTION = 0x1d,
};
--
2.31.1
8 months
[PATCH 1/2] doc: Add net.connman.iwd.IPv{4,6}Configuration API doc
by Andrew Zaborowski
---
doc/ip-configuration-api.txt | 47 ++++++++++++++++++++++++++++++++++++
1 file changed, 47 insertions(+)
create mode 100644 doc/ip-configuration-api.txt
diff --git a/doc/ip-configuration-api.txt b/doc/ip-configuration-api.txt
new file mode 100644
index 00000000..58a522de
--- /dev/null
+++ b/doc/ip-configuration-api.txt
@@ -0,0 +1,47 @@
+IP Configuration hierarchy
+===============================
+
+Service net.connman.iwd
+Interface net.connman.iwd.IPv4Configuration [Experimental]
+Interface net.connman.iwd.IPv6Configuration [Experimental]
+Object path /net/connman/iwd/{phy0,phy1,...}/{1,2,...}
+Object path /net/connman/iwd/{phy0,phy1,...}/p2p_peers/{aa_bb_cc_dd_ee_ff}
+
+The interfaces net.connman.iwd.IPv4Configuration and
+net.connman.iwd.IPv6Configuration currently have the same sets of methods,
+signals and properties. In station mode, when network configuration is
+enabled there may be one or both interfaces present on a device object in
+connected state depending on if IPv4 and IPv6 addresses have both been
+configured. In P2P mode only net.connman.iwd.IPv4Configuration is used.
+
+Properties string Method [readonly]
+
+ Indicates whether the local address was set
+ statically (value "static") or obtained automatically
+ such as through DHCP (value "auto"). Even when the
+ address was obtained from the remote end some
+ configuration bits, such as DNS addresses, may have
+ been overridden locally.
+
+ string Address [readonly]
+
+ Holds the local IP address.
+
+ byte PrefixLength [readonly]
+
+ Holds the prefix-length of the local subnet. For
+ IPv4 this maps to the netmask.
+
+ string Gateway [readonly, optional]
+
+ Holds the gateway address for the subnet if one
+ exists.
+
+ array(string) DomainNameServers [readonly, optional]
+
+ Holds the list of domain name server addresses
+ configured if any.
+
+ array(string) DomainNames [readonly, optional]
+
+ Holds the network's local domain names if any exist.
--
2.30.2
8 months