diff mbox series

[v2,2/2] WNM: Use standard BSS selection and enable abridged bit handling

Message ID 20240918123911.120326-2-benjamin@sipsolutions.net
State New
Headers show
Series [v2,1/2] WNM: Move driver MBO transition rejection into wnm_is_bss_excluded | expand

Commit Message

Benjamin Berg Sept. 18, 2024, 12:39 p.m. UTC
From: Benjamin Berg <benjamin.berg@intel.com>

Most of the logic to reject BSSs during transition has been moved into
wnm_is_bss_excluded. In addition to this, since commit 67bf89f55442
("WNM: Choose the best available BSS, not just the first one") we will
simply choose the BSS with the best throughput.

Overall, this matches the behaviour that the supplicant will use anyway
in wpa_supplicant_select_bss. The only bigger difference is that using
this will check all known BSSs instead of only the ones in the candidate
list. This means that with this change the abridged bit is handled
according to spec.

Another slight change is that this drops the logic to reject candidates
with a very low signal level. This does not seem to very relevant
anymore as we prefere stronger BSSs to begin with.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
---
 wpa_supplicant/events.c           |   2 +-
 wpa_supplicant/wnm_sta.c          | 129 +++---------------------------
 wpa_supplicant/wpa_supplicant_i.h |   5 ++
 3 files changed, 18 insertions(+), 118 deletions(-)

Comments

Ben Greear Sept. 18, 2024, 2:08 p.m. UTC | #1
On 9/18/24 05:39, Benjamin Berg wrote:
> From: Benjamin Berg <benjamin.berg@intel.com>
> 
> Most of the logic to reject BSSs during transition has been moved into
> wnm_is_bss_excluded. In addition to this, since commit 67bf89f55442
> ("WNM: Choose the best available BSS, not just the first one") we will
> simply choose the BSS with the best throughput.

It looks like you are dropping the logic that will keep it from roaming
unless the change in estimated throughput is relatively large?

[snip]

> -	if ((!target->est_throughput && !bss_in_list->est_throughput) ||
> -	    (target->est_throughput > bss_in_list->est_throughput &&
> -	     target->est_throughput - bss_in_list->est_throughput >
> -	     bss_in_list->est_throughput >> 4)) {
> -		/* It is more than 100/16 percent better, so switch. */
> -		return target;
> -	}

Or is that somehow handled in the current code elsewhere?

Thanks,
Ben
Ben Greear Sept. 18, 2024, 4:17 p.m. UTC | #2
On 9/18/24 09:12, Berg, Benjamin wrote:
> On Wed, 2024-09-18 at 07:08 -0700, Ben Greear wrote:
>> On 9/18/24 05:39, Benjamin Berg wrote:
>>> From: Benjamin Berg <benjamin.berg@intel.com>
>>>
>>> Most of the logic to reject BSSs during transition has been moved
>>> into
>>> wnm_is_bss_excluded. In addition to this, since commit 67bf89f55442
>>> ("WNM: Choose the best available BSS, not just the first one") we
>>> will
>>> simply choose the BSS with the best throughput.
>>
>> It looks like you are dropping the logic that will keep it from
>> roaming
>> unless the change in estimated throughput is relatively large?
>>
>> [snip]
>>
>>> -	if ((!target->est_throughput && !bss_in_list-
>>>> est_throughput) ||
>>> -	    (target->est_throughput > bss_in_list-
>>>> est_throughpubelieve it does not do anything since the commit I
>>> mentionedt &&
>>> -	     target->est_throughput - bss_in_list->est_throughput
>>>>
>>> -	     bss_in_list->est_throughput >> 4)) {
>>> -		/* It is more than 100/16 percent better, so
>>> switch. */
>>> -		return target;
>>> -	}
>>
>> Or is that somehow handled in the current code elsewhere?
> 
> No, I believe it does not do anything since the commit I mentioned.
> 
> If bss_in_list is set and it is better, then it will have already been
> sorted to the start by find_better_target.
> 
> If bss_in_list is not set, then obviously the code will not be reached
> and the found target is used.
> 
> And yes, that does mean that we are effectively ignoring the
> order/precedence value in the neighbor report (apart from a zero
> preference to mean "disallowed"). But, I do not think it is a change in
> behaviour at this point in time.

We need to dampen roams in the case where a user sits between two APs at nearly the same
RSSI (well, same estimated tput).  It should not roam back and forth every time a small environmental change
happens.  The code you are removing at least attempted to do that as far as I
can tell.

