All of lore.kernel.org
 help / color / mirror / Atom feed
From: James Prestwood <prestwoj@gmail.com>
To: iwd@lists.linux.dev
Cc: James Prestwood <prestwoj@gmail.com>
Subject: [PATCH v3 07/10] station: roam blacklist BSS's, and consider when roaming
Date: Tue, 25 Mar 2025 11:00:38 -0700	[thread overview]
Message-ID: <20250325180041.238676-7-prestwoj@gmail.com> (raw)
In-Reply-To: <20250325180041.238676-1-prestwoj@gmail.com>

If the BSS is requesting IWD roam elsewhere add this BSS to the
blacklist using BLACKLIST_REASON_ROAM_REQUESTED. This will lower
the chances of IWD roaming/connecting back to this BSS in the
future.

This then allows IWD to consider this blacklist state when picking
a roam candidate. Its undesireable to fully ban a roam blacklisted
BSS, so some additional sorting logic has been added. Prior to
comparing based on rank, BSS's will be sorted into 3 groups:

Optimal - Not roam blacklisted, and above the roaming threshold
Above Threshold - May be blacklisted, and above the roaming threshold
Below Threshold - BSS is below the roaming threshold
---
 src/station.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 84 insertions(+), 4 deletions(-)

diff --git a/src/station.c b/src/station.c
index e2ed78f3..e3c7c189 100644
--- a/src/station.c
+++ b/src/station.c
@@ -155,6 +155,57 @@ struct anqp_entry {
 	uint32_t pending;
 };
 
+/*
+ * Rather than sorting BSS's purely based on ranking a higher level grouping
+ * is used. The purpose of this higher order grouping is the consider the BSS's
+ * roam blacklist status. The roam blacklist is a "soft" blacklist in that we
+ * still should connect to these BSS's if they are the only "good" option.
+ * The question here is: what makes a BSS "good" vs "bad".
+ *
+ * For an initial (probably nieve) approach here we can use the RoamThreshod[5G]
+ * and sort BSS's into "above" or "below" this threshold. Within each of these
+ * groups a BSS may be blacklisted, meaning it should get sorted lower on the
+ * list compared to others within the same group.
+ *
+ * Since we have several call sites needing to check/compare these groupings
+ * a bitmask can be used to describe the grouping:
+ *
+ * Each group will have 2 bits. The lower order bit signifies the BSS is in the
+ * group, but also blacklisted. The higher order bit signifies the BSS is in
+ * the group, but not blacklisted. The bitmask between two BSS's can then be
+ * compared directly similar to rank.
+ */
+
+#define UNDER_THRESHOLD_BIT 1
+#define ABOVE_THRESHOLD_BIT 3
+
+static uint32_t evaluate_bss_group(const uint8_t *addr, uint32_t freq,
+					int16_t signal_strength)
+{
+	int threshold;
+	int signal = signal_strength / 100;
+	bool roam_blacklist;
+	uint32_t mask = 0;
+
+	if (blacklist_contains_bss(addr, BLACKLIST_REASON_CONNECT_FAILED))
+		return mask;
+
+	roam_blacklist = blacklist_contains_bss(addr,
+					BLACKLIST_REASON_ROAM_REQUESTED);
+
+	if (freq > 4000)
+		netdev_get_low_signal_thresholds(NULL, &threshold);
+	else
+		netdev_get_low_signal_thresholds(&threshold, NULL);
+
+	if (signal >= threshold)
+		set_bit(&mask, ABOVE_THRESHOLD_BIT - roam_blacklist);
+	else
+		set_bit(&mask, UNDER_THRESHOLD_BIT - roam_blacklist);
+
+	return mask;
+}
+
 /*
  * Used as entries for the roam list since holding scan_bss pointers directly
  * from station->bss_list is not 100% safe due to the possibility of the
@@ -164,11 +215,13 @@ struct roam_bss {
 	uint8_t addr[6];
 	uint16_t rank;
 	int32_t signal_strength;
+	uint32_t group;
 	bool ft_failed: 1;
 };
 
 static struct roam_bss *roam_bss_from_scan_bss(const struct scan_bss *bss,
-						uint16_t rank)
+						uint16_t rank,
+						uint32_t group)
 {
 	struct roam_bss *rbss = l_new(struct roam_bss, 1);
 
@@ -176,6 +229,7 @@ static struct roam_bss *roam_bss_from_scan_bss(const struct scan_bss *bss,
 	rbss->rank = rank;
 	rbss->signal_strength = bss->signal_strength;
 	rbss->ft_failed = false;
+	rbss->group = group;
 
 	return rbss;
 }
@@ -184,6 +238,12 @@ static int roam_bss_rank_compare(const void *a, const void *b, void *user_data)
 {
 	const struct roam_bss *new_bss = a, *bss = b;
 
+	if (bss->group > new_bss->group)
+		return 1;
+	else if (bss->group < new_bss->group)
+		return -1;
+
+	/* BSS's both have the same group, sort by rank */
 	if (bss->rank == new_bss->rank)
 		return (bss->signal_strength >
 					new_bss->signal_strength) ? 1 : -1;
