All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 01/14] frame-xchg: add type to frame_xchg_prefix
@ 2022-09-15 22:07 James Prestwood
  2022-09-15 22:07 ` [PATCH v3 02/14] station: don't set OCVC for FT AKMs James Prestwood
                   ` (13 more replies)
  0 siblings, 14 replies; 19+ messages in thread
From: James Prestwood @ 2022-09-15 22:07 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

All uses of frame-xchg were for action frames, and the frame type
was hard coded. Soon other frame types will be needed so the type
must now be specified in the frame_xchg_prefix structure.
---
 src/anqp.c       | 1 +
 src/frame-xchg.c | 2 +-
 src/frame-xchg.h | 1 +
 src/p2p.c        | 4 ++++
 4 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/src/anqp.c b/src/anqp.c
index 8febdf91..a3c3d7ed 100644
--- a/src/anqp.c
+++ b/src/anqp.c
@@ -156,6 +156,7 @@ static bool anqp_response_frame_event(const struct mmpdu_header *hdr,
 }
 
 static const struct frame_xchg_prefix anqp_frame_prefix = {
+	.frame_type = 0x00d0,
 	.data = (uint8_t []) {
 		0x04, 0x0b,
 	},
diff --git a/src/frame-xchg.c b/src/frame-xchg.c
index 5ba36081..158befd0 100644
--- a/src/frame-xchg.c
+++ b/src/frame-xchg.c
@@ -1193,7 +1193,7 @@ uint32_t frame_xchg_startv(uint64_t wdev_id, struct iovec *frame, uint32_t freq,
 		watch = l_new(struct frame_xchg_watch_data, 1);
 		watch->prefix = prefix;
 		watch->cb = va_arg(resp_args, void *);
-		frame_watch_add(wdev_id, group_id, 0x00d0,
+		frame_watch_add(wdev_id, group_id, prefix->frame_type,
 				prefix->data, prefix->len,
 				frame_xchg_resp_cb, fx, NULL);
 
diff --git a/src/frame-xchg.h b/src/frame-xchg.h
index e3748538..360bb4d4 100644
--- a/src/frame-xchg.h
+++ b/src/frame-xchg.h
@@ -32,6 +32,7 @@ typedef void (*frame_xchg_cb_t)(int err, void *user_data);
 typedef void (*frame_xchg_destroy_func_t)(void *user_data);
 
 struct frame_xchg_prefix {
+	uint16_t frame_type;
 	const uint8_t *data;
 	size_t len;
 };
diff --git a/src/p2p.c b/src/p2p.c
index ff3b8e45..45a1b70b 100644
--- a/src/p2p.c
+++ b/src/p2p.c
@@ -820,6 +820,7 @@ static void p2p_peer_frame_xchg(struct p2p_peer *peer, struct iovec *tx_body,
 
 static const struct frame_xchg_prefix p2p_frame_go_neg_req = {
 	/* Management -> Public Action -> P2P -> GO Negotiation Request */
+	.frame_type = 0x00d0,
 	.data = (uint8_t []) {
 		0x04, 0x09, 0x50, 0x6f, 0x9a, 0x09,
 		P2P_ACTION_GO_NEGOTIATION_REQ
@@ -829,6 +830,7 @@ static const struct frame_xchg_prefix p2p_frame_go_neg_req = {
 
 static const struct frame_xchg_prefix p2p_frame_go_neg_resp = {
 	/* Management -> Public Action -> P2P -> GO Negotiation Response */
+	.frame_type = 0x00d0,
 	.data = (uint8_t []) {
 		0x04, 0x09, 0x50, 0x6f, 0x9a, 0x09,
 		P2P_ACTION_GO_NEGOTIATION_RESP
@@ -838,6 +840,7 @@ static const struct frame_xchg_prefix p2p_frame_go_neg_resp = {
 
 static const struct frame_xchg_prefix p2p_frame_go_neg_confirm = {
 	/* Management -> Public Action -> P2P -> GO Negotiation Confirm */
+	.frame_type = 0x00d0,
 	.data = (uint8_t []) {
 		0x04, 0x09, 0x50, 0x6f, 0x9a, 0x09,
 		P2P_ACTION_GO_NEGOTIATION_CONFIRM
@@ -847,6 +850,7 @@ static const struct frame_xchg_prefix p2p_frame_go_neg_confirm = {
 
 static const struct frame_xchg_prefix p2p_frame_pd_resp = {
 	/* Management -> Public Action -> P2P -> Provision Discovery Response */
+	.frame_type = 0x00d0,
 	.data = (uint8_t []) {
 		0x04, 0x09, 0x50, 0x6f, 0x9a, 0x09,
 		P2P_ACTION_PROVISION_DISCOVERY_RESP
-- 
2.34.3


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

* [PATCH v3 02/14] station: don't set OCVC for FT AKMs
  2022-09-15 22:07 [PATCH v3 01/14] frame-xchg: add type to frame_xchg_prefix James Prestwood
@ 2022-09-15 22:07 ` James Prestwood
  2022-09-15 22:07 ` [PATCH v3 03/14] ft: remove OCI element from auth/assoc James Prestwood
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: James Prestwood @ 2022-09-15 22:07 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

Using OCV in FT is now disabled, so if the AKM is FT don't set the
capability or AP's may reject FT attempts.
---
 src/station.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/src/station.c b/src/station.c
index 4faac050..79d2c755 100644
--- a/src/station.c
+++ b/src/station.c
@@ -1110,9 +1110,15 @@ build_ie:
 	 * seen that they do not include the OCI in the 4-way handshake yet
 	 * still advertise the capability. Because of this OCV is disabled if
 	 * any offload features are detected (since IWD prefers to use offload).
+	 *
+	 * TODO: For now OCV is disabled if the network is FT capable. This is
+	 *       being done until support in the kernel is added to
+	 *       automatically include the OCI element for the association
+	 *       request.
 	 */
 	info.ocvc = !disable_ocv && bss_info.ocvc && info.mfpc &&
-			!wiphy_can_offload(wiphy);
+			!wiphy_can_offload(wiphy) &&
+			!IE_AKM_IS_FT(info.akm_suites);
 
 	/*
 	 * IEEE 802.11-2020 9.4.2.24.4 states extended key IDs can only be used
-- 
2.34.3


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

* [PATCH v3 03/14] ft: remove OCI element from auth/assoc
  2022-09-15 22:07 [PATCH v3 01/14] frame-xchg: add type to frame_xchg_prefix James Prestwood
  2022-09-15 22:07 ` [PATCH v3 02/14] station: don't set OCVC for FT AKMs James Prestwood
@ 2022-09-15 22:07 ` James Prestwood
  2022-09-16 16:05   ` Denis Kenzior
  2022-09-15 22:07 ` [PATCH v3 04/14] frame-xchg: create global group enum James Prestwood
                   ` (11 subsequent siblings)
  13 siblings, 1 reply; 19+ messages in thread
From: James Prestwood @ 2022-09-15 22:07 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

FT is moving to authentication via CMD_FRAME which breaks the ability
to get the OCI from the kernel (since its now an offchannel operation).
Using OCI during FT isn't that useful anyways, so its being removed.
---
 src/ft.c     | 26 ++------------------------
 src/ft.h     |  2 +-
 src/netdev.c |  3 +--
 3 files changed, 4 insertions(+), 27 deletions(-)

diff --git a/src/ft.c b/src/ft.c
index 2285a86f..7ae78476 100644
--- a/src/ft.c
+++ b/src/ft.c
@@ -233,10 +233,6 @@ static int ft_tx_reassociate(struct ft_sm *ft)
 		rsn_info.num_pmkids = 1;
 		rsn_info.pmkids = hs->pmk_r1_name;
 
-		/* Always set OCVC false for FT-over-DS */
-		if (ft->over_ds)
-			rsn_info.ocvc = false;
-
 		rsne = alloca(256);
 		ie_build_rsne(&rsn_info, rsne);
 
@@ -276,22 +272,6 @@ static int ft_tx_reassociate(struct ft_sm *ft)
 		memcpy(ft_info.anonce, hs->anonce, 32);
 		memcpy(ft_info.snonce, hs->snonce, 32);
 
-		/*
-		 * IEEE 802.11-2020 Section 13.7.1 FT reassociation in an RSN
-		 *
-		 * "If dot11RSNAOperatingChannelValidationActivated is true and
-		 *  the FTO indicates OCVC capability, the target AP shall
-		 *  ensure that OCI subelement of the FTE matches by ensuring
-		 *  that all of the following are true:
-		 *      - OCI subelement is present
-		 *      - Channel information in the OCI matches current
-		 *        operating channel parameters (see 12.2.9)"
-		 */
-		if (hs->supplicant_ocvc && hs->chandef) {
-			oci_from_chandef(hs->chandef, ft_info.oci);
-			ft_info.oci_present = true;
-		}
-
 		fte = alloca(256);
 		ie_build_fast_bss_transition(&ft_info, kck_len, fte);
 
@@ -812,7 +792,7 @@ static bool ft_over_ds_start(struct auth_proto *ap)
 	return ft_tx_reassociate(ft) == 0;
 }
 
-bool ft_build_authenticate_ies(struct handshake_state *hs, bool ocvc,
+bool ft_build_authenticate_ies(struct handshake_state *hs,
 				const uint8_t *new_snonce, uint8_t *buf,
 				size_t *len)
 {
@@ -841,7 +821,6 @@ bool ft_build_authenticate_ies(struct handshake_state *hs, bool ocvc,
 
 		rsn_info.num_pmkids = 1;
 		rsn_info.pmkids = hs->pmk_r0_name;
-		rsn_info.ocvc = ocvc;
 
 		ie_build_rsne(&rsn_info, ptr);
 		ptr += ptr[1] + 2;
@@ -892,8 +871,7 @@ static bool ft_start(struct auth_proto *ap)
 	uint8_t buf[512];
 	size_t len;
 
-	if (!ft_build_authenticate_ies(hs, hs->supplicant_ocvc, hs->snonce,
-					buf, &len))
+	if (!ft_build_authenticate_ies(hs, hs->snonce, buf, &len))
 		return false;
 
 	iov.iov_base = buf;
diff --git a/src/ft.h b/src/ft.h
index f90fc1b2..dd56da23 100644
--- a/src/ft.h
+++ b/src/ft.h
@@ -45,7 +45,7 @@ struct ft_ds_info {
 
 void ft_ds_info_free(struct ft_ds_info *info);
 
-bool ft_build_authenticate_ies(struct handshake_state *hs, bool ocvc,
+bool ft_build_authenticate_ies(struct handshake_state *hs,
 				const uint8_t *new_snonce, uint8_t *buf,
 				size_t *len);
 
diff --git a/src/netdev.c b/src/netdev.c
index 7a14f1dd..61cb6284 100644
--- a/src/netdev.c
+++ b/src/netdev.c
@@ -4765,8 +4765,7 @@ int netdev_fast_transition_over_ds_action(struct netdev *netdev,
 	iovs[0].iov_base = ft_req;
 	iovs[0].iov_len = sizeof(ft_req);
 
-	if (!ft_build_authenticate_ies(hs, false, info->super.snonce,
-						buf, &len))
+	if (!ft_build_authenticate_ies(hs, info->super.snonce, buf, &len))
 		goto failed;
 
 	iovs[1].iov_base = buf;
-- 
2.34.3


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

* [PATCH v3 04/14] frame-xchg: create global group enum
  2022-09-15 22:07 [PATCH v3 01/14] frame-xchg: add type to frame_xchg_prefix James Prestwood
  2022-09-15 22:07 ` [PATCH v3 02/14] station: don't set OCVC for FT AKMs James Prestwood
  2022-09-15 22:07 ` [PATCH v3 03/14] ft: remove OCI element from auth/assoc James Prestwood
@ 2022-09-15 22:07 ` James Prestwood
  2022-09-16 16:06   ` Denis Kenzior
  2022-09-15 22:07 ` [PATCH v3 05/14] ft: netdev: prep for FT isolation into ft.c James Prestwood
                   ` (10 subsequent siblings)
  13 siblings, 1 reply; 19+ messages in thread
From: James Prestwood @ 2022-09-15 22:07 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

Only P2P utilizes groups for now but to avoid conflicts in group
numbers for other modules create a global list which can be added
to as needed.
---
 src/frame-xchg.h |  7 +++++++
 src/p2p.c        | 24 +++++++++---------------
 2 files changed, 16 insertions(+), 15 deletions(-)

diff --git a/src/frame-xchg.h b/src/frame-xchg.h
index 360bb4d4..5b55ded8 100644
--- a/src/frame-xchg.h
+++ b/src/frame-xchg.h
@@ -37,6 +37,13 @@ struct frame_xchg_prefix {
 	size_t len;
 };
 
+enum frame_xchg_group {
+	FRAME_GROUP_DEFAULT = 0,
+	FRAME_GROUP_P2P_LISTEN,
+	FRAME_GROUP_P2P_CONNECT,
+	FRAME_GROUP_FT,
+};
+
 bool frame_watch_add(uint64_t wdev_id, uint32_t group, uint16_t frame_type,
 			const uint8_t *prefix, size_t prefix_len,
 			frame_watch_cb_t handler, void *user_data,
diff --git a/src/p2p.c b/src/p2p.c
index 45a1b70b..cfd8560a 100644
--- a/src/p2p.c
+++ b/src/p2p.c
@@ -190,12 +190,6 @@ static const int channels_scan_2_4_other[] = { 2, 3, 4, 5, 7, 8, 9, 10 };
  */
 #define P2P_GO_INTENT 2
 
-enum {
-	FRAME_GROUP_DEFAULT = 0,
-	FRAME_GROUP_LISTEN,
-	FRAME_GROUP_CONNECT,
-};
-
 static bool p2p_device_match(const void *a, const void *b)
 {
 	const struct p2p_device *dev = a;
@@ -718,7 +712,7 @@ static void p2p_connection_reset(struct p2p_device *dev)
 
 	netdev_watch_remove(dev->conn_netdev_watch_id);
 
-	frame_watch_group_remove(dev->wdev_id, FRAME_GROUP_CONNECT);
+	frame_watch_group_remove(dev->wdev_id, FRAME_GROUP_P2P_CONNECT);
 	frame_xchg_stop_wdev(dev->wdev_id);
 
 	if (!dev->enabled || (dev->enabled && dev->start_stop_cmd_id)) {
@@ -2527,13 +2521,13 @@ respond:
 
 	if (status == P2P_STATUS_SUCCESS)
 		p2p_peer_frame_xchg(peer, iov, dev->addr, 0, 600, 0, true,
-					FRAME_GROUP_CONNECT,
+					FRAME_GROUP_P2P_CONNECT,
 					p2p_go_negotiation_resp_done,
 					&p2p_frame_go_neg_confirm,
 					p2p_go_negotiation_confirm_cb, NULL);
 	else
 		p2p_peer_frame_xchg(peer, iov, dev->addr, 0, 0, 0, true,
-					FRAME_GROUP_CONNECT,
+					FRAME_GROUP_P2P_CONNECT,
 					p2p_go_negotiation_resp_err_done, NULL);
 
 	l_debug("GO Negotiation Response sent with status %i", status);
@@ -2804,7 +2798,7 @@ static bool p2p_go_negotiation_resp_cb(const struct mmpdu_header *mpdu,
 	iov[iov_len].iov_base = NULL;
 
 	p2p_peer_frame_xchg(dev->conn_peer, iov, dev->conn_peer->device_addr,
-				0, 0, 0, false, FRAME_GROUP_CONNECT,
+				0, 0, 0, false, FRAME_GROUP_P2P_CONNECT,
 				p2p_go_negotiation_confirm_done, NULL);
 	l_free(confirm_body);
 
@@ -2893,7 +2887,7 @@ static void p2p_start_go_negotiation(struct p2p_device *dev)
 
 	p2p_peer_frame_xchg(dev->conn_peer, iov, dev->conn_peer->device_addr,
 				100, resp_timeout, 256, false,
-				FRAME_GROUP_CONNECT,
+				FRAME_GROUP_P2P_CONNECT,
 				p2p_go_negotiation_req_done,
 				&p2p_frame_go_neg_resp,
 				p2p_go_negotiation_resp_cb, NULL);
@@ -3035,7 +3029,7 @@ static void p2p_start_provision_discovery(struct p2p_device *dev)
 	 * sent to the P2P Device Address of the P2P Group Owner"
 	 */
 	p2p_peer_frame_xchg(dev->conn_peer, iov, dev->conn_peer->device_addr,
-				200, 600, 8, false, FRAME_GROUP_CONNECT,
+				200, 600, 8, false, FRAME_GROUP_P2P_CONNECT,
 				p2p_provision_disc_req_done,
 				&p2p_frame_pd_resp, p2p_provision_disc_resp_cb,
 				NULL);
@@ -4167,9 +4161,9 @@ static void p2p_device_discovery_start(struct p2p_device *dev)
 		dev->listen_channel = channels_social[l_getrandom_uint32() %
 						L_ARRAY_SIZE(channels_social)];
 
-	frame_watch_add(dev->wdev_id, FRAME_GROUP_LISTEN, 0x0040,
+	frame_watch_add(dev->wdev_id, FRAME_GROUP_P2P_LISTEN, 0x0040,
 			(uint8_t *) "", 0, p2p_device_probe_cb, dev, NULL);
-	frame_watch_add(dev->wdev_id, FRAME_GROUP_LISTEN, 0x00d0,
+	frame_watch_add(dev->wdev_id, FRAME_GROUP_P2P_LISTEN, 0x00d0,
 			p2p_frame_go_neg_req.data, p2p_frame_go_neg_req.len,
 			p2p_device_go_negotiation_req_cb, dev, NULL);
 
@@ -4187,7 +4181,7 @@ static void p2p_device_discovery_stop(struct p2p_device *dev)
 		l_timeout_remove(dev->scan_timeout);
 
 	p2p_device_roc_cancel(dev);
-	frame_watch_group_remove(dev->wdev_id, FRAME_GROUP_LISTEN);
+	frame_watch_group_remove(dev->wdev_id, FRAME_GROUP_P2P_LISTEN);
 }
 
 static void p2p_device_enable_cb(struct l_genl_msg *msg, void *user_data)
-- 
2.34.3


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

* [PATCH v3 05/14] ft: netdev: prep for FT isolation into ft.c
  2022-09-15 22:07 [PATCH v3 01/14] frame-xchg: add type to frame_xchg_prefix James Prestwood
                   ` (2 preceding siblings ...)
  2022-09-15 22:07 ` [PATCH v3 04/14] frame-xchg: create global group enum James Prestwood
@ 2022-09-15 22:07 ` James Prestwood
  2022-09-15 22:07 ` [PATCH v3 06/14] netdev: use new ft_sm for over-DS James Prestwood
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: James Prestwood @ 2022-09-15 22:07 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

Currently netdev handles caching FT auth information and uses FT
parsers/auth-proto to manage the protocol. This sets up to remove
this state machine from netdev and isolate it into ft.c.

This does not break the existing auth-proto (hence the slight
modifications, which will be removed soon).

Eventually the auth-proto will be removed from FT entirely, replaced
just by an FT state machine, similar to how EAPoL works (netdev hooks
to TX/RX frames).
---
 src/ft.c     | 337 +++++++++++++++++++++++++++++++++++++++++++++++++--
 src/ft.h     |  20 ++-
 src/netdev.c |  47 ++++---
 3 files changed, 377 insertions(+), 27 deletions(-)

diff --git a/src/ft.c b/src/ft.c
index 7ae78476..2c9c92e6 100644
--- a/src/ft.c
+++ b/src/ft.c
@@ -33,6 +33,33 @@
 #include "src/mpdu.h"
 #include "src/auth-proto.h"
 #include "src/band.h"
+#include "src/scan.h"
+#include "src/frame-xchg.h"
+#include "src/util.h"
+#include "src/netdev.h"
+#include "src/module.h"
+
+static ft_tx_action_func_t tx_action = NULL;
+static ft_tx_associate_func_t tx_assoc = NULL;
+static struct l_queue *sm_list = NULL;
+
+struct ft_info {
+	uint8_t spa[6];
+	uint8_t aa[6];
+	uint8_t snonce[32];
+	uint8_t mde[3];
+	uint8_t *fte;
+	uint8_t *authenticator_ie;
+
+	struct ie_ft_info ft_info;
+
+	bool parsed : 1;
+};
+
+struct ft_info_finder {
+	const uint8_t *spa;
+	const uint8_t *aa;
+};
 
 struct ft_sm {
 	struct auth_proto ap;
@@ -45,8 +72,24 @@ struct ft_sm {
 	void *user_data;
 
 	bool over_ds : 1;
+
+	uint8_t prev_bssid[6];
+	struct l_queue *ft_auths;
 };
 
+static bool match_ifindex(const void *a, const void *data)
+{
+	const struct ft_sm *sm = a;
+	uint32_t ifindex = L_PTR_TO_UINT(data);
+
+	return sm->hs->ifindex == ifindex;
+}
+
+static struct ft_sm *ft_sm_find(uint32_t ifindex)
+{
+	return l_queue_find(sm_list, match_ifindex, L_UINT_TO_PTR(ifindex));
+}
+
 /*
  * Calculate the MIC field of the FTE and write it directly to that FTE,
  * assuming it was all zeros before.  See 12.8.4 and 12.8.5.
@@ -286,7 +329,7 @@ static int ft_tx_reassociate(struct ft_sm *ft)
 		iov_elems += 1;
 	}
 
-	return ft->tx_assoc(iov, iov_elems, ft->user_data);
+	return tx_assoc(ft->hs->ifindex, ft->prev_bssid, iov, iov_elems);
 
 error:
 	return -EINVAL;
@@ -328,7 +371,7 @@ static bool ft_verify_rsne(const uint8_t *rsne, const uint8_t *pmk_r0_name,
 	return true;
 }
 
-static int ft_parse_ies(struct handshake_state *hs,
+static int parse_ies(struct handshake_state *hs,
 			const uint8_t *authenticator_ie,
 			const uint8_t *ies, size_t ies_len,
 			const uint8_t **mde_out,
@@ -460,7 +503,7 @@ bool ft_over_ds_parse_action_ies(struct ft_ds_info *info,
 	const uint8_t *fte = NULL;
 	bool is_rsn = hs->supplicant_ie != NULL;
 
-	if (ft_parse_ies(hs, info->authenticator_ie, ies, ies_len,
+	if (parse_ies(hs, info->authenticator_ie, ies, ies_len,
 				&mde, &fte) < 0)
 		return false;
 
@@ -492,7 +535,7 @@ static int ft_process_ies(struct handshake_state *hs, const uint8_t *ies,
 	if (!ies)
 		goto ft_error;
 
-	if (ft_parse_ies(hs, hs->authenticator_ie, ies, ies_len,
+	if (parse_ies(hs, hs->authenticator_ie, ies, ies_len,
 				&mde, &fte) < 0)
 		goto ft_error;
 
@@ -634,10 +677,9 @@ auth_error:
 	return (int)status_code;
 }
 
-static int ft_rx_associate(struct auth_proto *ap, const uint8_t *frame,
-				size_t frame_len)
+int __ft_rx_associate(uint32_t ifindex, const uint8_t *frame, size_t frame_len)
 {
-	struct ft_sm *ft = l_container_of(ap, struct ft_sm, ap);
+	struct ft_sm *ft = ft_sm_find(ifindex);
 	struct handshake_state *hs = ft->hs;
 	uint32_t kck_len = handshake_state_get_kck_len(hs);
 	const uint8_t *rsne = NULL;
@@ -651,6 +693,9 @@ static int ft_rx_associate(struct auth_proto *ap, const uint8_t *frame,
 					&mde, &fte))
 		return -EBADMSG;
 
+	if (out_status != 0)
+		return (int)out_status;
+
 	/*
 	 * During a transition in an RSN, check for an RSNE containing the
 	 * PMK-R1-Name and the remaining fields same as in the advertised
@@ -771,6 +816,14 @@ static int ft_rx_associate(struct auth_proto *ap, const uint8_t *frame,
 	return 0;
 }
 
+static int ft_rx_associate(struct auth_proto *ap, const uint8_t *frame,
+				size_t frame_len)
+{
+	struct ft_sm *sm = l_container_of(ap, struct ft_sm, ap);
+
+	return __ft_rx_associate(sm->hs->ifindex, frame, frame_len);
+}
+
 static int ft_rx_oci(struct auth_proto *ap)
 {
 	struct ft_sm *ft = l_container_of(ap, struct ft_sm, ap);
@@ -778,10 +831,12 @@ static int ft_rx_oci(struct auth_proto *ap)
 	return ft_tx_reassociate(ft);
 }
 
-static void ft_sm_free(struct auth_proto *ap)
+static void ft_auth_proto_free(struct auth_proto *ap)
 {
 	struct ft_sm *ft = l_container_of(ap, struct ft_sm, ap);
 
+	l_queue_remove(sm_list, ft);
+
 	l_free(ft);
 }
 
@@ -899,9 +954,13 @@ struct auth_proto *ft_over_air_sm_new(struct handshake_state *hs,
 	ft->ap.rx_authenticate = ft_rx_authenticate;
 	ft->ap.rx_associate = ft_rx_associate;
 	ft->ap.start = ft_start;
-	ft->ap.free = ft_sm_free;
+	ft->ap.free = ft_auth_proto_free;
 	ft->ap.rx_oci = ft_rx_oci;
 
+	memcpy(ft->prev_bssid, hs->aa, 6);
+
+	l_queue_push_tail(sm_list, ft);
+
 	return &ft->ap;
 }
 
@@ -918,7 +977,265 @@ struct auth_proto *ft_over_ds_sm_new(struct handshake_state *hs,
 
 	ft->ap.rx_associate = ft_rx_associate;
 	ft->ap.start = ft_over_ds_start;
-	ft->ap.free = ft_sm_free;
+	ft->ap.free = ft_auth_proto_free;
+
+	memcpy(ft->prev_bssid, hs->aa, 6);
+
+	l_queue_push_tail(sm_list, ft);
 
 	return &ft->ap;
 }
+
+void __ft_set_tx_action_func(ft_tx_action_func_t func)
+{
+	tx_action = func;
+}
+
+void __ft_set_tx_associate_func(ft_tx_associate_func_t func)
+{
+	tx_assoc = func;
+}
+
+static bool match_ft_info(const void *a, const void *b)
+{
+	const struct ft_info *info = a;
+	const struct ft_info_finder *finder = b;
+
+	if (memcmp(info->spa, finder->spa, 6))
+		return false;
+	if (memcmp(info->aa, finder->aa, 6))
+		return false;
+
+	return true;
+}
+
+static bool ft_parse_ies(struct ft_info *info, struct handshake_state *hs,
+			const uint8_t *ies, size_t ies_len)
+{
+	const uint8_t *mde = NULL;
+	const uint8_t *fte = NULL;
+	bool is_rsn = hs->supplicant_ie != NULL;
+
+	if (parse_ies(hs, info->authenticator_ie, ies, ies_len,
+				&mde, &fte) < 0)
+		return false;
+
+	if (!mde_equal(info->mde, mde))
+		goto ft_error;
+
+	if (is_rsn) {
+		if (!ft_parse_fte(hs, info->snonce, fte, &info->ft_info))
+			goto ft_error;
+
+		info->fte = l_memdup(fte, fte[1] + 2);
+	} else if (fte)
+		goto ft_error;
+
+	return true;
+
+ft_error:
+	return false;
+}
+
+static void ft_action_response_cb(const struct mmpdu_header *hdr,
+					const void *body, size_t body_len,
+					int rssi, void *user_data)
+{
+	struct ft_sm *sm = user_data;
+	struct ft_info *info;
+	int ret;
+	const uint8_t *aa;
+	const uint8_t *spa;
+	const uint8_t *ies;
+	size_t ies_len;
+	struct ft_info_finder finder;
+
+	ret = ft_over_ds_parse_action_response(body, body_len, &spa, &aa,
+						&ies, &ies_len);
+	if (ret != 0)
+		return;
+
+	finder.spa = spa;
+	finder.aa = aa;
+
+	info = l_queue_find(sm->ft_auths, match_ft_info, &finder);
+	if (!info)
+		return;
+
+	if (!ft_parse_ies(info, sm->hs, ies, ies_len))
+		goto ft_error;
+
+	info->parsed = true;
+
+	return;
+
+ft_error:
+	l_debug("FT-over-DS authenticate to "MAC" failed", MAC_STR(info->aa));
+}
+
+static struct ft_info *ft_info_new(struct handshake_state *hs,
+					const struct scan_bss *target_bss)
+{
+	struct ft_info *info = l_new(struct ft_info, 1);
+
+	memcpy(info->spa, hs->spa, 6);
+	memcpy(info->aa, target_bss->addr, 6);
+	memcpy(info->mde, target_bss->mde, sizeof(info->mde));
+
+	if (target_bss->rsne)
+		info->authenticator_ie = l_memdup(target_bss->rsne,
+						target_bss->rsne[1] + 2);
+
+	l_getrandom(info->snonce, 32);
+
+	return info;
+}
+
+static void ft_info_destroy(void *data)
+{
+	struct ft_info *info = data;
+
+	if (info->fte)
+		l_free(info->fte);
+
+	if (info->authenticator_ie)
+		l_free(info->authenticator_ie);
+
+	l_free(info);
+}
+
+static void ft_prepare_handshake(struct ft_info *info,
+					struct handshake_state *hs)
+{
+	if (!hs->supplicant_ie)
+		return;
+
+	memcpy(hs->snonce, info->snonce, sizeof(hs->snonce));
+
+	handshake_state_set_fte(hs, info->fte);
+
+	handshake_state_set_anonce(hs, info->ft_info.anonce);
+
+	handshake_state_set_kh_ids(hs, info->ft_info.r0khid,
+						info->ft_info.r0khid_len,
+						info->ft_info.r1khid);
+
+	handshake_state_derive_ptk(hs);
+}
+
+static const uint8_t action_ft_response_prefix[] =  { 0x06, 0x02 };
+
+struct ft_sm *ft_sm_new(struct handshake_state *hs)
+{
+	struct ft_sm *sm = l_new(struct ft_sm, 1);
+	struct netdev *netdev = netdev_find(hs->ifindex);
+
+	sm->hs = hs;
+	sm->ft_auths = l_queue_new();
+	sm->over_ds = hs->mde[4] & 1;
+	memcpy(sm->prev_bssid, hs->aa, 6);
+
+	if (sm->over_ds)
+		frame_watch_add(netdev_get_wdev_id(netdev), FRAME_GROUP_FT,
+			0x00d0, action_ft_response_prefix,
+			sizeof(action_ft_response_prefix),
+			ft_action_response_cb, sm, NULL);
+
+	l_queue_push_tail(sm_list, sm);
+
+	return sm;
+}
+
+void ft_sm_free(struct ft_sm *sm)
+{
+	struct netdev *netdev = netdev_find(sm->hs->ifindex);
+
+	if (sm->over_ds)
+		frame_watch_group_remove(netdev_get_wdev_id(netdev),
+					FRAME_GROUP_FT);
+
+	l_queue_destroy(sm->ft_auths, ft_info_destroy);
+
+	l_queue_remove(sm_list, sm);
+
+	l_free(sm);
+}
+
+int ft_action(struct ft_sm *sm, const struct scan_bss *target)
+{
+	struct ft_info *info;
+	uint8_t ft_req[14];
+	struct iovec iov[5];
+	uint8_t ies[512];
+	size_t len;
+	int ret = -EINVAL;
+
+	info = ft_info_new(sm->hs, target);
+
+	ft_req[0] = 6; /* FT category */
+	ft_req[1] = 1; /* FT Request action */
+	memcpy(ft_req + 2, info->spa, 6);
+	memcpy(ft_req + 8, info->aa, 6);
+
+	if (!ft_build_authenticate_ies(sm->hs, info->snonce, ies, &len))
+		goto failed;
+
+	iov[0].iov_base = ft_req;
+	iov[0].iov_len = sizeof(ft_req);
+
+	iov[1].iov_base = ies;
+	iov[1].iov_len = len;
+
+	ret = tx_action(sm->hs->ifindex, sm->hs->aa, iov, 2);
+	if (ret < 0)
+		goto failed;
+
+	l_queue_push_tail(sm->ft_auths, info);
+
+	return 0;
+
+failed:
+	l_free(info);
+	return ret;
+}
+
+int ft_associate(struct ft_sm *sm, const uint8_t *addr)
+{
+	struct ft_info *info;
+	struct ft_info_finder finder;
+
+	finder.spa = sm->hs->spa;
+	finder.aa = addr;
+
+	info = l_queue_find(sm->ft_auths, match_ft_info, &finder);
+	/*
+	 * TODO: Since FT-over-DS is done early, before the time of roaming, it
+	 *       may end up that a completely new BSS is the best candidate and
+	 *       we haven't yet authenticated. We could actually authenticate
+	 *       at this point, but for now just assume the caller will choose
+	 *       a different BSS.
+	 */
+	if (!info)
+		return -ENOENT;
+
+	ft_prepare_handshake(info, sm->hs);
+
+	return ft_tx_reassociate(sm);
+}
+
+static int ft_init(void)
+{
+	sm_list = l_queue_new();
+
+	return 0;
+}
+
+static void ft_exit(void)
+{
+	if (!l_queue_isempty(sm_list))
+		l_warn("stale FT state machines found!");
+
+	l_queue_destroy(sm_list, (l_queue_destroy_func_t)ft_sm_free);
+}
+
+IWD_MODULE(ft, ft_init, ft_exit);
diff --git a/src/ft.h b/src/ft.h
index dd56da23..6e0f4271 100644
--- a/src/ft.h
+++ b/src/ft.h
@@ -21,11 +21,16 @@
  */
 
 struct handshake_state;
+struct scan_bss;
+
+typedef int (*ft_tx_action_func_t)(uint32_t ifindex, const uint8_t *dest,
+					struct iovec *iov, size_t iov_len);
 
 typedef void (*ft_tx_authenticate_func_t)(struct iovec *iov, size_t iov_len,
 					void *user_data);
-typedef int (*ft_tx_associate_func_t)(struct iovec *ie_iov, size_t iov_len,
-					void *user_data);
+typedef int (*ft_tx_associate_func_t)(uint32_t ifindex,
+					const uint8_t *prev_bssid,
+					struct iovec *ie_iov, size_t iov_len);
 typedef int (*ft_get_oci)(void *user_data);
 
 typedef void (*ft_ds_free_func_t)(void *user_data);
@@ -71,3 +76,14 @@ struct auth_proto *ft_over_ds_sm_new(struct handshake_state *hs,
 
 bool ft_over_ds_prepare_handshake(struct ft_ds_info *info,
 					struct handshake_state *hs);
+
+void __ft_set_tx_action_func(ft_tx_action_func_t func);
+void __ft_set_tx_associate_func(ft_tx_associate_func_t func);
+int __ft_rx_associate(uint32_t ifindex, const uint8_t *frame,
+			size_t frame_len);
+
+struct ft_sm *ft_sm_new(struct handshake_state *hs);
+void ft_sm_free(struct ft_sm *sm);
+
+int ft_action(struct ft_sm *sm, const struct scan_bss *target);
+int ft_associate(struct ft_sm *sm, const uint8_t *addr);
diff --git a/src/netdev.c b/src/netdev.c
index 61cb6284..03b384bb 100644
--- a/src/netdev.c
+++ b/src/netdev.c
@@ -4366,6 +4366,25 @@ static uint32_t netdev_send_action_frame(struct netdev *netdev,
 						user_data);
 }
 
+static void netdev_ft_action_cb(struct l_genl_msg *msg, void *user_data)
+{
+	if (l_genl_msg_get_error(msg) < 0)
+		l_debug("Failed to send FT-Action");
+}
+
+static int netdev_tx_ft_action_frame(uint32_t ifindex, const uint8_t *dest,
+					struct iovec *iov, size_t iov_len)
+{
+	struct netdev *netdev = netdev_find(ifindex);
+
+	if (!netdev_send_action_framev(netdev, dest, iov, iov_len,
+					netdev->frequency,
+					netdev_ft_action_cb, NULL))
+		return -EIO;
+
+	return 0;
+}
+
 static void netdev_cmd_authenticate_ft_cb(struct l_genl_msg *msg,
 						void *user_data)
 {
@@ -4408,11 +4427,10 @@ restore_snonce:
 					MMPDU_STATUS_CODE_UNSPECIFIED);
 }
 
-static int netdev_ft_tx_associate(struct iovec *ft_iov, size_t n_ft_iov,
-					void *user_data)
+static int netdev_ft_tx_associate(uint32_t ifindex, const uint8_t *prev_bssid,
+					struct iovec *ft_iov, size_t n_ft_iov)
 {
-	struct netdev *netdev = user_data;
-	struct auth_proto *ap = netdev->ap;
+	struct netdev *netdev = netdev_find(ifindex);
 	struct handshake_state *hs = netdev->handshake;
 	struct l_genl_msg *msg;
 	struct iovec iov[64];
@@ -4433,7 +4451,7 @@ static int netdev_ft_tx_associate(struct iovec *ft_iov, size_t n_ft_iov,
 	mpdu_sort_ies(subtype, iov, c_iov);
 
 	l_genl_msg_append_attr(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN,
-				ap->prev_bssid);
+				prev_bssid);
 	l_genl_msg_append_attrv(msg, NL80211_ATTR_IE, iov, c_iov);
 
 	netdev->connect_cmd_id = l_genl_family_send(nl80211, msg,
@@ -4645,17 +4663,15 @@ int netdev_fast_transition(struct netdev *netdev,
 			l_get_le16(target_bss->mde))
 		return -EINVAL;
 
-	prepare_ft(netdev, target_bss);
-
-	handshake_state_new_snonce(netdev->handshake);
-
 	netdev->connect_cb = cb;
 
 	netdev->ap = ft_over_air_sm_new(netdev->handshake,
 					netdev_ft_tx_authenticate,
 					netdev_ft_tx_associate,
 					netdev_get_oci, netdev);
-	memcpy(netdev->ap->prev_bssid, orig_bss->addr, ETH_ALEN);
+	prepare_ft(netdev, target_bss);
+
+	handshake_state_new_snonce(netdev->handshake);
 
 	wiphy_radio_work_insert(netdev->wiphy, &netdev->work,
 				WIPHY_WORK_PRIORITY_CONNECT, &ft_work_ops);
@@ -4687,16 +4703,14 @@ int netdev_fast_transition_over_ds(struct netdev *netdev,
 	if (!info || !info->parsed)
 		return -ENOENT;
 
-	prepare_ft(netdev, target_bss);
-
-	ft_over_ds_prepare_handshake(&info->super, netdev->handshake);
-
 	netdev->connect_cb = cb;
 
 	netdev->ap = ft_over_ds_sm_new(netdev->handshake,
 					netdev_ft_tx_associate,
 					netdev);
-	memcpy(netdev->ap->prev_bssid, orig_bss->addr, ETH_ALEN);
+	prepare_ft(netdev, target_bss);
+
+	ft_over_ds_prepare_handshake(&info->super, netdev->handshake);
 
 	wiphy_radio_work_insert(netdev->wiphy, &netdev->work,
 				WIPHY_WORK_PRIORITY_CONNECT, &ft_work_ops);
@@ -6641,6 +6655,9 @@ static int netdev_init(void)
 	__eapol_set_tx_packet_func(netdev_control_port_frame);
 	__eapol_set_install_pmk_func(netdev_set_pmk);
 
+	__ft_set_tx_action_func(netdev_tx_ft_action_frame);
+	__ft_set_tx_associate_func(netdev_ft_tx_associate);
+
 	unicast_watch = l_genl_add_unicast_watch(genl, NL80211_GENL_NAME,
 						netdev_unicast_notify,
 						NULL, NULL);
-- 
2.34.3


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

* [PATCH v3 06/14] netdev: use new ft_sm for over-DS
  2022-09-15 22:07 [PATCH v3 01/14] frame-xchg: add type to frame_xchg_prefix James Prestwood
                   ` (3 preceding siblings ...)
  2022-09-15 22:07 ` [PATCH v3 05/14] ft: netdev: prep for FT isolation into ft.c James Prestwood
@ 2022-09-15 22:07 ` James Prestwood
  2022-09-15 22:07 ` [PATCH v3 07/14] ft: implement offchannel authentication James Prestwood
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: James Prestwood @ 2022-09-15 22:07 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

FT-over-DS auth entries are now stored in ft.c itself, and a few APIs
are exposed to send the action/associate frames. This is duplicated
in netdev, which can now be removed. Currently FT-over-Air still
uses the auth-proto which has been left in place for now.

The basic flow remains the same, station initiates action frames to
possible roam candidates. Authentication takes place and the IEs
are stored in ft.c. Then, when a roam is required, association may
begin using one of the cached authentications.
---
 src/netdev.c | 255 +++++++++------------------------------------------
 1 file changed, 43 insertions(+), 212 deletions(-)

diff --git a/src/netdev.c b/src/netdev.c
index 03b384bb..2519feda 100644
--- a/src/netdev.c
+++ b/src/netdev.c
@@ -96,13 +96,6 @@ struct netdev_handshake_state {
 	enum connection_type type;
 };
 
-struct netdev_ft_over_ds_info {
-	struct ft_ds_info super;
-	struct netdev *netdev;
-
-	bool parsed : 1;
-};
-
 struct netdev_ext_key_info {
 	uint16_t proto;
 	bool noencrypt;
@@ -128,6 +121,7 @@ struct netdev {
 	struct eapol_sm *sm;
 	struct auth_proto *ap;
 	struct owe_sm *owe_sm;
+	struct ft_sm *ft_sm;
 	struct handshake_state *handshake;
 	uint32_t connect_cmd_id;
 	uint32_t disconnect_cmd_id;
@@ -176,8 +170,6 @@ struct netdev {
 	struct l_genl_msg *auth_cmd;
 	struct wiphy_radio_work_item work;
 
-	struct l_queue *ft_ds_list;
-
 	struct netdev_ext_key_info *ext_key_info;
 
 	bool connected : 1;
@@ -752,13 +744,6 @@ 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)
@@ -779,6 +764,11 @@ static void netdev_connect_free(struct netdev *netdev)
 		netdev->owe_sm = NULL;
 	}
 
+	if (netdev->ft_sm) {
+		ft_sm_free(netdev->ft_sm);
+		netdev->ft_sm = NULL;
+	}
+
 	eapol_preauth_cancel(netdev->index);
 
 	if (netdev->handshake) {
@@ -847,11 +837,6 @@ static void netdev_connect_free(struct netdev *netdev)
 		l_genl_family_cancel(nl80211, netdev->get_oci_cmd_id);
 		netdev->get_oci_cmd_id = 0;
 	}
-
-	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,
@@ -962,11 +947,6 @@ static void netdev_free(void *data)
 	if (netdev->fw_roam_bss)
 		scan_bss_free(netdev->fw_roam_bss);
 
-	if (netdev->ft_ds_list) {
-		l_queue_destroy(netdev->ft_ds_list, netdev_ft_ds_entry_free);
-		netdev->ft_ds_list = NULL;
-	}
-
 	scan_wdev_remove(netdev->wdev_id);
 
 	watchlist_destroy(&netdev->station_watches);
@@ -1415,9 +1395,12 @@ 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;
+	/* TODO: Create only for over-DS. Over-air still uses auth-proto */
+	if (netdev->handshake->mde && (netdev->handshake->mde[4] & 1)) {
+		if (netdev->ft_sm)
+			ft_sm_free(netdev->ft_sm);
+
+		netdev->ft_sm = ft_sm_new(netdev->handshake);
 	}
 
 	if (netdev->connect_cb) {
@@ -3198,7 +3181,7 @@ static void netdev_associate_event(struct l_genl_msg *msg,
 	if (!netdev->connected || netdev->aborting)
 		return;
 
-	if (!netdev->ap) {
+	if (!netdev->ap && !netdev->ft_sm) {
 		netdev->associated = true;
 		netdev->in_reassoc = false;
 		return;
@@ -3238,7 +3221,7 @@ static void netdev_associate_event(struct l_genl_msg *msg,
 	if (L_WARN_ON(!frame))
 		goto assoc_failed;
 
-	if (netdev->ap) {
+	if (netdev->ap || netdev->ft_sm) {
 		const struct mmpdu_header *hdr;
 		const struct mmpdu_association_response *assoc;
 
@@ -3249,7 +3232,12 @@ static void netdev_associate_event(struct l_genl_msg *msg,
 		assoc = mmpdu_body(hdr);
 		status_code = L_CPU_TO_LE16(assoc->status_code);
 
-		ret = auth_proto_rx_associate(netdev->ap, frame, frame_len);
+		if (netdev->ap)
+			ret = auth_proto_rx_associate(netdev->ap, frame,
+							frame_len);
+		else
+			ret = __ft_rx_associate(netdev->index, frame,
+							frame_len);
 		if (ret == 0) {
 			bool fils = !!(netdev->handshake->akm_suite &
 					(IE_RSN_AKM_SUITE_FILS_SHA256 |
@@ -3257,8 +3245,10 @@ static void netdev_associate_event(struct l_genl_msg *msg,
 					 IE_RSN_AKM_SUITE_FT_OVER_FILS_SHA384 |
 					 IE_RSN_AKM_SUITE_FT_OVER_FILS_SHA256));
 
-			auth_proto_free(netdev->ap);
-			netdev->ap = NULL;
+			if (netdev->ap) {
+				auth_proto_free(netdev->ap);
+				netdev->ap = NULL;
+			}
 
 			netdev->sm = eapol_sm_new(netdev->handshake);
 			eapol_register(netdev->sm);
@@ -4533,81 +4523,6 @@ static void prepare_ft(struct netdev *netdev, const struct scan_bss *target_bss)
 	}
 }
 
-static void netdev_ft_over_ds_auth_failed(struct netdev_ft_over_ds_info *info,
-						uint16_t status)
-{
-	l_queue_remove(info->netdev->ft_ds_list, info);
-	ft_ds_info_free(&info->super);
-}
-
-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,
-					const void *body, size_t body_len,
-					int rssi, void *user_data)
-{
-	struct netdev *netdev = user_data;
-	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;
-	struct ft_ds_finder finder;
-
-	if (!netdev->connected)
-		return;
-
-	ret = ft_over_ds_parse_action_response(body, body_len, &spa, &aa,
-						&ies, &ies_len);
-	if (ret < 0)
-		return;
-
-	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;
-	}
-
-	if (!ft_over_ds_parse_action_ies(&info->super, netdev->handshake,
-						ies, ies_len))
-		goto ft_error;
-
-	info->parsed = true;
-
-	return;
-
-ft_error:
-	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);
-}
-
 static void netdev_qos_map_frame_event(const struct mmpdu_header *hdr,
 					const void *body, size_t body_len,
 					int rssi, void *user_data)
@@ -4634,16 +4549,23 @@ static bool netdev_ft_work_ready(struct wiphy_radio_work_item *item)
 {
 	struct netdev *netdev = l_container_of(item, struct netdev, work);
 
-	if (!auth_proto_start(netdev->ap)) {
-		/* Restore original nonce */
-		memcpy(netdev->handshake->snonce, netdev->prev_snonce, 32);
+	if (netdev->ft_sm) {
+		if (ft_associate(netdev->ft_sm, netdev->handshake->aa))
+			goto assoc_failed;
 
-		netdev_connect_failed(netdev, NETDEV_RESULT_ABORTED,
-						MMPDU_STATUS_CODE_UNSPECIFIED);
-		return true;
+		return false;
 	}
 
-	return false;
+	if (auth_proto_start(netdev->ap))
+		return false;
+
+assoc_failed:
+	/* Restore original nonce */
+	memcpy(netdev->handshake->snonce, netdev->prev_snonce, 32);
+
+	netdev_connect_failed(netdev, NETDEV_RESULT_ABORTED,
+						MMPDU_STATUS_CODE_UNSPECIFIED);
+	return true;
 }
 
 static const struct wiphy_radio_work_item_ops ft_work_ops = {
@@ -4684,124 +4606,38 @@ int netdev_fast_transition_over_ds(struct netdev *netdev,
 					const struct scan_bss *orig_bss,
 					netdev_connect_cb_t cb)
 {
-	struct netdev_ft_over_ds_info *info;
-	struct ft_ds_finder finder;
-
 	if (!netdev->operational)
 		return -ENOTCONN;
 
-	if (!netdev->handshake->mde || !target_bss->mde_present ||
+	if (!netdev->ft_sm || !netdev->handshake->mde ||
+			!target_bss->mde_present ||
 			l_get_le16(netdev->handshake->mde + 2) !=
 			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;
-
 	netdev->connect_cb = cb;
 
-	netdev->ap = ft_over_ds_sm_new(netdev->handshake,
-					netdev_ft_tx_associate,
-					netdev);
 	prepare_ft(netdev, target_bss);
 
-	ft_over_ds_prepare_handshake(&info->super, netdev->handshake);
-
 	wiphy_radio_work_insert(netdev->wiphy, &netdev->work,
 				WIPHY_WORK_PRIORITY_CONNECT, &ft_work_ops);
 
 	return 0;
 }
 
-static void netdev_ft_request_cb(struct l_genl_msg *msg, void *user_data)
-{
-	struct netdev_ft_over_ds_info *info = user_data;
-
-	if (l_genl_msg_get_error(msg) < 0) {
-		l_error("Could not send CMD_FRAME for FT-over-DS");
-		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);
-
-	l_free(info);
-}
-
 int netdev_fast_transition_over_ds_action(struct netdev *netdev,
 					const struct scan_bss *target_bss)
 {
-	struct netdev_ft_over_ds_info *info;
-	uint8_t ft_req[14];
-	struct handshake_state *hs = netdev->handshake;
-	struct iovec iovs[5];
-	uint8_t buf[512];
-	size_t len;
-
 	if (!netdev->operational)
 		return -ENOTCONN;
 
-	if (!netdev->handshake->mde || !target_bss->mde_present ||
+	if (!netdev->ft_sm || !netdev->handshake->mde ||
+			!target_bss->mde_present ||
 			l_get_le16(netdev->handshake->mde + 2) !=
 			l_get_le16(target_bss->mde))
 		return -EINVAL;
 
-	l_debug("");
-
-	info = l_new(struct netdev_ft_over_ds_info, 1);
-	info->netdev = netdev;
-
-	memcpy(info->super.spa, hs->spa, ETH_ALEN);
-	memcpy(info->super.aa, target_bss->addr, ETH_ALEN);
-	memcpy(info->super.mde, target_bss->mde, sizeof(info->super.mde));
-
-	if (target_bss->rsne)
-		info->super.authenticator_ie = l_memdup(target_bss->rsne,
-						target_bss->rsne[1] + 2);
-
-	l_getrandom(info->super.snonce, 32);
-	info->super.free = netdev_ft_ds_info_free;
-
-	ft_req[0] = 6; /* FT category */
-	ft_req[1] = 1; /* FT Request action */
-	memcpy(ft_req + 2, netdev->addr, 6);
-	memcpy(ft_req + 8, info->super.aa, 6);
-
-	iovs[0].iov_base = ft_req;
-	iovs[0].iov_len = sizeof(ft_req);
-
-	if (!ft_build_authenticate_ies(hs, info->super.snonce, buf, &len))
-		goto failed;
-
-	iovs[1].iov_base = buf;
-	iovs[1].iov_len = len;
-
-	iovs[2].iov_base = NULL;
-
-	if (!netdev->ft_ds_list)
-		netdev->ft_ds_list = l_queue_new();
-
-	l_queue_push_head(netdev->ft_ds_list, info);
-
-	netdev_send_action_framev(netdev, netdev->handshake->aa, iovs, 2,
-					netdev->frequency,
-					netdev_ft_request_cb,
-					info);
-
-	return 0;
-
-failed:
-	l_free(info);
-	return -EIO;
+	return ft_action(netdev->ft_sm, target_bss);
 }
 
 static void netdev_preauth_cb(const uint8_t *pmk, void *user_data)
@@ -5829,7 +5665,6 @@ static void netdev_add_station_frame_watches(struct netdev *netdev)
 	static const uint8_t action_neighbor_report_prefix[2] = { 0x05, 0x05 };
 	static const uint8_t action_sa_query_resp_prefix[2] = { 0x08, 0x01 };
 	static const uint8_t action_sa_query_req_prefix[2] = { 0x08, 0x00 };
-	static const uint8_t action_ft_response_prefix[] =  { 0x06, 0x02 };
 	static const uint8_t action_qos_map_prefix[] = { 0x01, 0x04 };
 	uint64_t wdev = netdev->wdev_id;
 
@@ -5846,10 +5681,6 @@ static void netdev_add_station_frame_watches(struct netdev *netdev)
 			sizeof(action_sa_query_req_prefix),
 			netdev_sa_query_req_frame_event, netdev, NULL);
 
-	frame_watch_add(wdev, 0, 0x00d0, action_ft_response_prefix,
-			sizeof(action_ft_response_prefix),
-			netdev_ft_response_frame_event, netdev, NULL);
-
 	if (wiphy_supports_qos_set_map(netdev->wiphy))
 		frame_watch_add(wdev, 0, 0x00d0, action_qos_map_prefix,
 				sizeof(action_qos_map_prefix),
-- 
2.34.3


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

* [PATCH v3 07/14] ft: implement offchannel authentication
  2022-09-15 22:07 [PATCH v3 01/14] frame-xchg: add type to frame_xchg_prefix James Prestwood
                   ` (4 preceding siblings ...)
  2022-09-15 22:07 ` [PATCH v3 06/14] netdev: use new ft_sm for over-DS James Prestwood
@ 2022-09-15 22:07 ` James Prestwood
  2022-09-15 22:07 ` [PATCH v3 08/14] netdev: update FT-over-Air to use ft_authenticate() James Prestwood
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: James Prestwood @ 2022-09-15 22:07 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

A new API was added, ft_authenticate, which will send an
authentication frame offchannel via CMD_FRAME. This bypasses
the kernel's authentication state allowing multiple auth
attempts to take place without disconnecting.
---
 src/ft.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/ft.h |   5 +++
 2 files changed, 139 insertions(+)

diff --git a/src/ft.c b/src/ft.c
index 2c9c92e6..559e3984 100644
--- a/src/ft.c
+++ b/src/ft.c
@@ -50,6 +50,7 @@ struct ft_info {
 	uint8_t mde[3];
 	uint8_t *fte;
 	uint8_t *authenticator_ie;
+	uint32_t frequency;
 
 	struct ie_ft_info ft_info;
 
@@ -69,6 +70,7 @@ struct ft_sm {
 	ft_tx_associate_func_t tx_assoc;
 	ft_get_oci get_oci;
 
+	ft_authenticate_cb_t auth_cb;
 	void *user_data;
 
 	bool over_ds : 1;
@@ -1082,6 +1084,8 @@ static struct ft_info *ft_info_new(struct handshake_state *hs,
 	memcpy(info->aa, target_bss->addr, 6);
 	memcpy(info->mde, target_bss->mde, sizeof(info->mde));
 
+	info->frequency = target_bss->frequency;
+
 	if (target_bss->rsne)
 		info->authenticator_ie = l_memdup(target_bss->rsne,
 						target_bss->rsne[1] + 2);
@@ -1199,6 +1203,136 @@ failed:
 	return ret;
 }
 
+static void ft_authenticate_cb(int err, void *user_data)
+{
+	if (err < 0)
+		l_debug("Failed to send FT-Authenticate");
+}
+
+static void ft_authenticate_destroy(void *user_data)
+{
+	struct ft_sm *sm = user_data;
+	struct ft_info *info = l_queue_peek_head(sm->ft_auths);
+
+	if (L_WARN_ON(!info))
+		return;
+
+	if (!info->parsed)
+		goto failed;
+
+	sm->auth_cb(0, info->aa, info->frequency, sm->user_data);
+
+	return;
+
+failed:
+	l_queue_pop_head(sm->ft_auths);
+	ft_info_destroy(info);
+
+	sm->auth_cb(-EINVAL, info->aa, info->frequency, sm->user_data);
+}
+
+static void ft_authenticate_response_cb(const struct mmpdu_header *hdr,
+					const void *body, size_t body_len,
+					int rssi, void *user_data)
+{
+	struct ft_sm *sm = user_data;
+	struct ft_info *info = l_queue_peek_head(sm->ft_auths);
+	uint16_t status;
+	const uint8_t *ies;
+	size_t ies_len;
+
+	if (!ft_parse_authentication_resp_frame((const uint8_t *)hdr,
+					mmpdu_header_len(hdr) + body_len,
+					info->spa, info->aa, info->aa, 2,
+					&status, &ies, &ies_len))
+		return;
+
+	if (status != 0)
+		return;
+
+	if (!ft_parse_ies(info, sm->hs, ies, ies_len))
+		return;
+
+	info->parsed = true;
+
+	return;
+}
+
+static const struct frame_xchg_prefix ft_prefix = {
+	.frame_type = 0x0000 | (MPDU_MANAGEMENT_SUBTYPE_AUTHENTICATION << 4),
+	.data = (uint8_t []) { 0x02, 0x00 },
+	.len = 2,
+};
+
+static bool ft_send_authenticate(struct ft_sm *sm, struct ft_info *info)
+{
+	uint64_t wdev_id = netdev_get_wdev_id(netdev_find(sm->hs->ifindex));
+	uint8_t header[28 + sizeof(struct mmpdu_authentication)];
+	uint8_t ies[256];
+	size_t len;
+	struct iovec iov[3];
+	struct mmpdu_header *mpdu = (struct mmpdu_header *) header;
+	struct mmpdu_authentication *auth;
+	struct handshake_state *hs = sm->hs;
+
+	memset(mpdu, 0, sizeof(*mpdu));
+
+	/* Header */
+	mpdu->fc.protocol_version = 0;
+	mpdu->fc.type = MPDU_TYPE_MANAGEMENT;
+	mpdu->fc.subtype = MPDU_MANAGEMENT_SUBTYPE_AUTHENTICATION;
+	memcpy(mpdu->address_1, info->aa, 6);
+	memcpy(mpdu->address_2, info->spa, 6);
+	memcpy(mpdu->address_3, info->aa, 6);
+
+	/* Authentication body */
+	auth = (void *) mmpdu_body(mpdu);
+	auth->algorithm = L_CPU_TO_LE16(MMPDU_AUTH_ALGO_FT);
+	auth->transaction_sequence = L_CPU_TO_LE16(1);
+	auth->status = L_CPU_TO_LE16(0);
+
+	iov[0].iov_base = mpdu;
+	iov[0].iov_len = mmpdu_header_len(mpdu) +
+				sizeof(struct mmpdu_authentication);
+
+	if (!ft_build_authenticate_ies(hs, info->snonce, ies, &len))
+		return false;
+
+	iov[1].iov_base = ies;
+	iov[1].iov_len = len;
+
+	iov[2].iov_base = NULL;
+
+	return frame_xchg_start(wdev_id, iov, info->frequency, 0,
+				300, 0, FRAME_GROUP_FT,
+				ft_authenticate_cb, sm,
+				ft_authenticate_destroy, &ft_prefix,
+				ft_authenticate_response_cb, NULL) != 0;
+}
+
+int ft_authenticate(struct ft_sm *sm, const struct scan_bss *target,
+			ft_authenticate_cb_t cb, void *user_data)
+{
+	struct ft_info *info = ft_info_new(sm->hs, target);
+	int ret = -EINVAL;
+
+	if (!ft_send_authenticate(sm, info))
+		goto failed;
+
+	l_queue_clear(sm->ft_auths, ft_info_destroy);
+
+	sm->auth_cb = cb;
+	sm->user_data = user_data;
+
+	l_queue_push_tail(sm->ft_auths, info);
+
+	return 0;
+
+failed:
+	l_free(info);
+	return ret;
+}
+
 int ft_associate(struct ft_sm *sm, const uint8_t *addr)
 {
 	struct ft_info *info;
diff --git a/src/ft.h b/src/ft.h
index 6e0f4271..9839128a 100644
--- a/src/ft.h
+++ b/src/ft.h
@@ -35,6 +35,9 @@ typedef int (*ft_get_oci)(void *user_data);
 
 typedef void (*ft_ds_free_func_t)(void *user_data);
 
+typedef void (*ft_authenticate_cb_t)(int err, const uint8_t *addr,
+					uint32_t freq, void *user_data);
+
 struct ft_ds_info {
 	uint8_t spa[6];
 	uint8_t aa[6];
@@ -87,3 +90,5 @@ void ft_sm_free(struct ft_sm *sm);
 
 int ft_action(struct ft_sm *sm, const struct scan_bss *target);
 int ft_associate(struct ft_sm *sm, const uint8_t *addr);
+int ft_authenticate(struct ft_sm *sm, const struct scan_bss *target,
+			ft_authenticate_cb_t cb, void *user_data);
-- 
2.34.3


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

* [PATCH v3 08/14] netdev: update FT-over-Air to use ft_authenticate()
  2022-09-15 22:07 [PATCH v3 01/14] frame-xchg: add type to frame_xchg_prefix James Prestwood
                   ` (5 preceding siblings ...)
  2022-09-15 22:07 ` [PATCH v3 07/14] ft: implement offchannel authentication James Prestwood
@ 2022-09-15 22:07 ` James Prestwood
  2022-09-15 22:07 ` [PATCH v3 09/14] ft: remove unused code after refactor James Prestwood
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: James Prestwood @ 2022-09-15 22:07 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

This removes the FT auth-proto entirely from FT-over-Air, and
instead requires using ft_authenticate/ft_associate along with
the new ft_sm state machine.

The authentication phase is now done off-channel which allows
failures to be non-fatal (eventually). Currently the behavior
isn't changed, and failing to authenticate to a BSS will result
in a disconnect.
---
 src/ft.c     |   6 +++
 src/netdev.c | 113 +++++++++++++++++----------------------------------
 2 files changed, 44 insertions(+), 75 deletions(-)

diff --git a/src/ft.c b/src/ft.c
index 559e3984..abb2f380 100644
--- a/src/ft.c
+++ b/src/ft.c
@@ -1114,6 +1114,12 @@ static void ft_prepare_handshake(struct ft_info *info,
 	if (!hs->supplicant_ie)
 		return;
 
+	if (info->authenticator_ie)
+		handshake_state_set_authenticator_ie(hs,
+						info->authenticator_ie);
+
+	memcpy(hs->mde + 2, info->mde, 3);
+
 	memcpy(hs->snonce, info->snonce, sizeof(hs->snonce));
 
 	handshake_state_set_fte(hs, info->fte);
diff --git a/src/netdev.c b/src/netdev.c
index 2519feda..cfb741db 100644
--- a/src/netdev.c
+++ b/src/netdev.c
@@ -1395,8 +1395,7 @@ static void netdev_connect_ok(struct netdev *netdev)
 		netdev->fw_roam_bss = NULL;
 	}
 
-	/* TODO: Create only for over-DS. Over-air still uses auth-proto */
-	if (netdev->handshake->mde && (netdev->handshake->mde[4] & 1)) {
+	if (netdev->handshake->mde) {
 		if (netdev->ft_sm)
 			ft_sm_free(netdev->ft_sm);
 
@@ -4375,48 +4374,6 @@ static int netdev_tx_ft_action_frame(uint32_t ifindex, const uint8_t *dest,
 	return 0;
 }
 
-static void netdev_cmd_authenticate_ft_cb(struct l_genl_msg *msg,
-						void *user_data)
-{
-	struct netdev *netdev = user_data;
-
-	netdev->connect_cmd_id = 0;
-
-	if (l_genl_msg_get_error(msg) < 0)
-		netdev_connect_failed(netdev,
-					NETDEV_RESULT_AUTHENTICATION_FAILED,
-					MMPDU_STATUS_CODE_UNSPECIFIED);
-}
-
-static void netdev_ft_tx_authenticate(struct iovec *iov,
-					size_t iov_len, void *user_data)
-{
-	struct netdev *netdev = user_data;
-	struct l_genl_msg *cmd_authenticate;
-
-	cmd_authenticate = netdev_build_cmd_authenticate(netdev,
-							NL80211_AUTHTYPE_FT);
-	l_genl_msg_append_attrv(cmd_authenticate, NL80211_ATTR_IE, iov,
-					iov_len);
-
-	netdev->connect_cmd_id = l_genl_family_send(nl80211,
-						cmd_authenticate,
-						netdev_cmd_authenticate_ft_cb,
-						netdev, NULL);
-	if (!netdev->connect_cmd_id) {
-		l_genl_msg_unref(cmd_authenticate);
-		goto restore_snonce;
-	}
-
-	return;
-
-restore_snonce:
-	memcpy(netdev->handshake->snonce, netdev->prev_snonce, 32);
-
-	netdev_connect_failed(netdev, NETDEV_RESULT_AUTHENTICATION_FAILED,
-					MMPDU_STATUS_CODE_UNSPECIFIED);
-}
-
 static int netdev_ft_tx_associate(uint32_t ifindex, const uint8_t *prev_bssid,
 					struct iovec *ft_iov, size_t n_ft_iov)
 {
@@ -4456,7 +4413,8 @@ static int netdev_ft_tx_associate(uint32_t ifindex, const uint8_t *prev_bssid,
 	return 0;
 }
 
-static void prepare_ft(struct netdev *netdev, const struct scan_bss *target_bss)
+static void prepare_ft(struct netdev *netdev, const uint8_t *addr,
+			uint32_t frequency)
 {
 	struct netdev_handshake_state *nhs;
 
@@ -4467,15 +4425,9 @@ static void prepare_ft(struct netdev *netdev, const struct scan_bss *target_bss)
 	 */
 	memcpy(netdev->prev_snonce, netdev->handshake->snonce, 32);
 
-	netdev->frequency = target_bss->frequency;
-
-	handshake_state_set_authenticator_address(netdev->handshake,
-							target_bss->addr);
+	handshake_state_set_authenticator_address(netdev->handshake, addr);
 
-	if (target_bss->rsne)
-		handshake_state_set_authenticator_ie(netdev->handshake,
-							target_bss->rsne);
-	memcpy(netdev->handshake->mde + 2, target_bss->mde, 3);
+	netdev->frequency = frequency;
 
 	netdev->handshake->active_tk_index = 0;
 	netdev->associated = false;
@@ -4549,15 +4501,10 @@ static bool netdev_ft_work_ready(struct wiphy_radio_work_item *item)
 {
 	struct netdev *netdev = l_container_of(item, struct netdev, work);
 
-	if (netdev->ft_sm) {
-		if (ft_associate(netdev->ft_sm, netdev->handshake->aa))
-			goto assoc_failed;
-
-		return false;
-	}
+	if (ft_associate(netdev->ft_sm, netdev->handshake->aa))
+		goto assoc_failed;
 
-	if (auth_proto_start(netdev->ap))
-		return false;
+	return false;
 
 assoc_failed:
 	/* Restore original nonce */
@@ -4572,6 +4519,27 @@ static const struct wiphy_radio_work_item_ops ft_work_ops = {
 	.do_work = netdev_ft_work_ready,
 };
 
+static void netdev_ft_authenticate_cb(int err, const uint8_t *addr,
+					uint32_t frequency,
+					void *user_data)
+{
+	struct netdev *netdev = user_data;
+
+	if (err < 0)
+		goto ft_failed;
+
+	prepare_ft(netdev, addr, frequency);
+
+	wiphy_radio_work_insert(netdev->wiphy, &netdev->work,
+				WIPHY_WORK_PRIORITY_CONNECT, &ft_work_ops);
+
+	return;
+
+ft_failed:
+	netdev_connect_failed(netdev, NETDEV_RESULT_AUTHENTICATION_FAILED,
+					MMPDU_STATUS_CODE_UNSPECIFIED);
+}
+
 int netdev_fast_transition(struct netdev *netdev,
 				const struct scan_bss *target_bss,
 				const struct scan_bss *orig_bss,
@@ -4580,25 +4548,20 @@ int netdev_fast_transition(struct netdev *netdev,
 	if (!netdev->operational)
 		return -ENOTCONN;
 
-	if (!netdev->handshake->mde || !target_bss->mde_present ||
+	if (!netdev->ft_sm || !netdev->handshake->mde ||
+			!target_bss->mde_present ||
 			l_get_le16(netdev->handshake->mde + 2) !=
 			l_get_le16(target_bss->mde))
 		return -EINVAL;
 
 	netdev->connect_cb = cb;
 
-	netdev->ap = ft_over_air_sm_new(netdev->handshake,
-					netdev_ft_tx_authenticate,
-					netdev_ft_tx_associate,
-					netdev_get_oci, netdev);
-	prepare_ft(netdev, target_bss);
-
-	handshake_state_new_snonce(netdev->handshake);
-
-	wiphy_radio_work_insert(netdev->wiphy, &netdev->work,
-				WIPHY_WORK_PRIORITY_CONNECT, &ft_work_ops);
-
-	return 0;
+	/*
+	 * ft_authenticate uses offchannel so we cant start a wiphy work item
+	 * until that completes
+	 */
+	return ft_authenticate(netdev->ft_sm, target_bss,
+				netdev_ft_authenticate_cb, netdev);
 }
 
 int netdev_fast_transition_over_ds(struct netdev *netdev,
@@ -4617,7 +4580,7 @@ int netdev_fast_transition_over_ds(struct netdev *netdev,
 
 	netdev->connect_cb = cb;
 
-	prepare_ft(netdev, target_bss);
+	prepare_ft(netdev, target_bss->addr, target_bss->frequency);
 
 	wiphy_radio_work_insert(netdev->wiphy, &netdev->work,
 				WIPHY_WORK_PRIORITY_CONNECT, &ft_work_ops);
-- 
2.34.3


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

* [PATCH v3 09/14] ft: remove unused code after refactor
  2022-09-15 22:07 [PATCH v3 01/14] frame-xchg: add type to frame_xchg_prefix James Prestwood
                   ` (6 preceding siblings ...)
  2022-09-15 22:07 ` [PATCH v3 08/14] netdev: update FT-over-Air to use ft_authenticate() James Prestwood
@ 2022-09-15 22:07 ` James Prestwood
  2022-09-15 22:07 ` [PATCH v3 10/14] ft: add ft_sm_can_associate James Prestwood
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: James Prestwood @ 2022-09-15 22:07 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

Removes unused code as well as makes a few functions static which
are no longer used externally.
---
 src/ft.c | 254 ++-----------------------------------------------------
 src/ft.h |  47 ----------
 2 files changed, 5 insertions(+), 296 deletions(-)

diff --git a/src/ft.c b/src/ft.c
index abb2f380..2dfa7a11 100644
--- a/src/ft.c
+++ b/src/ft.c
@@ -24,6 +24,8 @@
 #include <config.h>
 #endif
 
+#include <errno.h>
+
 #include <ell/ell.h>
 
 #include "src/ie.h"
@@ -31,8 +33,6 @@
 #include "src/crypto.h"
 #include "src/ft.h"
 #include "src/mpdu.h"
-#include "src/auth-proto.h"
-#include "src/band.h"
 #include "src/scan.h"
 #include "src/frame-xchg.h"
 #include "src/util.h"
@@ -63,13 +63,8 @@ struct ft_info_finder {
 };
 
 struct ft_sm {
-	struct auth_proto ap;
 	struct handshake_state *hs;
 
-	ft_tx_authenticate_func_t tx_auth;
-	ft_tx_associate_func_t tx_assoc;
-	ft_get_oci get_oci;
-
 	ft_authenticate_cb_t auth_cb;
 	void *user_data;
 
@@ -496,79 +491,8 @@ static bool mde_equal(const uint8_t *mde1, const uint8_t *mde2)
 	return memcmp(mde1, mde1, mde1[1] + 2) == 0;
 }
 
-bool ft_over_ds_parse_action_ies(struct ft_ds_info *info,
-					struct handshake_state *hs,
-					const uint8_t *ies,
-					size_t ies_len)
-{
-	const uint8_t *mde = NULL;
-	const uint8_t *fte = NULL;
-	bool is_rsn = hs->supplicant_ie != NULL;
-
-	if (parse_ies(hs, info->authenticator_ie, ies, ies_len,
-				&mde, &fte) < 0)
-		return false;
-
-	if (!mde_equal(info->mde, mde))
-		goto ft_error;
-
-	if (is_rsn) {
-		if (!ft_parse_fte(hs, info->snonce, fte, &info->ft_info))
-			goto ft_error;
-
-		info->fte = l_memdup(fte, fte[1] + 2);
-	} else if (fte)
-		goto ft_error;
-
-	return true;
-
-ft_error:
-	return false;
-}
-
-static int ft_process_ies(struct handshake_state *hs, const uint8_t *ies,
-			size_t ies_len)
-{
-	const uint8_t *mde = NULL;
-	const uint8_t *fte = NULL;
-	bool is_rsn = hs->supplicant_ie != NULL;
-
-	/* Check 802.11r IEs */
-	if (!ies)
-		goto ft_error;
-
-	if (parse_ies(hs, hs->authenticator_ie, ies, ies_len,
-				&mde, &fte) < 0)
-		goto ft_error;
-
-	if (!mde_equal(hs->mde, mde))
-		goto ft_error;
-
-	if (is_rsn) {
-		struct ie_ft_info ft_info;
-
-		if (!ft_parse_fte(hs, hs->snonce, fte, &ft_info))
-			goto ft_error;
-
-		handshake_state_set_fte(hs, fte);
-
-		handshake_state_set_anonce(hs, ft_info.anonce);
-
-		handshake_state_set_kh_ids(hs, ft_info.r0khid,
-						ft_info.r0khid_len,
-						ft_info.r1khid);
-
-		handshake_state_derive_ptk(hs);
-	} else if (fte)
-		goto ft_error;
-
-	return 0;
-
-ft_error:
-	return -EBADMSG;
-}
-
-int ft_over_ds_parse_action_response(const uint8_t *frame, size_t frame_len,
+static 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,
@@ -610,75 +534,6 @@ int ft_over_ds_parse_action_response(const uint8_t *frame, size_t frame_len,
 	return 0;
 }
 
-bool ft_over_ds_prepare_handshake(struct ft_ds_info *info,
-					struct handshake_state *hs)
-{
-	if (!hs->supplicant_ie)
-		return true;
-
-	memcpy(hs->snonce, info->snonce, sizeof(hs->snonce));
-
-	handshake_state_set_fte(hs, info->fte);
-
-	handshake_state_set_anonce(hs, info->ft_info.anonce);
-
-	handshake_state_set_kh_ids(hs, info->ft_info.r0khid,
-						info->ft_info.r0khid_len,
-						info->ft_info.r1khid);
-
-	handshake_state_derive_ptk(hs);
-
-	return true;
-}
-
-void ft_ds_info_free(struct ft_ds_info *info)
-{
-	__typeof__(info->free) destroy = info->free;
-
-	if (info->fte)
-		l_free(info->fte);
-
-	if (info->authenticator_ie)
-		l_free(info->authenticator_ie);
-
-	if (destroy)
-		destroy(info);
-}
-
-static int ft_rx_authenticate(struct auth_proto *ap, const uint8_t *frame,
-				size_t frame_len)
-{
-	struct ft_sm *ft = l_container_of(ap, struct ft_sm, ap);
-	uint16_t status_code = MMPDU_STATUS_CODE_UNSPECIFIED;
-	const uint8_t *ies = NULL;
-	size_t ies_len;
-	int ret;
-
-	/*
-	 * Parse the Authentication Response and validate the contents
-	 * according to 12.5.2 / 12.5.4: RSN or non-RSN Over-the-air
-	 * FT Protocol.
-	 */
-	if (!ft_parse_authentication_resp_frame(frame, frame_len, ft->hs->spa,
-						ft->hs->aa, ft->hs->aa,
-						2, &status_code,
-						&ies, &ies_len))
-		goto auth_error;
-
-	/* AP Rejected the authenticate / associate */
-	if (status_code != 0)
-		goto auth_error;
-
-	ret = ft_process_ies(ft->hs, ies, ies_len);
-	if (ret < 0)
-		goto auth_error;
-
-	return ft->get_oci(ft->user_data);
-
-auth_error:
-	return (int)status_code;
-}
-
 int __ft_rx_associate(uint32_t ifindex, const uint8_t *frame, size_t frame_len)
 {
 	struct ft_sm *ft = ft_sm_find(ifindex);
@@ -818,38 +673,7 @@ int __ft_rx_associate(uint32_t ifindex, const uint8_t *frame, size_t frame_len)
 	return 0;
 }
 
-static int ft_rx_associate(struct auth_proto *ap, const uint8_t *frame,
-				size_t frame_len)
-{
-	struct ft_sm *sm = l_container_of(ap, struct ft_sm, ap);
-
-	return __ft_rx_associate(sm->hs->ifindex, frame, frame_len);
-}
-
-static int ft_rx_oci(struct auth_proto *ap)
-{
-	struct ft_sm *ft = l_container_of(ap, struct ft_sm, ap);
-
-	return ft_tx_reassociate(ft);
-}
-
-static void ft_auth_proto_free(struct auth_proto *ap)
-{
-	struct ft_sm *ft = l_container_of(ap, struct ft_sm, ap);
-
-	l_queue_remove(sm_list, ft);
-
-	l_free(ft);
-}
-
-static bool ft_over_ds_start(struct auth_proto *ap)
-{
-	struct ft_sm *ft = l_container_of(ap, struct ft_sm, ap);
-
-	return ft_tx_reassociate(ft) == 0;
-}
-
-bool ft_build_authenticate_ies(struct handshake_state *hs,
+static bool ft_build_authenticate_ies(struct handshake_state *hs,
 				const uint8_t *new_snonce, uint8_t *buf,
 				size_t *len)
 {
@@ -920,74 +744,6 @@ bool ft_build_authenticate_ies(struct handshake_state *hs,
 	return true;
 }
 
-static bool ft_start(struct auth_proto *ap)
-{
-	struct ft_sm *ft = l_container_of(ap, struct ft_sm, ap);
-	struct handshake_state *hs = ft->hs;
-	struct iovec iov;
-	uint8_t buf[512];
-	size_t len;
-
-	if (!ft_build_authenticate_ies(hs, hs->snonce, buf, &len))
-		return false;
-
-	iov.iov_base = buf;
-	iov.iov_len = len;
-
-	ft->tx_auth(&iov, 1, ft->user_data);
-
-	return true;
-}
-
-struct auth_proto *ft_over_air_sm_new(struct handshake_state *hs,
-				ft_tx_authenticate_func_t tx_auth,
-				ft_tx_associate_func_t tx_assoc,
-				ft_get_oci get_oci,
-				void *user_data)
-{
-	struct ft_sm *ft = l_new(struct ft_sm, 1);
-
-	ft->tx_auth = tx_auth;
-	ft->tx_assoc = tx_assoc;
-	ft->get_oci = get_oci;
-	ft->hs = hs;
-	ft->user_data = user_data;
-
-	ft->ap.rx_authenticate = ft_rx_authenticate;
-	ft->ap.rx_associate = ft_rx_associate;
-	ft->ap.start = ft_start;
-	ft->ap.free = ft_auth_proto_free;
-	ft->ap.rx_oci = ft_rx_oci;
-
-	memcpy(ft->prev_bssid, hs->aa, 6);
-
-	l_queue_push_tail(sm_list, ft);
-
-	return &ft->ap;
-}
-
-struct auth_proto *ft_over_ds_sm_new(struct handshake_state *hs,
-				ft_tx_associate_func_t tx_assoc,
-				void *user_data)
-{
-	struct ft_sm *ft = l_new(struct ft_sm, 1);
-
-	ft->tx_assoc = tx_assoc;
-	ft->hs = hs;
-	ft->user_data = user_data;
-	ft->over_ds = true;
-
-	ft->ap.rx_associate = ft_rx_associate;
-	ft->ap.start = ft_over_ds_start;
-	ft->ap.free = ft_auth_proto_free;
-
-	memcpy(ft->prev_bssid, hs->aa, 6);
-
-	l_queue_push_tail(sm_list, ft);
-
-	return &ft->ap;
-}
-
 void __ft_set_tx_action_func(ft_tx_action_func_t func)
 {
 	tx_action = func;
diff --git a/src/ft.h b/src/ft.h
index 9839128a..1a18cd0e 100644
--- a/src/ft.h
+++ b/src/ft.h
@@ -26,60 +26,13 @@ struct scan_bss;
 typedef int (*ft_tx_action_func_t)(uint32_t ifindex, const uint8_t *dest,
 					struct iovec *iov, size_t iov_len);
 
-typedef void (*ft_tx_authenticate_func_t)(struct iovec *iov, size_t iov_len,
-					void *user_data);
 typedef int (*ft_tx_associate_func_t)(uint32_t ifindex,
 					const uint8_t *prev_bssid,
 					struct iovec *ie_iov, size_t iov_len);
-typedef int (*ft_get_oci)(void *user_data);
-
-typedef void (*ft_ds_free_func_t)(void *user_data);
 
 typedef void (*ft_authenticate_cb_t)(int err, const uint8_t *addr,
 					uint32_t freq, void *user_data);
 
-struct ft_ds_info {
-	uint8_t spa[6];
-	uint8_t aa[6];
-	uint8_t snonce[32];
-	uint8_t mde[3];
-	uint8_t *fte;
-	uint8_t *authenticator_ie;
-
-	struct ie_ft_info ft_info;
-
-	void (*free)(struct ft_ds_info *s);
-};
-
-void ft_ds_info_free(struct ft_ds_info *info);
-
-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(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 *ies,
-					size_t ies_len);
-
-struct auth_proto *ft_over_air_sm_new(struct handshake_state *hs,
-				ft_tx_authenticate_func_t tx_auth,
-				ft_tx_associate_func_t tx_assoc,
-				ft_get_oci get_oci,
-				void *user_data);
-
-struct auth_proto *ft_over_ds_sm_new(struct handshake_state *hs,
-				ft_tx_associate_func_t tx_assoc,
-				void *user_data);
-
-bool ft_over_ds_prepare_handshake(struct ft_ds_info *info,
-					struct handshake_state *hs);
-
 void __ft_set_tx_action_func(ft_tx_action_func_t func);
 void __ft_set_tx_associate_func(ft_tx_associate_func_t func);
 int __ft_rx_associate(uint32_t ifindex, const uint8_t *frame,
-- 
2.34.3


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

* [PATCH v3 10/14] ft: add ft_sm_can_associate
  2022-09-15 22:07 [PATCH v3 01/14] frame-xchg: add type to frame_xchg_prefix James Prestwood
                   ` (7 preceding siblings ...)
  2022-09-15 22:07 ` [PATCH v3 09/14] ft: remove unused code after refactor James Prestwood
@ 2022-09-15 22:07 ` James Prestwood
  2022-09-15 22:07 ` [PATCH v3 11/14] netdev: check for authentication for FT-over-DS James Prestwood
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: James Prestwood @ 2022-09-15 22:07 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

Checks whether or not there is a cached authenication for the target.
---
 src/ft.c | 13 +++++++++++++
 src/ft.h |  2 ++
 2 files changed, 15 insertions(+)

diff --git a/src/ft.c b/src/ft.c
index 2dfa7a11..3b3ca83b 100644
--- a/src/ft.c
+++ b/src/ft.c
@@ -1119,6 +1119,19 @@ int ft_associate(struct ft_sm *sm, const uint8_t *addr)
 	return ft_tx_reassociate(sm);
 }
 
+bool ft_sm_can_associate(struct ft_sm *sm, const struct scan_bss *target)
+{
+	struct ft_info *info;
+	struct ft_info_finder finder;
+
+	finder.spa = sm->hs->spa;
+	finder.aa = target->addr;
+
+	info = l_queue_find(sm->ft_auths, match_ft_info, &finder);
+
+	return (info && info->parsed);
+}
+
 static int ft_init(void)
 {
 	sm_list = l_queue_new();
diff --git a/src/ft.h b/src/ft.h
index 1a18cd0e..56702369 100644
--- a/src/ft.h
+++ b/src/ft.h
@@ -41,6 +41,8 @@ int __ft_rx_associate(uint32_t ifindex, const uint8_t *frame,
 struct ft_sm *ft_sm_new(struct handshake_state *hs);
 void ft_sm_free(struct ft_sm *sm);
 
+bool ft_sm_can_associate(struct ft_sm *sm, const struct scan_bss *target);
+
 int ft_action(struct ft_sm *sm, const struct scan_bss *target);
 int ft_associate(struct ft_sm *sm, const uint8_t *addr);
 int ft_authenticate(struct ft_sm *sm, const struct scan_bss *target,
-- 
2.34.3


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

* [PATCH v3 11/14] netdev: check for authentication for FT-over-DS
  2022-09-15 22:07 [PATCH v3 01/14] frame-xchg: add type to frame_xchg_prefix James Prestwood
                   ` (8 preceding siblings ...)
  2022-09-15 22:07 ` [PATCH v3 10/14] ft: add ft_sm_can_associate James Prestwood
@ 2022-09-15 22:07 ` James Prestwood
  2022-09-15 22:07 ` [PATCH v3 12/14] station: create list of roam candidates James Prestwood
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: James Prestwood @ 2022-09-15 22:07 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

If the target BSS never authenticated/responded to the initial
action frames there is no point in trying to associate. Any
attempt would fail, and cause a disconnect. Check this and return
-ENOENT so the caller can choose a different BSS.
---
 src/netdev.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/netdev.c b/src/netdev.c
index cfb741db..52ad89ba 100644
--- a/src/netdev.c
+++ b/src/netdev.c
@@ -4578,6 +4578,9 @@ int netdev_fast_transition_over_ds(struct netdev *netdev,
 			l_get_le16(target_bss->mde))
 		return -EINVAL;
 
+	if (!ft_sm_can_associate(netdev->ft_sm, target_bss))
+		return -ENOENT;
+
 	netdev->connect_cb = cb;
 
 	prepare_ft(netdev, target_bss->addr, target_bss->frequency);
-- 
2.34.3


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

* [PATCH v3 12/14] station: create list of roam candidates
  2022-09-15 22:07 [PATCH v3 01/14] frame-xchg: add type to frame_xchg_prefix James Prestwood
                   ` (9 preceding siblings ...)
  2022-09-15 22:07 ` [PATCH v3 11/14] netdev: check for authentication for FT-over-DS James Prestwood
@ 2022-09-15 22:07 ` James Prestwood
  2022-09-15 22:07 ` [PATCH v3 13/14] station: try multiple " James Prestwood
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 19+ messages in thread
From: James Prestwood @ 2022-09-15 22:07 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

The current behavior is to only find the best roam candidate, which
generally is fine. But if for whatever reason IWD fails to roam it
would be nice having a few backup BSS's rather than having to
re-scan, or worse disassociate and reconnect entirely.

This patch doesn't change the roam behavior, just prepares for
using a roam candidate list. One difference though is any roam
candidates are added to station->bss_list, rather than just the
best BSS. This shouldn't effect any external behavior.

The candidate list is built based on scan_bss rank. First we establish
a base rank, the rank of the current BSS (or zero if AP roaming). Any
BSS in the results with a higher rank, excluding the current BSS, will
be added to the sorted station->roam_bss_list as well as stations
overall BSS list. If the resulting list is empty there were no better
BSS's, otherwise station can now try to roam starting with the best
candidate (head of the roam list).
---
 src/station.c | 84 +++++++++++++++++++++++++++++++++------------------
 1 file changed, 54 insertions(+), 30 deletions(-)

diff --git a/src/station.c b/src/station.c
index 79d2c755..76023520 100644
--- a/src/station.c
+++ b/src/station.c
@@ -107,6 +107,7 @@ struct station {
 
 	/* Set of frequencies to scan first when attempting a roam */
 	struct scan_freq_set *roam_freqs;
+	struct l_queue *roam_bss_list;
 
 	/* Frequencies split into subsets by priority */
 	struct scan_freq_set *scan_freqs_order[3];
@@ -1640,6 +1641,11 @@ static void station_roam_state_clear(struct station *station)
 		scan_freq_set_free(station->roam_freqs);
 		station->roam_freqs = NULL;
 	}
+
+	if (station->roam_bss_list) {
+		l_queue_destroy(station->roam_bss_list, NULL);
+		station->roam_bss_list = NULL;
+	}
 }
 
 static void station_reset_connection_state(struct station *station)
@@ -1981,6 +1987,11 @@ static void station_roamed(struct station *station)
 			l_warn("Could not request neighbor report");
 	}
 
+	if (station->roam_bss_list) {
+		l_queue_destroy(station->roam_bss_list, NULL);
+		station->roam_bss_list = NULL;
+	}
+
 	station_ft_ds_action_start(station);
 
 	station_enter_state(station, STATION_STATE_CONNECTED);
@@ -2005,6 +2016,11 @@ static void station_roam_failed(struct station *station)
 {
 	l_debug("%u", netdev_get_ifindex(station->netdev));
 
+	if (station->roam_bss_list) {
+		l_queue_destroy(station->roam_bss_list, NULL);
+		station->roam_bss_list = NULL;
+	}
+
 	/*
 	 * If we attempted a reassociation or a fast transition, and ended up
 	 * here then we are now disconnected.
@@ -2186,8 +2202,7 @@ static void station_preauthenticate_cb(struct netdev *netdev,
 	station_transition_reassociate(station, bss, new_hs);
 }
 
-static void station_transition_start(struct station *station,
-							struct scan_bss *bss)
+static void station_transition_start(struct station *station)
 {
 	struct handshake_state *hs = netdev_get_handshake(station->netdev);
 	struct network *connected = station->connected_network;
@@ -2195,6 +2210,7 @@ static void station_transition_start(struct station *station,
 	struct handshake_state *new_hs;
 	struct ie_rsn_info cur_rsne, target_rsne;
 	int ret;
+	struct scan_bss *bss = l_queue_peek_head(station->roam_bss_list);
 
 	l_debug("%u, target %s", netdev_get_ifindex(station->netdev),
 			util_address_to_string(bss->addr));
@@ -2334,12 +2350,10 @@ static bool station_roam_scan_notify(int err, struct l_queue *bss_list,
 	struct handshake_state *hs = netdev_get_handshake(station->netdev);
 	struct scan_bss *current_bss = station->connected_bss;
 	struct scan_bss *bss;
-	struct scan_bss *best_bss = NULL;
-	double best_bss_rank = 0.0;
+	double cur_bss_rank = 0.0;
 	static const double RANK_FT_FACTOR = 1.3;
 	uint16_t mdid;
 	enum security orig_security, security;
-	bool seen = false;
 
 	if (err) {
 		station_roam_failed(station);
@@ -2358,6 +2372,21 @@ static bool station_roam_scan_notify(int err, struct l_queue *bss_list,
 		ie_parse_mobility_domain_from_data(hs->mde, hs->mde[1] + 2,
 							&mdid, NULL, NULL);
 
+	station->roam_bss_list = l_queue_new();
+
+	/*
+	 * Find the current BSS rank, use the updated result if it exists. If
+	 * this is an AP roam keep the current rank as zero to force the roam
+	 * to occur.
+	 */
+	bss = l_queue_find(bss_list, bss_match_bssid, current_bss->addr);
+	if (bss && !station->ap_directed_roaming) {
+		cur_bss_rank = bss->rank;
+
+		if (hs->mde && bss->mde_present && l_get_le16(bss->mde) == mdid)
+			cur_bss_rank *= RANK_FT_FACTOR;
+	}
+
 	/*
 	 * BSSes in the bss_list come already ranked with their initial
 	 * association preference rank value.  We only need to add preference
@@ -2379,9 +2408,8 @@ static bool station_roam_scan_notify(int err, struct l_queue *bss_list,
 				bss->frequency, bss->rank, bss->signal_strength,
 				kbps100 / 10, kbps100 % 10);
 
-		/* Skip the BSS we are connected to if doing an AP roam */
-		if (station->ap_directed_roaming && !memcmp(bss->addr,
-				station->connected_bss->addr, 6))
+		/* Skip the BSS we are connected to */
+		if (!memcmp(bss->addr, station->connected_bss->addr, 6))
 			goto next;
 
 		/* Skip result if it is not part of the ESS */
@@ -2395,8 +2423,6 @@ static bool station_roam_scan_notify(int err, struct l_queue *bss_list,
 		if (security != orig_security)
 			goto next;
 
-		seen = true;
-
 		if (network_can_connect_bss(network, bss) < 0)
 			goto next;
 
@@ -2408,15 +2434,19 @@ static bool station_roam_scan_notify(int err, struct l_queue *bss_list,
 		if (hs->mde && bss->mde_present && l_get_le16(bss->mde) == mdid)
 			rank *= RANK_FT_FACTOR;
 
-		if (rank > best_bss_rank) {
-			if (best_bss)
-				scan_bss_free(best_bss);
+		if (rank <= cur_bss_rank)
+			goto next;
 
-			best_bss = bss;
-			best_bss_rank = rank;
+		/*
+		 * We need to update/add any potential roam candidate so
+		 * station/network know it exists.
+		 */
+		station_update_roam_bss(station, bss);
 
-			continue;
-		}
+		l_queue_insert(station->roam_bss_list, bss,
+				scan_bss_rank_compare, NULL);
+
+		continue;
 
 next:
 		scan_bss_free(bss);
@@ -2424,25 +2454,17 @@ next:
 
 	l_queue_destroy(bss_list, NULL);
 
-	if (!seen)
-		goto fail_free_bss;
-
 	/* See if we have anywhere to roam to */
-	if (!best_bss || scan_bss_addr_eq(best_bss, station->connected_bss)) {
+	if (l_queue_isempty(station->roam_bss_list)) {
 		station_debug_event(station, "no-roam-candidates");
-		goto fail_free_bss;
+		goto fail;
 	}
 
-	station_update_roam_bss(station, best_bss);
-
-	station_transition_start(station, best_bss);
+	station_transition_start(station);
 
 	return true;
 
-fail_free_bss:
-	if (best_bss)
-		scan_bss_free(best_bss);
-
+fail:
 	station_roam_failed(station);
 
 	return true;
@@ -4396,10 +4418,12 @@ static bool station_force_roam_scan_notify(int err, struct l_queue *bss_list,
 
 	/* The various roam routines expect this to be set from scanning */
 	station->preparing_roam = true;
+	station->roam_bss_list = l_queue_new();
+	l_queue_push_tail(station->roam_bss_list, target);
 
 	station_update_roam_bss(station, target);
 
-	station_transition_start(station, target);
+	station_transition_start(station);
 
 	reply = l_dbus_message_new_method_return(data->pending);
 
-- 
2.34.3


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

* [PATCH v3 13/14] station: try multiple roam candidates
  2022-09-15 22:07 [PATCH v3 01/14] frame-xchg: add type to frame_xchg_prefix James Prestwood
                   ` (10 preceding siblings ...)
  2022-09-15 22:07 ` [PATCH v3 12/14] station: create list of roam candidates James Prestwood
@ 2022-09-15 22:07 ` James Prestwood
  2022-09-15 22:07 ` [PATCH v3 14/14] netdev: add NETDEV_EVENT_FT_AUTHENTICATE, handle in station James Prestwood
  2022-09-16 16:04 ` [PATCH v3 01/14] frame-xchg: add type to frame_xchg_prefix Denis Kenzior
  13 siblings, 0 replies; 19+ messages in thread
From: James Prestwood @ 2022-09-15 22:07 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

There were a few failure paths in station_transition_start which
may not always be fatal. Both FT variants could fail, e.g. if
neither FT-over-DS or FT-over-Air were able to authenticate. In
this case it would be wise to try another BSS.
---
 src/station.c | 95 +++++++++++++++++++++++++++++++--------------------
 1 file changed, 58 insertions(+), 37 deletions(-)

diff --git a/src/station.c b/src/station.c
index 76023520..25d169dc 100644
--- a/src/station.c
+++ b/src/station.c
@@ -2113,21 +2113,23 @@ static void station_fast_transition_cb(struct netdev *netdev,
 static void station_netdev_event(struct netdev *netdev, enum netdev_event event,
 					void *event_data, void *user_data);
 
-static void station_transition_reassociate(struct station *station,
+static int station_transition_reassociate(struct station *station,
 						struct scan_bss *bss,
 						struct handshake_state *new_hs)
 {
-	if (netdev_reassociate(station->netdev, bss, station->connected_bss,
+	int ret;
+
+	ret = netdev_reassociate(station->netdev, bss, station->connected_bss,
 				new_hs, station_netdev_event,
-				station_reassociate_cb, station) < 0) {
-		handshake_state_free(new_hs);
-		station_roam_failed(station);
-		return;
-	}
+				station_reassociate_cb, station);
+	if (ret < 0)
+		return ret;
 
 	station->connected_bss = bss;
 	station->preparing_roam = false;
 	station_enter_state(station, STATION_STATE_ROAMING);
+
+	return 0;
 }
 
 static bool bss_match_bssid(const void *a, const void *b)
@@ -2199,10 +2201,14 @@ static void station_preauthenticate_cb(struct netdev *netdev,
 		handshake_state_set_supplicant_ie(new_hs, rsne_buf);
 	}
 
-	station_transition_reassociate(station, bss, new_hs);
+	if (station_transition_reassociate(station, bss, new_hs) < 0) {
+		handshake_state_free(new_hs);
+		station_roam_failed(station);
+	}
 }
 
-static void station_transition_start(struct station *station)
+static bool station_try_next_transition(struct station *station,
+					struct scan_bss *bss)
 {
 	struct handshake_state *hs = netdev_get_handshake(station->netdev);
 	struct network *connected = station->connected_network;
@@ -2210,7 +2216,6 @@ static void station_transition_start(struct station *station)
 	struct handshake_state *new_hs;
 	struct ie_rsn_info cur_rsne, target_rsne;
 	int ret;
-	struct scan_bss *bss = l_queue_peek_head(station->roam_bss_list);
 
 	l_debug("%u, target %s", netdev_get_ifindex(station->netdev),
 			util_address_to_string(bss->addr));
@@ -2226,11 +2231,8 @@ static void station_transition_start(struct station *station)
 
 		/* Rebuild handshake RSN for target AP */
 		if (station_build_handshake_rsn(hs, station->wiphy,
-				station->connected_network, bss) < 0) {
-			l_error("rebuilding handshake rsne failed");
-			station_roam_failed(station);
-			return;
-		}
+				station->connected_network, bss) < 0)
+			return false;
 
 		/* Reset the vendor_ies in case they're different */
 		vendor_ies = network_info_get_extra_ies(info, bss, &iov_elems);
@@ -2243,29 +2245,23 @@ static void station_transition_start(struct station *station)
 			/* 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;
-			}
+			else if (ret < 0)
+				return false;
+
+			station->connected_bss = bss;
+			station->preparing_roam = false;
+			station_enter_state(station, STATION_STATE_ROAMING);
+
+			return true;
 		} else {
 try_over_air:
 			if (netdev_fast_transition(station->netdev, bss,
 					station->connected_bss,
-					station_fast_transition_cb) < 0) {
-				station_roam_failed(station);
-				return;
-			}
-		}
-
-		station->connected_bss = bss;
-		station->preparing_roam = false;
-		station_enter_state(station, STATION_STATE_ROAMING);
+					station_fast_transition_cb) < 0)
+				return false;
 
-		return;
+			return true;
+		}
 	}
 
 	/* Non-FT transition */
@@ -2296,17 +2292,42 @@ try_over_air:
 		if (netdev_preauthenticate(station->netdev, bss,
 						station_preauthenticate_cb,
 						station) >= 0)
-			return;
+			return true;
 	}
 
 	new_hs = station_handshake_setup(station, connected, bss);
 	if (!new_hs) {
 		l_error("station_handshake_setup failed in reassociation");
-		station_roam_failed(station);
-		return;
+		return false;
+	}
+
+	if (station_transition_reassociate(station, bss, new_hs) < 0) {
+		handshake_state_free(new_hs);
+		return false;
+	}
+
+	return true;
+}
+
+static void station_transition_start(struct station *station)
+{
+	struct scan_bss *bss;
+	bool roaming = false;
+
+	/*
+	 * For each failed attempt pop the BSS leaving the head of the queue
+	 * with the current roam candidate.
+	 */
+	while ((bss = l_queue_peek_head(station->roam_bss_list))) {
+		roaming = station_try_next_transition(station, bss);
+		if (roaming)
+			break;
+
+		l_queue_pop_head(station->roam_bss_list);
 	}
 
-	station_transition_reassociate(station, bss, new_hs);
+	if (!roaming)
+		station_roam_failed(station);
 }
 
 static void station_roam_scan_triggered(int err, void *user_data)
-- 
2.34.3


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

* [PATCH v3 14/14] netdev: add NETDEV_EVENT_FT_AUTHENTICATE, handle in station
  2022-09-15 22:07 [PATCH v3 01/14] frame-xchg: add type to frame_xchg_prefix James Prestwood
                   ` (11 preceding siblings ...)
  2022-09-15 22:07 ` [PATCH v3 13/14] station: try multiple " James Prestwood
@ 2022-09-15 22:07 ` James Prestwood
  2022-09-16 16:04 ` [PATCH v3 01/14] frame-xchg: add type to frame_xchg_prefix Denis Kenzior
  13 siblings, 0 replies; 19+ messages in thread
From: James Prestwood @ 2022-09-15 22:07 UTC (permalink / raw)
  To: iwd; +Cc: James Prestwood

Once FT-Authenticate finishes station needs to know regardless of
the outcome. For a success the current BSS/roam state needs to be
updated, and for failure station may attempt to FT to a different
BSS>
---
 src/netdev.c  | 12 +++++-------
 src/netdev.h  |  1 +
 src/station.c | 18 ++++++++++++++++++
 3 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/src/netdev.c b/src/netdev.c
index 52ad89ba..00c33691 100644
--- a/src/netdev.c
+++ b/src/netdev.c
@@ -4525,19 +4525,17 @@ static void netdev_ft_authenticate_cb(int err, const uint8_t *addr,
 {
 	struct netdev *netdev = user_data;
 
+	if (netdev->event_filter)
+		netdev->event_filter(netdev, NETDEV_EVENT_FT_AUTHENTICATE,
+					&err, netdev->user_data);
+
 	if (err < 0)
-		goto ft_failed;
+		return;
 
 	prepare_ft(netdev, addr, frequency);
 
 	wiphy_radio_work_insert(netdev->wiphy, &netdev->work,
 				WIPHY_WORK_PRIORITY_CONNECT, &ft_work_ops);
-
-	return;
-
-ft_failed:
-	netdev_connect_failed(netdev, NETDEV_RESULT_AUTHENTICATION_FAILED,
-					MMPDU_STATUS_CODE_UNSPECIFIED);
 }
 
 int netdev_fast_transition(struct netdev *netdev,
diff --git a/src/netdev.h b/src/netdev.h
index dcf3ad1b..55df9b22 100644
--- a/src/netdev.h
+++ b/src/netdev.h
@@ -50,6 +50,7 @@ enum netdev_event {
 	NETDEV_EVENT_RSSI_THRESHOLD_HIGH,
 	NETDEV_EVENT_RSSI_LEVEL_NOTIFY,
 	NETDEV_EVENT_PACKET_LOSS_NOTIFY,
+	NETDEV_EVENT_FT_AUTHENTICATE,
 };
 
 enum netdev_watch_event {
diff --git a/src/station.c b/src/station.c
index 25d169dc..47e6d39b 100644
--- a/src/station.c
+++ b/src/station.c
@@ -3134,6 +3134,21 @@ static void station_packets_lost(struct station *station, uint32_t num_pkts)
 	station_start_roam(station);
 }
 
+static void station_ft_authenticate_event(struct station *station, int err)
+{
+	struct scan_bss *target = l_queue_pop_head(station->roam_bss_list);
+
+	if (err) {
+		/* Failed target popped, continue trying more targets */
+		station_transition_start(station);
+		return;
+	}
+
+	station->connected_bss = target;
+	station->preparing_roam = false;
+	station_enter_state(station, STATION_STATE_ROAMING);
+}
+
 static void station_netdev_event(struct netdev *netdev, enum netdev_event event,
 					void *event_data, void *user_data)
 {
@@ -3172,6 +3187,9 @@ static void station_netdev_event(struct netdev *netdev, enum netdev_event event,
 	case NETDEV_EVENT_PACKET_LOSS_NOTIFY:
 		station_packets_lost(station, l_get_u32(event_data));
 		break;
+	case NETDEV_EVENT_FT_AUTHENTICATE:
+		station_ft_authenticate_event(station, *((int *)event_data));
+		break;
 	}
 }
 
-- 
2.34.3


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

* Re: [PATCH v3 01/14] frame-xchg: add type to frame_xchg_prefix
  2022-09-15 22:07 [PATCH v3 01/14] frame-xchg: add type to frame_xchg_prefix James Prestwood
                   ` (12 preceding siblings ...)
  2022-09-15 22:07 ` [PATCH v3 14/14] netdev: add NETDEV_EVENT_FT_AUTHENTICATE, handle in station James Prestwood
@ 2022-09-16 16:04 ` Denis Kenzior
  13 siblings, 0 replies; 19+ messages in thread
From: Denis Kenzior @ 2022-09-16 16:04 UTC (permalink / raw)
  To: James Prestwood, iwd

Hi James,

On 9/15/22 17:07, James Prestwood wrote:
> All uses of frame-xchg were for action frames, and the frame type
> was hard coded. Soon other frame types will be needed so the type
> must now be specified in the frame_xchg_prefix structure.
> ---
>   src/anqp.c       | 1 +
>   src/frame-xchg.c | 2 +-
>   src/frame-xchg.h | 1 +
>   src/p2p.c        | 4 ++++
>   4 files changed, 7 insertions(+), 1 deletion(-)
> 

Patch 1-2 applied, thanks.

Regards,
-Denis


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

* Re: [PATCH v3 03/14] ft: remove OCI element from auth/assoc
  2022-09-15 22:07 ` [PATCH v3 03/14] ft: remove OCI element from auth/assoc James Prestwood
@ 2022-09-16 16:05   ` Denis Kenzior
  2022-09-16 16:18     ` James Prestwood
  0 siblings, 1 reply; 19+ messages in thread
From: Denis Kenzior @ 2022-09-16 16:05 UTC (permalink / raw)
  To: James Prestwood, iwd

Hi James,

On 9/15/22 17:07, James Prestwood wrote:
> FT is moving to authentication via CMD_FRAME which breaks the ability
> to get the OCI from the kernel (since its now an offchannel operation).
> Using OCI during FT isn't that useful anyways, so its being removed.
> ---
>   src/ft.c     | 26 ++------------------------
>   src/ft.h     |  2 +-
>   src/netdev.c |  3 +--
>   3 files changed, 4 insertions(+), 27 deletions(-)
> 

Hmm, why don't we just keep this code in case the kernel starts providing us the 
OCI info prior to Associate?  These paths just won't be hit when ocvc is false, no?

Regards,
-Denis

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

* Re: [PATCH v3 04/14] frame-xchg: create global group enum
  2022-09-15 22:07 ` [PATCH v3 04/14] frame-xchg: create global group enum James Prestwood
@ 2022-09-16 16:06   ` Denis Kenzior
  2022-09-16 16:28     ` James Prestwood
  0 siblings, 1 reply; 19+ messages in thread
From: Denis Kenzior @ 2022-09-16 16:06 UTC (permalink / raw)
  To: James Prestwood, iwd

Hi James,

On 9/15/22 17:07, James Prestwood wrote:
> Only P2P utilizes groups for now but to avoid conflicts in group
> numbers for other modules create a global list which can be added
> to as needed.

A non-zero group implies opening a new nl80211 socket.  Do you really need/want 
to do this for FT?

> ---
>   src/frame-xchg.h |  7 +++++++
>   src/p2p.c        | 24 +++++++++---------------
>   2 files changed, 16 insertions(+), 15 deletions(-)
> 
> diff --git a/src/frame-xchg.h b/src/frame-xchg.h
> index 360bb4d4..5b55ded8 100644
> --- a/src/frame-xchg.h
> +++ b/src/frame-xchg.h
> @@ -37,6 +37,13 @@ struct frame_xchg_prefix {
>   	size_t len;
>   };
>   
> +enum frame_xchg_group {
> +	FRAME_GROUP_DEFAULT = 0,
> +	FRAME_GROUP_P2P_LISTEN,
> +	FRAME_GROUP_P2P_CONNECT,
> +	FRAME_GROUP_FT,

Anyway, I dropped the FT enum for now.  It doesn't belong here anyhow. 
Applied, thanks.

Regards,
-Denis

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

* Re: [PATCH v3 03/14] ft: remove OCI element from auth/assoc
  2022-09-16 16:05   ` Denis Kenzior
@ 2022-09-16 16:18     ` James Prestwood
  0 siblings, 0 replies; 19+ messages in thread
From: James Prestwood @ 2022-09-16 16:18 UTC (permalink / raw)
  To: Denis Kenzior, iwd

On Fri, 2022-09-16 at 11:05 -0500, Denis Kenzior wrote:
> Hi James,
> 
> On 9/15/22 17:07, James Prestwood wrote:
> > FT is moving to authentication via CMD_FRAME which breaks the
> > ability
> > to get the OCI from the kernel (since its now an offchannel
> > operation).
> > Using OCI during FT isn't that useful anyways, so its being
> > removed.
> > ---
> >   src/ft.c     | 26 ++------------------------
> >   src/ft.h     |  2 +-
> >   src/netdev.c |  3 +--
> >   3 files changed, 4 insertions(+), 27 deletions(-)
> > 
> 
> Hmm, why don't we just keep this code in case the kernel starts
> providing us the 
> OCI info prior to Associate?  These paths just won't be hit when ocvc
> is false, no?

True, we can leave it in there.

> 
> Regards,
> -Denis



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

* Re: [PATCH v3 04/14] frame-xchg: create global group enum
  2022-09-16 16:06   ` Denis Kenzior
@ 2022-09-16 16:28     ` James Prestwood
  0 siblings, 0 replies; 19+ messages in thread
From: James Prestwood @ 2022-09-16 16:28 UTC (permalink / raw)
  To: Denis Kenzior, iwd

On Fri, 2022-09-16 at 11:06 -0500, Denis Kenzior wrote:
> Hi James,
> 
> On 9/15/22 17:07, James Prestwood wrote:
> > Only P2P utilizes groups for now but to avoid conflicts in group
> > numbers for other modules create a global list which can be added
> > to as needed.
> 
> A non-zero group implies opening a new nl80211 socket.  Do you really
> need/want 
> to do this for FT?

I did it that way because the over-air path uses frame-xchg with a
prefix/callback provided rather than a separate frame watch. So the
frame watch is only used for that Authentication sequence.

The alternative would be a single frame watch with an extra timer...

Unless frame-xchg can handle the prefix/callback being provided to
start() with group 0, not duplicate the watch for each auth attempt,
and filter and random auth frames it might get when we aren't
expecting.
 
> 
> > ---
> >   src/frame-xchg.h |  7 +++++++
> >   src/p2p.c        | 24 +++++++++---------------
> >   2 files changed, 16 insertions(+), 15 deletions(-)
> > 
> > diff --git a/src/frame-xchg.h b/src/frame-xchg.h
> > index 360bb4d4..5b55ded8 100644
> > --- a/src/frame-xchg.h
> > +++ b/src/frame-xchg.h
> > @@ -37,6 +37,13 @@ struct frame_xchg_prefix {
> >         size_t len;
> >   };
> >   
> > +enum frame_xchg_group {
> > +       FRAME_GROUP_DEFAULT = 0,
> > +       FRAME_GROUP_P2P_LISTEN,
> > +       FRAME_GROUP_P2P_CONNECT,
> > +       FRAME_GROUP_FT,
> 
> Anyway, I dropped the FT enum for now.  It doesn't belong here
> anyhow. 
> Applied, thanks.
> 
> Regards,
> -Denis



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

end of thread, other threads:[~2022-09-16 16:28 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-15 22:07 [PATCH v3 01/14] frame-xchg: add type to frame_xchg_prefix James Prestwood
2022-09-15 22:07 ` [PATCH v3 02/14] station: don't set OCVC for FT AKMs James Prestwood
2022-09-15 22:07 ` [PATCH v3 03/14] ft: remove OCI element from auth/assoc James Prestwood
2022-09-16 16:05   ` Denis Kenzior
2022-09-16 16:18     ` James Prestwood
2022-09-15 22:07 ` [PATCH v3 04/14] frame-xchg: create global group enum James Prestwood
2022-09-16 16:06   ` Denis Kenzior
2022-09-16 16:28     ` James Prestwood
2022-09-15 22:07 ` [PATCH v3 05/14] ft: netdev: prep for FT isolation into ft.c James Prestwood
2022-09-15 22:07 ` [PATCH v3 06/14] netdev: use new ft_sm for over-DS James Prestwood
2022-09-15 22:07 ` [PATCH v3 07/14] ft: implement offchannel authentication James Prestwood
2022-09-15 22:07 ` [PATCH v3 08/14] netdev: update FT-over-Air to use ft_authenticate() James Prestwood
2022-09-15 22:07 ` [PATCH v3 09/14] ft: remove unused code after refactor James Prestwood
2022-09-15 22:07 ` [PATCH v3 10/14] ft: add ft_sm_can_associate James Prestwood
2022-09-15 22:07 ` [PATCH v3 11/14] netdev: check for authentication for FT-over-DS James Prestwood
2022-09-15 22:07 ` [PATCH v3 12/14] station: create list of roam candidates James Prestwood
2022-09-15 22:07 ` [PATCH v3 13/14] station: try multiple " James Prestwood
2022-09-15 22:07 ` [PATCH v3 14/14] netdev: add NETDEV_EVENT_FT_AUTHENTICATE, handle in station James Prestwood
2022-09-16 16:04 ` [PATCH v3 01/14] frame-xchg: add type to frame_xchg_prefix 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.