Thanks,
Ben
Benjamin Berg Sept. 18, 2024, 4:17 p.m. UTC | #3
On Wed, 2024-09-18 at 07:08 -0700, Ben Greear wrote:
> On 9/18/24 05:39, Benjamin Berg wrote:
> > From: Benjamin Berg <benjamin.berg@intel.com>
> > 
> > Most of the logic to reject BSSs during transition has been moved into
> > wnm_is_bss_excluded. In addition to this, since commit 67bf89f55442
> > ("WNM: Choose the best available BSS, not just the first one") we
> > will simply choose the BSS with the best throughput.
> 
> It looks like you are dropping the logic that will keep it from roaming
> unless the change in estimated throughput is relatively large?
> 
> [snip]
> 
> > -	if ((!target->est_throughput && !bss_in_list->est_throughput) ||
> > -	    (target->est_throughput > bss_in_list->est_throught &&
> > -	     target->est_throughput - bss_in_list->est_throughput
> > > 
> > -	     bss_in_list->est_throughput >> 4)) {
> > -		/* It is more than 100/16 percent better, so switch. */
> > -		return target;
> > -	}
> 
> Or is that somehow handled in the current code elsewhere?

No, I believe it does not do anything since the commit I mentioned.

If bss_in_list is set and it is better, then it will have already been
sorted to the start by find_better_target.

If bss_in_list is not set, then obviously the code will not be reached
and the found target is used.

And yes, that does mean that we are effectively ignoring the
order/precedence value in the neighbor report (apart from a zero
preference to mean "disallowed"). But, I do not think it is a change in
behaviour at this point in time.

Benjamin
Benjamin Berg Sept. 18, 2024, 4:53 p.m. UTC | #4
On Wed, 2024-09-18 at 09:17 -0700, Ben Greear wrote:
> On 9/18/24 09:12, Berg, Benjamin wrote:
> > On Wed, 2024-09-18 at 07:08 -0700, Ben Greear wrote:
> > > On 9/18/24 05:39, Benjamin Berg wrote:
> > > 
> > > [SNIP]
> > > Or is that somehow handled in the current code elsewhere?
> > 
> > No, I believe it does not do anything since the commit I mentioned.
> > 
> > If bss_in_list is set and it is better, then it will have already been
> > sorted to the start by find_better_target.
> > 
> > If bss_in_list is not set, then obviously the code will not be reached
> > and the found target is used.
> > 
> > And yes, that does mean that we are effectively ignoring the
> > order/precedence value in the neighbor report (apart from a zero
> > preference to mean "disallowed"). But, I do not think it is a change in
> > behaviour at this point in time.
> 
> We need to dampen roams in the case where a user sits between two APs at nearly the same
> RSSI (well, same estimated tput).  It should not roam back and forth every time a small environmental change
> happens.  The code you are removing at least attempted to do that as far as I
> can tell.

Hmm, right, I misunderstood. Yes, it prevents the roam if estimated
throughput is not better by a margin.

So, we have this code path (slightly updated by this patch) in
wnm_scan_process:

	if (pre_scan_check) {
		struct os_reltime age;

		if (!bss)
			return 0;

		os_reltime_age(&bss->last_update, &age);
		if (age.sec >= 10)
			return 0;

#ifndef CONFIG_NO_ROAMING
		if (current_bss && bss != current_bss &&
		    wpa_supplicant_need_to_roam_within_ess(wpa_s, current_bss,
							   bss))
			return 0;
#endif /* CONFIG_NO_ROAMING */
	}

We could do something similar if we are allowed to stay on current_bss.

Basically we could just call wpa_supplicant_need_to_roam_within_ess
outside of the "pre_scan_check" if we are allowed to stay with the
current BSS. If that code decides that we should not roam, we simply
select current_bss as our target and are done.

Does that seem reasonable to you? We could even just have the same
100/16 logic there … but, is that actually better?