@@ -2805,6 +2865,7 @@ 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;
+	uint32_t cur_bss_group = 0;
 	double cur_bss_rank = 0.0;
 	static const double RANK_FT_FACTOR = 1.3;
 	uint16_t mdid;
@@ -2835,6 +2896,9 @@ static bool station_roam_scan_notify(int err, struct l_queue *bss_list,
 	bss = l_queue_find(bss_list, bss_match_bssid, current_bss->addr);
 	if (bss && !station->ap_directed_roaming) {
 		cur_bss_rank = bss->rank;
+		cur_bss_group = evaluate_bss_group(current_bss->addr,
+						current_bss->frequency,
+						current_bss->signal_strength);
 
 		if (hs->mde && bss->mde_present && l_get_le16(bss->mde) == mdid)
 			cur_bss_rank *= RANK_FT_FACTOR;
@@ -2859,6 +2923,9 @@ static bool station_roam_scan_notify(int err, struct l_queue *bss_list,
 	while ((bss = l_queue_pop_head(bss_list))) {
 		double rank;
 		struct roam_bss *rbss;
+		uint32_t group = evaluate_bss_group(bss->addr,
+							bss->frequency,
+							bss->signal_strength);
 
 		station_print_scan_bss(bss);
 
@@ -2889,7 +2956,15 @@ 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 <= cur_bss_rank)
+		/*
+		 * First check the group:
+		 *   - If worse, disregard BSS candidate
+		 *   - If better, keep BSS candidate
+		 *   - If equal, compare based on rank
+		 */
+		if (group < cur_bss_group)
+			goto next;
+		else if (group == cur_bss_group && rank <= cur_bss_rank)
 			goto next;
 
 		/*
@@ -2898,7 +2973,7 @@ static bool station_roam_scan_notify(int err, struct l_queue *bss_list,
 		 */
 		station_update_roam_bss(station, bss);
 
-		rbss = roam_bss_from_scan_bss(bss, rank);
+		rbss = roam_bss_from_scan_bss(bss, rank, group);
 
 		l_queue_insert(station->roam_bss_list, rbss,
 				roam_bss_rank_compare, NULL);
@@ -3268,6 +3343,10 @@ static void station_ap_directed_roam(struct station *station,
 	l_timeout_remove(station->roam_trigger_timeout);
 	station->roam_trigger_timeout = NULL;
 
+	blacklist_add_bss(station->connected_bss->addr,
+				BLACKLIST_REASON_ROAM_REQUESTED);
+	station_debug_event(station, "ap-roam-blacklist-added");
+
 	if (req_mode & WNM_REQUEST_MODE_PREFERRED_CANDIDATE_LIST) {
 		l_debug("roam: AP sent a preferred candidate list");
 		station_neighbor_report_cb(station->netdev, 0, body + pos,
@@ -5344,7 +5423,8 @@ 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;
 	l_queue_push_tail(station->roam_bss_list,
-				roam_bss_from_scan_bss(target, target->rank));
+				roam_bss_from_scan_bss(target, target->rank,
+				0xffff));
 
 	station_update_roam_bss(station, target);
 
-- 
2.34.1


  parent reply	other threads:[~2025-03-25 18:01 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-03-25 18:00 [PATCH v3 01/10] station: always add BSS to network blacklist on failure James Prestwood
2025-03-25 18:00 ` [PATCH v3 02/10] auto-t: add test for disabling the timeout blacklist James Prestwood
2025-03-25 18:00 ` [PATCH v3 03/10] blacklist: include a blacklist reason when adding/finding James Prestwood
2025-03-25 18:00 ` [PATCH v3 04/10] blacklist: fix pruning to remove the entry if its expired James Prestwood
2025-03-25 18:00 ` [PATCH v3 05/10] blacklist: add new blacklist reason, ROAM_REQUESTED James Prestwood
2025-03-25 18:00 ` [PATCH v3 06/10] netdev: add netdev_get_low_signal_thresholds James Prestwood
2025-03-25 18:00 ` James Prestwood [this message]
2025-03-26 17:49   ` [PATCH v3 07/10] station: roam blacklist BSS's, and consider when roaming James Prestwood
2025-03-25 18:00 ` [PATCH v3 08/10] station: roam blacklist AP even mid-roam James Prestwood
2025-03-25 18:00 ` [PATCH v3 09/10] auto-t: add tests for AP roam blacklisting James Prestwood
2025-03-25 18:00 ` [PATCH v3 10/10] doc: document InitialRoamRequestedTimeout James Prestwood

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250325180041.238676-7-prestwoj@gmail.com \
    --to=prestwoj@gmail.com \
    --cc=iwd@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.