All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 01/11] station: factor out logic for choosing FT
@ 2021-05-12 23:01 James Prestwood
  2021-05-12 23:01 ` [PATCH v3 02/11] station: remove ap_directed_roam check for over-DS James Prestwood
                   ` (10 more replies)
  0 siblings, 11 replies; 12+ messages in thread
From: James Prestwood @ 2021-05-12 23:01 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 1778 bytes --]

---
 src/station.c | 25 +++++++++++++++++++------
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/src/station.c b/src/station.c
index 479f81f5..bdb8859a 100644
--- a/src/station.c
+++ b/src/station.c
@@ -1823,13 +1823,30 @@ static void station_preauthenticate_cb(struct netdev *netdev,
 	station_transition_reassociate(station, bss, new_hs);
 }
 
+static bool station_can_fast_transition(struct handshake_state *hs,
+					struct scan_bss *bss)
+{
+	uint16_t mdid;
+
+	if (!hs->mde)
+		return false;
+
+	if (ie_parse_mobility_domain_from_data(hs->mde, hs->mde[1] + 2,
+						&mdid, NULL, NULL) < 0)
+		return false;
+
+	if (bss->mde_present && l_get_le16(bss->mde) == mdid)
+		return true;
+
+	return false;
+}
+
 static void station_transition_start(struct station *station,
 							struct scan_bss *bss)
 {
 	struct handshake_state *hs = netdev_get_handshake(station->netdev);
 	struct network *connected = station->connected_network;
 	enum security security = network_get_security(connected);
-	uint16_t mdid;
 	struct handshake_state *new_hs;
 	struct ie_rsn_info cur_rsne, target_rsne;
 
@@ -1839,12 +1856,8 @@ static void station_transition_start(struct station *station,
 	/* Reset AP roam flag, at this point the roaming behaves the same */
 	station->ap_directed_roaming = false;
 
-	if (hs->mde)
-		ie_parse_mobility_domain_from_data(hs->mde, hs->mde[1] + 2,
-							&mdid, NULL, NULL);
-
 	/* Can we use Fast Transition? */
-	if (hs->mde && bss->mde_present && l_get_le16(bss->mde) == mdid) {
+	if (station_can_fast_transition(hs, bss)) {
 		/* Rebuild handshake RSN for target AP */
 		if (station_build_handshake_rsn(hs, station->wiphy,
 				station->connected_network, bss) < 0) {
-- 
2.31.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 02/11] station: remove ap_directed_roam check for over-DS
  2021-05-12 23:01 [PATCH v3 01/11] station: factor out logic for choosing FT James Prestwood
@ 2021-05-12 23:01 ` James Prestwood
  2021-05-12 23:01 ` [PATCH v3 03/11] ft: break up FT action parsing into two steps James Prestwood
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: James Prestwood @ 2021-05-12 23:01 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 703 bytes --]

This flag was being checked but it is explicitly being set to
false prior.
---
 src/station.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/station.c b/src/station.c
index bdb8859a..b9368ef2 100644
--- a/src/station.c
+++ b/src/station.c
@@ -1867,8 +1867,7 @@ static void station_transition_start(struct station *station,
 		}
 
 		/* FT-over-DS can be better suited for these situations */
-		if ((hs->mde[4] & 1) && (station->ap_directed_roaming ||
-				station->signal_low)) {
+		if ((hs->mde[4] & 1) && station->signal_low) {
 			if (netdev_fast_transition_over_ds_action(
 					station->netdev, bss,
 					station_fast_transition_ds_cb,
-- 
2.31.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 03/11] ft: break up FT action parsing into two steps
  2021-05-12 23:01 [PATCH v3 01/11] station: factor out logic for choosing FT James Prestwood
  2021-05-12 23:01 ` [PATCH v3 02/11] station: remove ap_directed_roam check for over-DS James Prestwood
@ 2021-05-12 23:01 ` James Prestwood
  2021-05-12 23:01 ` [PATCH v3 04/11] netdev: handle multiple concurrent FT-over-DS action frames James Prestwood
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: James Prestwood @ 2021-05-12 23:01 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 3951 bytes --]

This is to prepare for multiple concurrent FT-over-DS action frames.
A list will be kept in netdev and for lookup reasons it needs to
parse the start of the frame to grab the aa/spa addresses. In this
call the IEs are also returned and passed to the new
ft_over_ds_parse_action_response.

For now the address checks have been moved into netdev, but this will
eventually turn into a queue lookup.
---
 src/ft.c     | 30 ++++++++++++++++++++----------
 src/ft.h     | 10 ++++++++--
 src/netdev.c | 18 ++++++++++++++++--
 3 files changed, 44 insertions(+), 14 deletions(-)

diff --git a/src/ft.c b/src/ft.c
index de754fd8..13733019 100644
--- a/src/ft.c
+++ b/src/ft.c
@@ -452,7 +452,7 @@ static bool mde_equal(const uint8_t *mde1, const uint8_t *mde2)
 	return memcmp(mde1, mde1, mde1[1] + 2) == 0;
 }
 
-static bool ft_over_ds_process_ies(struct ft_ds_info *info,
+bool ft_over_ds_parse_action_ies(struct ft_ds_info *info,
 					struct handshake_state *hs,
 					const uint8_t *ies,
 					size_t ies_len)
@@ -523,11 +523,15 @@ ft_error:
 	return -EBADMSG;
 }
 
-int ft_over_ds_parse_action_response(struct ft_ds_info *info,
-					struct handshake_state *hs,
-					const uint8_t *frame, size_t frame_len)
+int ft_over_ds_parse_action_response(const uint8_t *frame, size_t frame_len,
+					const uint8_t **spa_out,
+					const uint8_t **aa_out,
+					const uint8_t **ies_out,
+					size_t *ies_len)
 {
 	uint16_t status;
+	const uint8_t *aa;
+	const uint8_t *spa;
 
 	if (frame_len < 16)
 		return -EINVAL;
@@ -540,17 +544,23 @@ int ft_over_ds_parse_action_response(struct ft_ds_info *info,
 	if (frame[1] != 2)
 		return -EINVAL;
 
-	if (memcmp(frame + 2, info->spa, 6))
-		return -ENOENT;
-	if (memcmp(frame + 8, info->aa, 6))
-		return -ENOENT;
+	spa = frame + 2;
+	aa = frame + 8;
 
 	status = l_get_le16(frame + 14);
 	if (status != 0)
 		return (int)status;
 
-	if (!ft_over_ds_process_ies(info, hs, frame + 16, frame_len - 16))
-		return -EBADMSG;
+	if (spa_out)
+		*spa_out = spa;
+
+	if (aa_out)
+		*aa_out = aa;
+
+	if (ies_out && ies_len) {
+		*ies_out = frame + 16;
+		*ies_len = frame_len - 16;
+	}
 
 	return 0;
 }
diff --git a/src/ft.h b/src/ft.h
index 3d1cfe30..6167e0d7 100644
--- a/src/ft.h
+++ b/src/ft.h
@@ -47,9 +47,15 @@ bool ft_build_authenticate_ies(struct handshake_state *hs,
 				const uint8_t *new_snonce, uint8_t *buf,
 				size_t *len);
 
-int ft_over_ds_parse_action_response(struct ft_ds_info *info,
+int ft_over_ds_parse_action_response(const uint8_t *frame, size_t frame_len,
+					const uint8_t **spa_out,
+					const uint8_t **aa_out,
+					const uint8_t **ies_out,
+					size_t *ies_len);
+bool ft_over_ds_parse_action_ies(struct ft_ds_info *info,
 					struct handshake_state *hs,
-					const uint8_t *frame, size_t frame_len);
+					const uint8_t *ies,
+					size_t ies_len);
 
 struct auth_proto *ft_over_air_sm_new(struct handshake_state *hs,
 				ft_tx_authenticate_func_t tx_auth,
diff --git a/src/netdev.c b/src/netdev.c
index 9e7fc821..65627b9f 100644
--- a/src/netdev.c
+++ b/src/netdev.c
@@ -3769,12 +3769,26 @@ static void netdev_ft_response_frame_event(const struct mmpdu_header *hdr,
 	struct netdev_ft_over_ds_info *info = netdev->ft_ds_info;
 	int ret;
 	uint16_t status_code = MMPDU_STATUS_CODE_UNSPECIFIED;
+	const uint8_t *aa;
+	const uint8_t *spa;
+	const uint8_t *ies;
+	size_t ies_len;
 
 	if (!info)
 		return;
 
-	ret = ft_over_ds_parse_action_response(&info->super, netdev->handshake,
-						body, body_len);
+	ret = ft_over_ds_parse_action_response(body, body_len, &spa, &aa,
+						&ies, &ies_len);
+	if (ret != 0)
+		return;
+
+	if (memcmp(spa, info->super.spa, 6))
+		return;
+	if (memcmp(aa, info->super.aa, 6))
+		return;
+
+	ret = ft_over_ds_parse_action_ies(&info->super, netdev->handshake,
+						ies, ies_len);
 	if (ret < 0)
 		return;
 
-- 
2.31.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 04/11] netdev: handle multiple concurrent FT-over-DS action frames
  2021-05-12 23:01 [PATCH v3 01/11] station: factor out logic for choosing FT James Prestwood
  2021-05-12 23:01 ` [PATCH v3 02/11] station: remove ap_directed_roam check for over-DS James Prestwood
  2021-05-12 23:01 ` [PATCH v3 03/11] ft: break up FT action parsing into two steps James Prestwood
@ 2021-05-12 23:01 ` James Prestwood
  2021-05-12 23:01 ` [PATCH v3 05/11] network: add network_bss_list_get_entries James Prestwood
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: James Prestwood @ 2021-05-12 23:01 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 7261 bytes --]

The beauty of FT-over-DS is that a station can send and receive
action frames to many APs to prepare for a future roam. Each
AP authenticates the station and when a roam happens the station
can immediately move to reassociation.

To handle this a queue of netdev_ft_over_ds_info structs is used
instead of a single entry. Using the new ft.c parser APIs these
info structs can be looked up when responses come in. For now
the timeouts/callbacks are kept but these will be removed as it
really does not matter if the AP sends a response (keeps station
happy until the next patch).
---
 src/netdev.c | 112 ++++++++++++++++++++++++++++++++-------------------
 1 file changed, 71 insertions(+), 41 deletions(-)

diff --git a/src/netdev.c b/src/netdev.c
index 65627b9f..c194e78f 100644
--- a/src/netdev.c
+++ b/src/netdev.c
@@ -169,7 +169,7 @@ struct netdev {
 	struct l_genl_msg *auth_cmd;
 	struct wiphy_radio_work_item work;
 
-	struct netdev_ft_over_ds_info *ft_ds_info;
+	struct l_queue *ft_ds_list;
 
 	bool connected : 1;
 	bool associated : 1;
@@ -687,6 +687,13 @@ static void netdev_preauth_destroy(void *data)
 	l_free(state);
 }
 
+static void netdev_ft_ds_entry_free(void *data)
+{
+	struct netdev_ft_over_ds_info *info = data;
+
+	ft_ds_info_free(&info->super);
+}
+
 static void netdev_connect_free(struct netdev *netdev)
 {
 	if (netdev->work.id)
@@ -754,8 +761,10 @@ static void netdev_connect_free(struct netdev *netdev)
 		netdev->disconnect_cmd_id = 0;
 	}
 
-	if (netdev->ft_ds_info)
-		ft_ds_info_free(&netdev->ft_ds_info->super);
+	if (netdev->ft_ds_list) {
+		l_queue_destroy(netdev->ft_ds_list, netdev_ft_ds_entry_free);
+		netdev->ft_ds_list = NULL;
+	}
 }
 
 static void netdev_connect_failed(struct netdev *netdev,
@@ -854,6 +863,11 @@ static void netdev_free(void *data)
 		netdev->disconnect_idle = NULL;
 	}
 
+	if (netdev->ft_ds_list) {
+		l_queue_destroy(netdev->ft_ds_list, netdev_ft_ds_entry_free);
+		netdev->ft_ds_list = NULL;
+	}
+
 	if (netdev->events_ready)
 		WATCHLIST_NOTIFY(&netdev_watches, netdev_watch_func_t,
 					netdev, NETDEV_WATCH_EVENT_DEL);
@@ -1286,6 +1300,11 @@ static void netdev_connect_ok(struct netdev *netdev)
 		netdev->fw_roam_bss = NULL;
 	}
 
+	if (netdev->ft_ds_list) {
+		l_queue_destroy(netdev->ft_ds_list, netdev_ft_ds_entry_free);
+		netdev->ft_ds_list = NULL;
+	}
+
 	if (netdev->connect_cb) {
 		netdev->connect_cb(netdev, NETDEV_RESULT_OK, NULL,
 					netdev->user_data);
@@ -3442,12 +3461,6 @@ int netdev_reassociate(struct netdev *netdev, struct scan_bss *target_bss,
 	if (err < 0)
 		return err;
 
-	/* In case of a previous failed over-DS attempt */
-	if (netdev->ft_ds_info) {
-		ft_ds_info_free(&netdev->ft_ds_info->super);
-		netdev->ft_ds_info = NULL;
-	}
-
 	memcpy(netdev->prev_bssid, orig_bss->addr, ETH_ALEN);
 
 	netdev->associated = false;
@@ -3676,12 +3689,6 @@ static int netdev_ft_tx_associate(struct iovec *ie_iov, size_t iov_len,
 		return -EIO;
 	}
 
-	/* No need to keep this around at this point */
-	if (netdev->ft_ds_info) {
-		ft_ds_info_free(&netdev->ft_ds_info->super);
-		netdev->ft_ds_info = NULL;
-	}
-
 	return 0;
 }
 
@@ -3756,9 +3763,26 @@ static void netdev_ft_over_ds_auth_failed(struct netdev_ft_over_ds_info *info,
 	if (info->cb)
 		info->cb(info->netdev, status, info->super.aa, info->user_data);
 
+	l_queue_remove(info->netdev->ft_ds_list, info);
 	ft_ds_info_free(&info->super);
+}
 
-	info->netdev->ft_ds_info = NULL;
+struct ft_ds_finder {
+	const uint8_t *spa;
+	const uint8_t *aa;
+};
+
+static bool match_ft_ds_info(const void *a, const void *b)
+{
+	const struct netdev_ft_over_ds_info *info = a;
+	const struct ft_ds_finder *finder = b;
+
+	if (memcmp(info->super.spa, finder->spa, 6))
+		return false;
+	if (memcmp(info->super.aa, finder->aa, 6))
+		return false;
+
+	return true;
 }
 
 static void netdev_ft_response_frame_event(const struct mmpdu_header *hdr,
@@ -3766,41 +3790,41 @@ static void netdev_ft_response_frame_event(const struct mmpdu_header *hdr,
 					int rssi, void *user_data)
 {
 	struct netdev *netdev = user_data;
-	struct netdev_ft_over_ds_info *info = netdev->ft_ds_info;
+	struct netdev_ft_over_ds_info *info;
 	int ret;
 	uint16_t status_code = MMPDU_STATUS_CODE_UNSPECIFIED;
 	const uint8_t *aa;
 	const uint8_t *spa;
 	const uint8_t *ies;
 	size_t ies_len;
-
-	if (!info)
-		return;
+	struct ft_ds_finder finder;
 
 	ret = ft_over_ds_parse_action_response(body, body_len, &spa, &aa,
 						&ies, &ies_len);
-	if (ret != 0)
+	if (ret < 0)
 		return;
 
-	if (memcmp(spa, info->super.spa, 6))
-		return;
-	if (memcmp(aa, info->super.aa, 6))
+	finder.spa = spa;
+	finder.aa = aa;
+
+	info = l_queue_find(netdev->ft_ds_list, match_ft_ds_info, &finder);
+	if (!info)
 		return;
 
+	/* Lookup successful, now check the status code */
+	if (ret > 0) {
+		status_code = (uint16_t)ret;
+		goto ft_error;
+	}
+
 	ret = ft_over_ds_parse_action_ies(&info->super, netdev->handshake,
 						ies, ies_len);
 	if (ret < 0)
-		return;
+		goto ft_error;
 
 	l_timeout_remove(info->timeout);
 	info->timeout = NULL;
 
-	/* Now make sure the packet contained a success status code */
-	if (ret > 0) {
-		status_code = (uint16_t)ret;
-		goto ft_error;
-	}
-
 	info->parsed = true;
 
 	if (info->cb)
@@ -3809,7 +3833,8 @@ static void netdev_ft_response_frame_event(const struct mmpdu_header *hdr,
 	return;
 
 ft_error:
-	l_debug("FT-over-DS to "MAC" failed", MAC_STR(info->super.aa));
+	l_debug("FT-over-DS to "MAC" failed (%d)", MAC_STR(info->super.aa),
+			status_code);
 
 	netdev_ft_over_ds_auth_failed(info, status_code);
 }
@@ -3887,10 +3912,8 @@ int netdev_fast_transition_over_ds(struct netdev *netdev,
 					struct scan_bss *target_bss,
 					netdev_connect_cb_t cb)
 {
-	struct netdev_ft_over_ds_info *info = netdev->ft_ds_info;
-
-	if (!info || !info->parsed)
-		return -ENOENT;
+	struct netdev_ft_over_ds_info *info;
+	struct ft_ds_finder finder;
 
 	if (!netdev->operational)
 		return -ENOTCONN;
@@ -3900,6 +3923,14 @@ int netdev_fast_transition_over_ds(struct netdev *netdev,
 			l_get_le16(target_bss->mde))
 		return -EINVAL;
 
+	finder.spa = netdev->addr;
+	finder.aa = target_bss->addr;
+
+	info = l_queue_find(netdev->ft_ds_list, match_ft_ds_info, &finder);
+
+	if (!info || !info->parsed)
+		return -ENOENT;
+
 	prepare_ft(netdev, target_bss);
 
 	ft_over_ds_prepare_handshake(&info->super, netdev->handshake);
@@ -3963,10 +3994,6 @@ int netdev_fast_transition_over_ds_action(struct netdev *netdev,
 	uint8_t buf[512];
 	size_t len;
 
-	/* TODO: Just allow single outstanding action frame for now */
-	if (netdev->ft_ds_info)
-		return -EALREADY;
-
 	if (!netdev->operational)
 		return -ENOTCONN;
 
@@ -4005,7 +4032,10 @@ int netdev_fast_transition_over_ds_action(struct netdev *netdev,
 
 	iovs[2].iov_base = NULL;
 
-	netdev->ft_ds_info = info;
+	if (!netdev->ft_ds_list)
+		netdev->ft_ds_list = l_queue_new();
+
+	l_queue_push_head(netdev->ft_ds_list, info);
 
 	info->timeout = l_timeout_create_ms(300, netdev_ft_over_ds_timeout,
 						info, NULL);
-- 
2.31.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 05/11] network: add network_bss_list_get_entries
  2021-05-12 23:01 [PATCH v3 01/11] station: factor out logic for choosing FT James Prestwood
                   ` (2 preceding siblings ...)
  2021-05-12 23:01 ` [PATCH v3 04/11] netdev: handle multiple concurrent FT-over-DS action frames James Prestwood
@ 2021-05-12 23:01 ` James Prestwood
  2021-05-12 23:01 ` [PATCH v3 06/11] station: send FT-over-DS actions upon connection James Prestwood
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: James Prestwood @ 2021-05-12 23:01 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 1100 bytes --]

Gets the first l_queue_entry in the networks BSS list. Useful
for iterating only a given networks BSS's outside of network.c.
---
 src/network.c | 6 ++++++
 src/network.h | 3 +++
 2 files changed, 9 insertions(+)

diff --git a/src/network.c b/src/network.c
index 5bd57777..9e858663 100644
--- a/src/network.c
+++ b/src/network.c
@@ -761,6 +761,12 @@ bool network_has_erp_identity(struct network *network)
 	return ret;
 }
 
+const struct l_queue_entry *network_bss_list_get_entries(
+						struct network *network)
+{
+	return l_queue_get_entries(network->bss_list);
+}
+
 struct scan_bss *network_bss_select(struct network *network,
 						bool fallback_to_blacklist)
 {
diff --git a/src/network.h b/src/network.h
index 84fc4fba..bd51945f 100644
--- a/src/network.h
+++ b/src/network.h
@@ -81,3 +81,6 @@ const struct iovec *network_get_extra_ies(struct network *network,
 						size_t *num_elems);
 
 bool network_has_erp_identity(struct network *network);
+
+const struct l_queue_entry *network_bss_list_get_entries(
+						struct network *network);
-- 
2.31.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 06/11] station: send FT-over-DS actions upon connection
  2021-05-12 23:01 [PATCH v3 01/11] station: factor out logic for choosing FT James Prestwood
                   ` (3 preceding siblings ...)
  2021-05-12 23:01 ` [PATCH v3 05/11] network: add network_bss_list_get_entries James Prestwood
@ 2021-05-12 23:01 ` James Prestwood
  2021-05-12 23:01 ` [PATCH v3 07/11] netdev: remove callback/userdata/timeout from FT-over-DS action James Prestwood
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: James Prestwood @ 2021-05-12 23:01 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 5633 bytes --]

Roam times can be slightly improved by sending out the FT-over-DS
action frames to any BSS in the mobility domain immediately after
connecting. This preauthenticates IWD to each AP which means
Reassociation can happen right away when a roam is needed.

When a roam is needed station_transition_start will first try
FT-over-DS (if supported) via netdev_fast_transtion_over_ds. The
return is checked and if netdev has no cached entries FT-over-Air
will be used instead.
---
 src/station.c | 109 +++++++++++++++++++++++++++-----------------------
 1 file changed, 60 insertions(+), 49 deletions(-)

v3:
 * Added back check for connected_bss on loop
 * Removed extra check for station_can_fast_transition, and instead
   only check values which were not previously checked
diff --git a/src/station.c b/src/station.c
index b9368ef2..bbd50aee 100644
--- a/src/station.c
+++ b/src/station.c
@@ -1720,45 +1720,6 @@ static bool bss_match_bssid(const void *a, const void *b)
 	return !memcmp(bss->addr, bssid, sizeof(bss->addr));
 }
 
-static void station_fast_transition_ds_cb(struct netdev *netdev,
-					uint16_t status, const uint8_t *bssid,
-					void *user_data)
-{
-	struct station *station = user_data;
-	struct scan_bss *bss;
-
-	if (status != 0)
-		goto failed;
-
-	/*
-	 * TODO: In the future it may be desired to start sending out these
-	 * FT-over-DS action frames at the time of connecting then be able to
-	 * roam immediately when required. If this is being done we can simply
-	 * bail out now as ft already caches the entires. But since this was
-	 * initiated due to a need to roam, do so now.
-	 */
-
-	/* Make sure we still have our BSS */
-	bss = l_queue_find(station->bss_list, bss_match_bssid, bssid);
-	if (!bss)
-		goto failed;
-
-	l_debug("Starting FT-over-DS roam");
-
-	if (netdev_fast_transition_over_ds(station->netdev, bss,
-					station_fast_transition_cb) < 0)
-		goto failed;
-
-	station->connected_bss = bss;
-	station->preparing_roam = false;
-	station_enter_state(station, STATION_STATE_ROAMING);
-
-	return;
-
-failed:
-	station_roam_retry(station);
-}
-
 static void station_preauthenticate_cb(struct netdev *netdev,
 					enum netdev_result result,
 					const uint8_t *pmk, void *user_data)
@@ -1849,6 +1810,7 @@ static void station_transition_start(struct station *station,
 	enum security security = network_get_security(connected);
 	struct handshake_state *new_hs;
 	struct ie_rsn_info cur_rsne, target_rsne;
+	int ret;
 
 	l_debug("%u, target %s", netdev_get_ifindex(station->netdev),
 			util_address_to_string(bss->addr));
@@ -1868,19 +1830,21 @@ static void station_transition_start(struct station *station,
 
 		/* FT-over-DS can be better suited for these situations */
 		if ((hs->mde[4] & 1) && station->signal_low) {
-			if (netdev_fast_transition_over_ds_action(
-					station->netdev, bss,
-					station_fast_transition_ds_cb,
-					station) < 0) {
+			ret = netdev_fast_transition_over_ds(station->netdev,
+					bss, station_fast_transition_cb);
+			/* No action responses from this BSS, try over air */
+			if (ret == -ENOENT)
+				goto try_over_air;
+			else if (ret < 0) {
+				/*
+				 * If we are here FT-over-air will not work
+				 * either (identical checks) so try again later.
+				 */
 				station_roam_retry(station);
+				return;
 			}
-
-			/*
-			 * Set connected_bss/preparing_roam/state only on a
-			 * successful FT-over-DS action frame response
-			 */
-			return;
 		} else {
+try_over_air:
 			if (netdev_fast_transition(station->netdev, bss,
 					station_fast_transition_cb) < 0) {
 				station_roam_failed(station);
@@ -2512,10 +2476,42 @@ static void station_connect_dbus_reply(struct station *station,
 	dbus_pending_reply(&station->connect_pending, reply);
 }
 
+static void station_ft_ds_action_start(struct station *station, uint16_t mdid)
+{
+	const struct l_queue_entry *entry;
+	struct scan_bss *bss;
+	struct ie_rsn_info rsn_info;
+
+	for (entry = network_bss_list_get_entries(station->connected_network);
+						entry; entry = entry->next) {
+		bss = entry->data;
+
+		if (bss == station->connected_bss)
+			continue;
+
+		if (mdid != l_get_le16(bss->mde))
+			continue;
+
+		if (scan_bss_get_rsn_info(bss, &rsn_info) < 0)
+			continue;
+
+		if (!IE_AKM_IS_FT(rsn_info.akm_suites))
+			continue;
+
+		/*
+		* Fire and forget. Netdev will maintain a cache of responses and
+		* when the time comes these can be referenced for a roam
+		*/
+		netdev_fast_transition_over_ds_action(station->netdev, bss,
+							NULL, NULL);
+	}
+}
+
 static void station_connect_cb(struct netdev *netdev, enum netdev_result result,
 					void *event_data, void *user_data)
 {
 	struct station *station = user_data;
+	struct handshake_state *hs = netdev_get_handshake(netdev);
 
 	l_debug("%u, result: %d", netdev_get_ifindex(station->netdev), result);
 
@@ -2566,6 +2562,21 @@ static void station_connect_cb(struct netdev *netdev, enum netdev_result result,
 			l_warn("Could not request neighbor report");
 	}
 
+	/*
+	 * If this network supports FT-over-DS send initial action frames now
+	 * to prepare for future roams.
+	 */
+	if (station_can_fast_transition(hs, station->connected_bss) &&
+						(hs->mde[4] & 1)) {
+		uint16_t mdid;
+
+		if (ie_parse_mobility_domain_from_data(hs->mde, hs->mde[1] + 2,
+						&mdid, NULL, NULL) < 0)
+			return;
+
+		station_ft_ds_action_start(station, mdid);
+	}
+
 	network_connected(station->connected_network);
 
 	if (station->netconfig)
-- 
2.31.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 07/11] netdev: remove callback/userdata/timeout from FT-over-DS action
  2021-05-12 23:01 [PATCH v3 01/11] station: factor out logic for choosing FT James Prestwood
                   ` (4 preceding siblings ...)
  2021-05-12 23:01 ` [PATCH v3 06/11] station: send FT-over-DS actions upon connection James Prestwood
@ 2021-05-12 23:01 ` James Prestwood
  2021-05-12 23:01 ` [PATCH v3 08/11] auto-t: update FT-over-DS test for new behavior James Prestwood
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: James Prestwood @ 2021-05-12 23:01 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 4358 bytes --]

Since netdev maintains the list of FT over DS info structs there is not
any need for station to get callbacks when the initial action frame
is received, or not. This removes the need for the callback handler,
user data, and response timeout.
---
 src/netdev.c  | 38 +-------------------------------------
 src/netdev.h  |  4 +---
 src/station.c |  3 +--
 3 files changed, 3 insertions(+), 42 deletions(-)

diff --git a/src/netdev.c b/src/netdev.c
index c194e78f..55a63dd2 100644
--- a/src/netdev.c
+++ b/src/netdev.c
@@ -95,9 +95,6 @@ struct netdev_handshake_state {
 struct netdev_ft_over_ds_info {
 	struct ft_ds_info super;
 	struct netdev *netdev;
-	struct l_timeout *timeout;
-	netdev_ft_over_ds_cb_t cb;
-	void *user_data;
 
 	bool parsed : 1;
 };
@@ -3760,9 +3757,6 @@ static void prepare_ft(struct netdev *netdev, struct scan_bss *target_bss)
 static void netdev_ft_over_ds_auth_failed(struct netdev_ft_over_ds_info *info,
 						uint16_t status)
 {
-	if (info->cb)
-		info->cb(info->netdev, status, info->super.aa, info->user_data);
-
 	l_queue_remove(info->netdev->ft_ds_list, info);
 	ft_ds_info_free(&info->super);
 }
@@ -3822,14 +3816,8 @@ static void netdev_ft_response_frame_event(const struct mmpdu_header *hdr,
 	if (ret < 0)
 		goto ft_error;
 
-	l_timeout_remove(info->timeout);
-	info->timeout = NULL;
-
 	info->parsed = true;
 
-	if (info->cb)
-		info->cb(netdev, 0, info->super.aa, info->user_data);
-
 	return;
 
 ft_error:
@@ -3958,34 +3946,16 @@ static void netdev_ft_request_cb(struct l_genl_msg *msg, void *user_data)
 	}
 }
 
-static void netdev_ft_over_ds_timeout(struct l_timeout *timeout,
-					void *user_data)
-{
-	struct netdev_ft_over_ds_info *info = user_data;
-
-	l_timeout_remove(info->timeout);
-	info->timeout = NULL;
-
-	l_debug("");
-
-	netdev_ft_over_ds_auth_failed(info, MMPDU_STATUS_CODE_UNSPECIFIED);
-}
-
 static void netdev_ft_ds_info_free(struct ft_ds_info *ft)
 {
 	struct netdev_ft_over_ds_info *info = l_container_of(ft,
 					struct netdev_ft_over_ds_info, super);
 
-	if (info->timeout)
-		l_timeout_remove(info->timeout);
-
 	l_free(info);
 }
 
 int netdev_fast_transition_over_ds_action(struct netdev *netdev,
-					const struct scan_bss *target_bss,
-					netdev_ft_over_ds_cb_t cb,
-					void *user_data)
+					const struct scan_bss *target_bss)
 {
 	struct netdev_ft_over_ds_info *info;
 	uint8_t ft_req[14];
@@ -4013,9 +3983,6 @@ int netdev_fast_transition_over_ds_action(struct netdev *netdev,
 	l_getrandom(info->super.snonce, 32);
 	info->super.free = netdev_ft_ds_info_free;
 
-	info->cb = cb;
-	info->user_data = user_data;
-
 	ft_req[0] = 6; /* FT category */
 	ft_req[1] = 1; /* FT Request action */
 	memcpy(ft_req + 2, netdev->addr, 6);
@@ -4037,9 +4004,6 @@ int netdev_fast_transition_over_ds_action(struct netdev *netdev,
 
 	l_queue_push_head(netdev->ft_ds_list, info);
 
-	info->timeout = l_timeout_create_ms(300, netdev_ft_over_ds_timeout,
-						info, NULL);
-
 	netdev_send_action_framev(netdev, netdev->handshake->aa, iovs, 2,
 					netdev->frequency,
 					netdev_ft_request_cb,
diff --git a/src/netdev.h b/src/netdev.h
index 987504f6..f625957b 100644
--- a/src/netdev.h
+++ b/src/netdev.h
@@ -163,9 +163,7 @@ int netdev_reassociate(struct netdev *netdev, struct scan_bss *target_bss,
 int netdev_fast_transition(struct netdev *netdev, struct scan_bss *target_bss,
 				netdev_connect_cb_t cb);
 int netdev_fast_transition_over_ds_action(struct netdev *netdev,
-					const struct scan_bss *target_bss,
-					netdev_ft_over_ds_cb_t cb,
-					void *user_data);
+					const struct scan_bss *target_bss);
 int netdev_fast_transition_over_ds(struct netdev *netdev,
 					struct scan_bss *target_bss,
 					netdev_connect_cb_t cb);
diff --git a/src/station.c b/src/station.c
index bbd50aee..385bb272 100644
--- a/src/station.c
+++ b/src/station.c
@@ -2502,8 +2502,7 @@ static void station_ft_ds_action_start(struct station *station, uint16_t mdid)
 		* Fire and forget. Netdev will maintain a cache of responses and
 		* when the time comes these can be referenced for a roam
 		*/
-		netdev_fast_transition_over_ds_action(station->netdev, bss,
-							NULL, NULL);
+		netdev_fast_transition_over_ds_action(station->netdev, bss);
 	}
 }
 
-- 
2.31.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 08/11] auto-t: update FT-over-DS test for new behavior
  2021-05-12 23:01 [PATCH v3 01/11] station: factor out logic for choosing FT James Prestwood
                   ` (5 preceding siblings ...)
  2021-05-12 23:01 ` [PATCH v3 07/11] netdev: remove callback/userdata/timeout from FT-over-DS action James Prestwood
@ 2021-05-12 23:01 ` James Prestwood
  2021-05-12 23:01 ` [PATCH v3 09/11] ie: use bitwise compare for IE_AKM_IS_FT James Prestwood
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: James Prestwood @ 2021-05-12 23:01 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 1404 bytes --]

The FT-over-DS procedure now authenticates with multiple BSS's
upon connecting. This causes list_sta() to return our address for
any authenticated APs. It has now been changed to work with this
new behavior, as well as a check that the station fully connected
to the expected AP initially.
---
 autotests/testFT-PSK-over-DS/connection_test.py | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/autotests/testFT-PSK-over-DS/connection_test.py b/autotests/testFT-PSK-over-DS/connection_test.py
index 4c751841..47104b69 100644
--- a/autotests/testFT-PSK-over-DS/connection_test.py
+++ b/autotests/testFT-PSK-over-DS/connection_test.py
@@ -62,8 +62,13 @@ class Test(unittest.TestCase):
         condition = 'obj.state == DeviceState.connected'
         wd.wait_for_object_condition(device, condition)
 
+        self.bss_hostapd[0].wait_for_event('AP-STA-CONNECTED %s' % device.address)
+
+        # list_sta actually reports any authenticated stations. Due to the
+        # nature of FT-over-DS IWD should authenticate to all stations with
+        # the same mobility domain. This means both APs should show our station.
         self.assertTrue(self.bss_hostapd[0].list_sta())
-        self.assertFalse(self.bss_hostapd[1].list_sta())
+        self.assertTrue(self.bss_hostapd[1].list_sta())
 
         wd.unregister_psk_agent(psk_agent)
 
-- 
2.31.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 09/11] ie: use bitwise compare for IE_AKM_IS_FT
  2021-05-12 23:01 [PATCH v3 01/11] station: factor out logic for choosing FT James Prestwood
                   ` (6 preceding siblings ...)
  2021-05-12 23:01 ` [PATCH v3 08/11] auto-t: update FT-over-DS test for new behavior James Prestwood
@ 2021-05-12 23:01 ` James Prestwood
  2021-05-12 23:01 ` [PATCH v3 10/11] station: make station_can_fast_transition more robust James Prestwood
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: James Prestwood @ 2021-05-12 23:01 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 1140 bytes --]

This has the same effect when passing a single AKM value, but also
handles AKM bit fields (e.g. ie_rsn_info->akm_suites)
---
 src/ie.h | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

v3:
 * removed extra newline

diff --git a/src/ie.h b/src/ie.h
index 600cf297..538ca9a8 100644
--- a/src/ie.h
+++ b/src/ie.h
@@ -289,12 +289,12 @@ enum ie_rsn_akm_suite {
 	(akm == IE_RSN_AKM_SUITE_FT_OVER_SAE_SHA256))
 
 #define IE_AKM_IS_FT(akm) \
-	((akm == IE_RSN_AKM_SUITE_FT_OVER_8021X) || \
-	 (akm == IE_RSN_AKM_SUITE_FT_USING_PSK) || \
-	 (akm == IE_RSN_AKM_SUITE_FT_OVER_SAE_SHA256) || \
-	 (akm == IE_RSN_AKM_SUITE_FT_OVER_8021X_SHA384) || \
-	 (akm == IE_RSN_AKM_SUITE_FT_OVER_FILS_SHA256) || \
-	 (akm == IE_RSN_AKM_SUITE_FT_OVER_FILS_SHA384))
+	(akm & (IE_RSN_AKM_SUITE_FT_OVER_8021X | \
+		IE_RSN_AKM_SUITE_FT_USING_PSK | \
+		IE_RSN_AKM_SUITE_FT_OVER_SAE_SHA256 | \
+		IE_RSN_AKM_SUITE_FT_OVER_8021X_SHA384 | \
+		IE_RSN_AKM_SUITE_FT_OVER_FILS_SHA256 | \
+		IE_RSN_AKM_SUITE_FT_OVER_FILS_SHA384))
 
 #define IE_AKM_IS_FILS(akm) \
 	((akm == IE_RSN_AKM_SUITE_FILS_SHA256) || \
-- 
2.31.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 10/11] station: make station_can_fast_transition more robust
  2021-05-12 23:01 [PATCH v3 01/11] station: factor out logic for choosing FT James Prestwood
                   ` (7 preceding siblings ...)
  2021-05-12 23:01 ` [PATCH v3 09/11] ie: use bitwise compare for IE_AKM_IS_FT James Prestwood
@ 2021-05-12 23:01 ` James Prestwood
  2021-05-12 23:01 ` [PATCH v3 11/11] station: use IE_AKM_IS_FT when possible James Prestwood
  2021-05-12 23:07 ` [PATCH v3 01/11] station: factor out logic for choosing FT Denis Kenzior
  10 siblings, 0 replies; 12+ messages in thread
From: James Prestwood @ 2021-05-12 23:01 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 1020 bytes --]

Check that the current handshake is using an FT AKM and that the
target BSS AKM suites contain an FT AKM.
---
 src/station.c | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/src/station.c b/src/station.c
index 385bb272..325121f1 100644
--- a/src/station.c
+++ b/src/station.c
@@ -1796,10 +1796,23 @@ static bool station_can_fast_transition(struct handshake_state *hs,
 						&mdid, NULL, NULL) < 0)
 		return false;
 
-	if (bss->mde_present && l_get_le16(bss->mde) == mdid)
-		return true;
+	if (!(bss->mde_present && l_get_le16(bss->mde) == mdid))
+		return false;
 
-	return false;
+	if (hs->supplicant_ie != NULL) {
+		struct ie_rsn_info rsn_info;
+
+		if (!IE_AKM_IS_FT(hs->akm_suite))
+			return false;
+
+		if (scan_bss_get_rsn_info(bss, &rsn_info) < 0)
+			return false;
+
+		if (!IE_AKM_IS_FT(rsn_info.akm_suites))
+			return false;
+	}
+
+	return true;
 }
 
 static void station_transition_start(struct station *station,
-- 
2.31.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v3 11/11] station: use IE_AKM_IS_FT when possible
  2021-05-12 23:01 [PATCH v3 01/11] station: factor out logic for choosing FT James Prestwood
                   ` (8 preceding siblings ...)
  2021-05-12 23:01 ` [PATCH v3 10/11] station: make station_can_fast_transition more robust James Prestwood
@ 2021-05-12 23:01 ` James Prestwood
  2021-05-12 23:07 ` [PATCH v3 01/11] station: factor out logic for choosing FT Denis Kenzior
  10 siblings, 0 replies; 12+ messages in thread
From: James Prestwood @ 2021-05-12 23:01 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 720 bytes --]

Update a check to use IE_AKM_IS_FT as the condition is identical
to the macro.
---
 src/station.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/src/station.c b/src/station.c
index 325121f1..f64ba675 100644
--- a/src/station.c
+++ b/src/station.c
@@ -865,11 +865,7 @@ build_ie:
 	if (!handshake_state_set_supplicant_ie(hs, rsne_buf))
 		goto not_supported;
 
-	if (info.akm_suites & (IE_RSN_AKM_SUITE_FT_OVER_8021X |
-				IE_RSN_AKM_SUITE_FT_USING_PSK |
-				IE_RSN_AKM_SUITE_FT_OVER_SAE_SHA256 |
-				IE_RSN_AKM_SUITE_FT_OVER_FILS_SHA256 |
-				IE_RSN_AKM_SUITE_FT_OVER_FILS_SHA384))
+	if (IE_AKM_IS_FT(info.akm_suites))
 		add_mde = true;
 
 open_network:
-- 
2.31.1

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v3 01/11] station: factor out logic for choosing FT
  2021-05-12 23:01 [PATCH v3 01/11] station: factor out logic for choosing FT James Prestwood
                   ` (9 preceding siblings ...)
  2021-05-12 23:01 ` [PATCH v3 11/11] station: use IE_AKM_IS_FT when possible James Prestwood
@ 2021-05-12 23:07 ` Denis Kenzior
  10 siblings, 0 replies; 12+ messages in thread
From: Denis Kenzior @ 2021-05-12 23:07 UTC (permalink / raw)
  To: iwd

[-- Attachment #1: Type: text/plain, Size: 216 bytes --]

Hi James,

On 5/12/21 6:01 PM, James Prestwood wrote:
> ---
>   src/station.c | 25 +++++++++++++++++++------
>   1 file changed, 19 insertions(+), 6 deletions(-)
> 

All applied, thanks.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2021-05-12 23:07 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-12 23:01 [PATCH v3 01/11] station: factor out logic for choosing FT James Prestwood
2021-05-12 23:01 ` [PATCH v3 02/11] station: remove ap_directed_roam check for over-DS James Prestwood
2021-05-12 23:01 ` [PATCH v3 03/11] ft: break up FT action parsing into two steps James Prestwood
2021-05-12 23:01 ` [PATCH v3 04/11] netdev: handle multiple concurrent FT-over-DS action frames James Prestwood
2021-05-12 23:01 ` [PATCH v3 05/11] network: add network_bss_list_get_entries James Prestwood
2021-05-12 23:01 ` [PATCH v3 06/11] station: send FT-over-DS actions upon connection James Prestwood
2021-05-12 23:01 ` [PATCH v3 07/11] netdev: remove callback/userdata/timeout from FT-over-DS action James Prestwood
2021-05-12 23:01 ` [PATCH v3 08/11] auto-t: update FT-over-DS test for new behavior James Prestwood
2021-05-12 23:01 ` [PATCH v3 09/11] ie: use bitwise compare for IE_AKM_IS_FT James Prestwood
2021-05-12 23:01 ` [PATCH v3 10/11] station: make station_can_fast_transition more robust James Prestwood
2021-05-12 23:01 ` [PATCH v3 11/11] station: use IE_AKM_IS_FT when possible James Prestwood
2021-05-12 23:07 ` [PATCH v3 01/11] station: factor out logic for choosing FT Denis Kenzior

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.