Benjamin
Ben Greear Sept. 18, 2024, 4:59 p.m. UTC | #5
On 9/18/24 09:53, Benjamin Berg wrote:
> On Wed, 2024-09-18 at 09:17 -0700, Ben Greear wrote:
>> On 9/18/24 09:12, Berg, Benjamin wrote:
>>> On Wed, 2024-09-18 at 07:08 -0700, Ben Greear wrote:
>>>> On 9/18/24 05:39, Benjamin Berg wrote:
>>>>
>>>> [SNIP]
>>>> Or is that somehow handled in the current code elsewhere?
>>>
>>> No, I believe it does not do anything since the commit I mentioned.
>>>
>>> If bss_in_list is set and it is better, then it will have already been
>>> sorted to the start by find_better_target.
>>>
>>> If bss_in_list is not set, then obviously the code will not be reached
>>> and the found target is used.
>>>
>>> And yes, that does mean that we are effectively ignoring the
>>> order/precedence value in the neighbor report (apart from a zero
>>> preference to mean "disallowed"). But, I do not think it is a change in
>>> behaviour at this point in time.
>>
>> We need to dampen roams in the case where a user sits between two APs at nearly the same
>> RSSI (well, same estimated tput).  It should not roam back and forth every time a small environmental change
>> happens.  The code you are removing at least attempted to do that as far as I
>> can tell.
> 
> Hmm, right, I misunderstood. Yes, it prevents the roam if estimated
> throughput is not better by a margin.
> 
> So, we have this code path (slightly updated by this patch) in
> wnm_scan_process:
> 
> 	if (pre_scan_check) {
> 		struct os_reltime age;
> 
> 		if (!bss)
> 			return 0;
> 
> 		os_reltime_age(&bss->last_update, &age);
> 		if (age.sec >= 10)
> 			return 0;
> 
> #ifndef CONFIG_NO_ROAMING
> 		if (current_bss && bss != current_bss &&
> 		    wpa_supplicant_need_to_roam_within_ess(wpa_s, current_bss,
> 							   bss))
> 			return 0;
> #endif /* CONFIG_NO_ROAMING */
> 	}
> 
> We could do something similar if we are allowed to stay on current_bss.
> 
> Basically we could just call wpa_supplicant_need_to_roam_within_ess
> outside of the "pre_scan_check" if we are allowed to stay with the
> current BSS. If that code decides that we should not roam, we simply
> select current_bss as our target and are done.
> 
> Does that seem reasonable to you? We could even just have the same
> 100/16 logic there … but, is that actually better?

I'm sorry, but I'm too busy with other things right now to do a good job of thinking
through your proposal.  If we _must_ (re)connect for some reason, we should take the 'best'
AP, but if we are already associated, there should be some friction to roaming.  As long
a you are satisfied you are considering and meeting these goals, then probably you
are fine.

Thanks,
Ben

> 
> Benjamin
>
diff mbox series

Patch

diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 90e1c7b9f..74f725b3b 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -1733,7 +1733,7 @@  struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
 }
 
 
-static struct wpa_bss *
+struct wpa_bss *
 wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s,
 			  struct wpa_ssid *group,
 			  struct wpa_ssid **selected_ssid,
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 3638cd543..5f9fe2c2a 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -687,117 +687,6 @@  end:
 }
 
 
-static struct wpa_bss * find_better_target(struct wpa_bss *a,
-					   struct wpa_bss *b)
-{
-	if (!a)
-		return b;
-	if (!b)
-		return a;
-
-	if (a->est_throughput > b->est_throughput) {
-		wpa_printf(MSG_DEBUG, "WNM: A is better: " MACSTR
-			   " est-tput: %d  B: " MACSTR " est-tput: %d",
-			   MAC2STR(a->bssid), a->est_throughput,
-			   MAC2STR(b->bssid), b->est_throughput);
-		return a;
-	}
-
-	wpa_printf(MSG_DEBUG, "WNM: B is better, A: " MACSTR
-		   " est-tput: %d  B: " MACSTR " est-tput: %d",
-		   MAC2STR(a->bssid), a->est_throughput,
-		   MAC2STR(b->bssid), b->est_throughput);
-	return b;
-}
-
-static struct wpa_bss *
-compare_scan_neighbor_results(struct wpa_supplicant *wpa_s,
-			      enum mbo_transition_reject_reason *reason)
-{
-	u8 i;
-	struct wpa_bss *bss = wpa_s->current_bss;
-	struct wpa_bss *target;
-	struct wpa_bss *best_target = NULL;
-	struct wpa_bss *bss_in_list = NULL;
-
-	if (!bss)
-		return NULL;
-
-	wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d",
-		   MAC2STR(wpa_s->bssid), bss->level);
-
-	for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
-		struct neighbor_report *nei;
-
-		nei = &wpa_s->wnm_neighbor_report_elements[i];
-
-		target = wpa_bss_get_bssid(wpa_s, nei->bssid);
-		if (!target) {
-			wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
-				   " (pref %d) not found in scan results",
-				   MAC2STR(nei->bssid),
-				   nei->preference_present ? nei->preference :
-				   -1);
-			continue;
-		}
-
-		/*
-		 * TODO: Could consider allowing transition to another ESS if
-		 * PMF was enabled for the association.
-		 */
-		if (!wpa_scan_res_match(wpa_s, 0, target, wpa_s->current_ssid,
-					1, 0)) {
-			wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
-				   " (pref %d) does not match the current network profile",
-				   MAC2STR(nei->bssid),
-				   nei->preference_present ? nei->preference :
-				   -1);
-			continue;
-		}
-
-		if (target->level < bss->level && target->level < -80) {
-			wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
-				   " (pref %d) does not have sufficient signal level (%d)",
-				   MAC2STR(nei->bssid),
-				   nei->preference_present ? nei->preference :
-				   -1,
-				   target->level);
-			continue;
-		}
-
-		best_target = find_better_target(target, best_target);
-		if (target == bss)
-			bss_in_list = bss;
-	}
-
-	target = best_target;
-
-	if (!target)
-		return NULL;
-
-	wpa_printf(MSG_DEBUG,
-		   "WNM: Found an acceptable preferred transition candidate BSS "
-		   MACSTR " (RSSI %d, tput: %d  bss-tput: %d)",
-		   MAC2STR(target->bssid), target->level,
-		   target->est_throughput, bss->est_throughput);
-
-	if (!bss_in_list)
-		return target;
-
-	if ((!target->est_throughput && !bss_in_list->est_throughput) ||
-	    (target->est_throughput > bss_in_list->est_throughput &&
-	     target->est_throughput - bss_in_list->est_throughput >
-	     bss_in_list->est_throughput >> 4)) {
-		/* It is more than 100/16 percent better, so switch. */
-		return target;
-	}
-
-	wpa_printf(MSG_DEBUG,
-		   "WNM: Stay with our current BSS, not enough change in estimated throughput to switch");
-	return bss_in_list;
-}
-
-
 static int wpa_bss_ies_eq(struct wpa_bss *a, struct wpa_bss *b, u8 eid)
 {
 	const u8 *ie_a, *ie_b;
@@ -1115,11 +1004,12 @@  static void wnm_bss_tm_connect(struct wpa_supplicant *wpa_s,
 
 int wnm_scan_process(struct wpa_supplicant *wpa_s, bool pre_scan_check)
 {
-	struct wpa_bss *bss;
+	struct wpa_bss *bss, *current_bss = wpa_s->current_bss;
 	struct wpa_ssid *ssid = wpa_s->current_ssid;
 	enum bss_trans_mgmt_status_code status = WNM_BSS_TM_REJECT_UNSPECIFIED;
 	enum mbo_transition_reject_reason reason =
 		MBO_TRANSITION_REJECT_REASON_UNSPECIFIED;
+	struct wpa_ssid *selected_ssid = NULL;
 
 	if (!wpa_s->wnm_dialog_token)
 		return 0;
@@ -1143,7 +1033,7 @@  int wnm_scan_process(struct wpa_supplicant *wpa_s, bool pre_scan_check)
 	fetch_drv_mbo_candidate_info(wpa_s, &reason);
 
 	/* Compare the Neighbor Report and scan results */
-	bss = compare_scan_neighbor_results(wpa_s, &reason);
+	bss = wpa_supplicant_select_bss(wpa_s, ssid, &selected_ssid, 1);
 #ifdef CONFIG_MBO
 	if (!bss && wpa_s->wnm_mbo_trans_reason_present &&
 	    wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
@@ -1169,7 +1059,7 @@  int wnm_scan_process(struct wpa_supplicant *wpa_s, bool pre_scan_check)
 				nei->drv_mbo_reject = 0;
 		}
 
-		bss = compare_scan_neighbor_results(wpa_s, &reason);
+		bss = wpa_supplicant_select_bss(wpa_s, ssid, &selected_ssid, 1);
 	}
 #endif /* CONFIG_MBO */
 
@@ -1194,9 +1084,8 @@  int wnm_scan_process(struct wpa_supplicant *wpa_s, bool pre_scan_check)
 			return 0;
 
 #ifndef CONFIG_NO_ROAMING
-		if (wpa_s->current_bss && bss != wpa_s->current_bss &&
-		    wpa_supplicant_need_to_roam_within_ess(wpa_s,
-							   wpa_s->current_bss,
+		if (current_bss && bss != current_bss &&
+		    wpa_supplicant_need_to_roam_within_ess(wpa_s, current_bss,
 							   bss))
 			return 0;
 #endif /* CONFIG_NO_ROAMING */
@@ -1208,6 +1097,12 @@  int wnm_scan_process(struct wpa_supplicant *wpa_s, bool pre_scan_check)
 		goto send_bss_resp_fail;
 	}
 
+	wpa_printf(MSG_DEBUG,
+		   "WNM: Found an acceptable preferred transition candidate BSS "
+		   MACSTR " (RSSI %d, tput: %d  bss-tput: %d)",
+		   MAC2STR(bss->bssid), bss->level, bss->est_throughput,
+		   current_bss ? current_bss->est_throughput : -1);
+
 	/* Associate to the network */
 	wnm_bss_tm_connect(wpa_s, bss, ssid, 1);
 	return 1;
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 3f704ecfd..a59ade221 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1964,6 +1964,11 @@  struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
 				     struct wpa_ssid *group,
 				     int only_first_ssid, int debug_print);
 
+struct wpa_bss * wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s,
+					   struct wpa_ssid *group,
+					   struct wpa_ssid **selected_ssid,
+					   int only_first_ssid);
+
 int wpas_ctrl_iface_get_pref_freq_list_override(struct wpa_supplicant *wpa_s,
 						enum wpa_driver_if_type if_type,
 						unsigned int *num,