WNM: Keep BTM information until connection completes

In the MLD case, the information from the transition management request
is relevant during the association process in order to filter out links
that were disallowed by the BTM request. Also, the information remains
useful should a connection attempt fail.

To enable these scenarios, keep the information around until the
connection has completed. As this might make it impossible to establish
a connection, also clear this information at the same time that a normal
BSS ignore is cleared to avoid getting stuck in case the transition
fails unexpectedly.

Signed-off-by: Benjamin Berg <benjamin.berg@intel.com>
This commit is contained in:
Benjamin Berg 2024-02-20 14:18:27 +01:00 committed by Jouni Malinen
parent 17a2aa822c
commit e508c070c4
6 changed files with 47 additions and 28 deletions

View file

@ -8850,6 +8850,8 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_s->next_ssid = NULL; wpa_s->next_ssid = NULL;
wnm_btm_reset(wpa_s);
#ifdef CONFIG_INTERWORKING #ifdef CONFIG_INTERWORKING
#ifdef CONFIG_HS20 #ifdef CONFIG_HS20
hs20_cancel_fetch_osu(wpa_s); hs20_cancel_fetch_osu(wpa_s);

View file

@ -1802,10 +1802,12 @@ struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
break; break;
} }
if (selected == NULL && wpa_s->bssid_ignore && if (!selected &&
(wpa_s->bssid_ignore || wnm_active_bss_trans_mgmt(wpa_s)) &&
!wpa_s->countermeasures) { !wpa_s->countermeasures) {
wpa_dbg(wpa_s, MSG_DEBUG, wpa_dbg(wpa_s, MSG_DEBUG,
"No APs found - clear BSSID ignore list and try again"); "No APs found - clear BSSID ignore list and try again");
wnm_btm_reset(wpa_s);
wpa_bssid_ignore_clear(wpa_s); wpa_bssid_ignore_clear(wpa_s);
wpa_s->bssid_ignore_cleared = true; wpa_s->bssid_ignore_cleared = true;
} else if (selected == NULL) } else if (selected == NULL)

View file

@ -418,7 +418,7 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s,
} }
void wnm_deallocate_memory(struct wpa_supplicant *wpa_s) void wnm_btm_reset(struct wpa_supplicant *wpa_s)
{ {
int i; int i;
@ -430,6 +430,18 @@ void wnm_deallocate_memory(struct wpa_supplicant *wpa_s)
wpa_s->wnm_num_neighbor_report = 0; wpa_s->wnm_num_neighbor_report = 0;
os_free(wpa_s->wnm_neighbor_report_elements); os_free(wpa_s->wnm_neighbor_report_elements);
wpa_s->wnm_neighbor_report_elements = NULL; wpa_s->wnm_neighbor_report_elements = NULL;
wpa_s->wnm_cand_valid_until.sec = 0;
wpa_s->wnm_cand_valid_until.usec = 0;
wpa_s->wnm_mode = 0;
wpa_s->wnm_dialog_token = 0;
wpa_s->wnm_reply = 0;
#ifdef CONFIG_MBO
wpa_s->wnm_mbo_trans_reason_present = 0;
wpa_s->wnm_mbo_transition_reason = 0;
#endif /* CONFIG_MBO */
} }
@ -1140,7 +1152,7 @@ static void wnm_bss_tm_connect(struct wpa_supplicant *wpa_s,
if (bss == wpa_s->current_bss) { if (bss == wpa_s->current_bss) {
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
"WNM: Already associated with the preferred candidate"); "WNM: Already associated with the preferred candidate");
wnm_deallocate_memory(wpa_s); wnm_btm_reset(wpa_s);
return; return;
} }
@ -1156,7 +1168,6 @@ static void wnm_bss_tm_connect(struct wpa_supplicant *wpa_s,
*/ */
if (!already_connecting && radio_work_pending(wpa_s, "sme-connect")) if (!already_connecting && radio_work_pending(wpa_s, "sme-connect"))
wpa_s->bss_trans_mgmt_in_progress = true; wpa_s->bss_trans_mgmt_in_progress = true;
wnm_deallocate_memory(wpa_s);
} }
@ -1168,24 +1179,17 @@ int wnm_scan_process(struct wpa_supplicant *wpa_s, bool pre_scan_check)
enum mbo_transition_reject_reason reason = enum mbo_transition_reject_reason reason =
MBO_TRANSITION_REJECT_REASON_UNSPECIFIED; MBO_TRANSITION_REJECT_REASON_UNSPECIFIED;
if (!wpa_s->wnm_neighbor_report_elements) if (!wpa_s->wnm_dialog_token)
return 0; return 0;
wpa_dbg(wpa_s, MSG_DEBUG, wpa_dbg(wpa_s, MSG_DEBUG,
"WNM: Process scan results for BSS Transition Management"); "WNM: Process scan results for BSS Transition Management");
if (!pre_scan_check && if (!pre_scan_check &&
os_reltime_initialized(&wpa_s->wnm_cand_valid_until) &&
os_reltime_before(&wpa_s->wnm_cand_valid_until, os_reltime_before(&wpa_s->wnm_cand_valid_until,
&wpa_s->scan_trigger_time)) { &wpa_s->scan_trigger_time)) {
wpa_printf(MSG_DEBUG, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it"); wpa_printf(MSG_DEBUG, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it");
wnm_deallocate_memory(wpa_s); goto send_bss_resp_fail;
return 0;
}
if (!wpa_s->current_bss ||
!ether_addr_equal(wpa_s->wnm_cand_from_bss,
wpa_s->current_bss->bssid)) {
wpa_printf(MSG_DEBUG, "WNM: Stored BSS transition candidate list not from the current BSS - ignore it");
return 0;
} }
/* Compare the Neighbor Report and scan results */ /* Compare the Neighbor Report and scan results */
@ -1212,7 +1216,7 @@ int wnm_scan_process(struct wpa_supplicant *wpa_s, bool pre_scan_check)
return 0; return 0;
#ifndef CONFIG_NO_ROAMING #ifndef CONFIG_NO_ROAMING
if (bss != wpa_s->current_bss && if (wpa_s->current_bss && bss != wpa_s->current_bss &&
wpa_supplicant_need_to_roam_within_ess(wpa_s, wpa_supplicant_need_to_roam_within_ess(wpa_s,
wpa_s->current_bss, wpa_s->current_bss,
bss)) bss))
@ -1237,7 +1241,7 @@ send_bss_resp_fail:
wnm_send_bss_transition_mgmt_resp(wpa_s, status, reason, wnm_send_bss_transition_mgmt_resp(wpa_s, status, reason,
0, NULL); 0, NULL);
wnm_deallocate_memory(wpa_s); wnm_btm_reset(wpa_s);
return 0; return 0;
} }
@ -1389,16 +1393,13 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
if (end - pos < 5) if (end - pos < 5)
return; return;
#ifdef CONFIG_MBO
wpa_s->wnm_mbo_trans_reason_present = 0;
wpa_s->wnm_mbo_transition_reason = 0;
#endif /* CONFIG_MBO */
if (wpa_s->current_bss) if (wpa_s->current_bss)
beacon_int = wpa_s->current_bss->beacon_int; beacon_int = wpa_s->current_bss->beacon_int;
else else
beacon_int = 100; /* best guess */ beacon_int = 100; /* best guess */
wnm_btm_reset(wpa_s);
wpa_s->wnm_dialog_token = pos[0]; wpa_s->wnm_dialog_token = pos[0];
wpa_s->wnm_mode = pos[1]; wpa_s->wnm_mode = pos[1];
wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2); wpa_s->wnm_dissoc_timer = WPA_GET_LE16(pos + 2);
@ -1517,7 +1518,6 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
unsigned int valid_ms; unsigned int valid_ms;
wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available"); wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available");
wnm_deallocate_memory(wpa_s);
wpa_s->wnm_neighbor_report_elements = os_calloc( wpa_s->wnm_neighbor_report_elements = os_calloc(
WNM_MAX_NEIGHBOR_REPORT, WNM_MAX_NEIGHBOR_REPORT,
sizeof(struct neighbor_report)); sizeof(struct neighbor_report));
@ -1592,7 +1592,6 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
wpa_s->wnm_cand_valid_until.sec += wpa_s->wnm_cand_valid_until.sec +=
wpa_s->wnm_cand_valid_until.usec / 1000000; wpa_s->wnm_cand_valid_until.usec / 1000000;
wpa_s->wnm_cand_valid_until.usec %= 1000000; wpa_s->wnm_cand_valid_until.usec %= 1000000;
os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN);
/* /*
* Try fetching the latest scan results from the kernel. * Try fetching the latest scan results from the kernel.

View file

@ -65,7 +65,6 @@ int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
const char *btm_candidates, const char *btm_candidates,
int cand_list); int cand_list);
void wnm_deallocate_memory(struct wpa_supplicant *wpa_s);
int wnm_send_coloc_intf_report(struct wpa_supplicant *wpa_s, u8 dialog_token, int wnm_send_coloc_intf_report(struct wpa_supplicant *wpa_s, u8 dialog_token,
const struct wpabuf *elems); const struct wpabuf *elems);
void wnm_set_coloc_intf_elems(struct wpa_supplicant *wpa_s, void wnm_set_coloc_intf_elems(struct wpa_supplicant *wpa_s,
@ -81,6 +80,13 @@ void wnm_clear_coloc_intf_reporting(struct wpa_supplicant *wpa_s);
bool wnm_is_bss_excluded(struct wpa_supplicant *wpa_s, struct wpa_bss *bss); bool wnm_is_bss_excluded(struct wpa_supplicant *wpa_s, struct wpa_bss *bss);
void wnm_btm_reset(struct wpa_supplicant *wpa_s);
static inline bool wnm_active_bss_trans_mgmt(struct wpa_supplicant *wpa_s)
{
return !!wpa_s->wnm_dialog_token;
}
#else /* CONFIG_WNM */ #else /* CONFIG_WNM */
static inline int wnm_scan_process(struct wpa_supplicant *wpa_s, static inline int wnm_scan_process(struct wpa_supplicant *wpa_s,
@ -99,6 +105,15 @@ wnm_is_bss_excluded(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
return false; return false;
} }
static inline void wnm_btm_reset(struct wpa_supplicant *wpa_s)
{
}
static inline bool wnm_active_bss_trans_mgmt(struct wpa_supplicant *wpa_s)
{
return false;
}
#endif /* CONFIG_WNM */ #endif /* CONFIG_WNM */
#endif /* WNM_STA_H */ #endif /* WNM_STA_H */

View file

@ -676,9 +676,7 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
wpa_s->disallow_aps_ssid = NULL; wpa_s->disallow_aps_ssid = NULL;
wnm_bss_keep_alive_deinit(wpa_s); wnm_bss_keep_alive_deinit(wpa_s);
#ifdef CONFIG_WNM wnm_btm_reset(wpa_s);
wnm_deallocate_memory(wpa_s);
#endif /* CONFIG_WNM */
ext_password_deinit(wpa_s->ext_pw); ext_password_deinit(wpa_s->ext_pw);
wpa_s->ext_pw = NULL; wpa_s->ext_pw = NULL;
@ -1076,6 +1074,10 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
if (state == WPA_DISCONNECTED || state == WPA_INACTIVE) if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
wpa_supplicant_start_autoscan(wpa_s); wpa_supplicant_start_autoscan(wpa_s);
if (state == WPA_COMPLETED || state == WPA_INTERFACE_DISABLED ||
state == WPA_INACTIVE)
wnm_btm_reset(wpa_s);
#ifndef CONFIG_NO_WMM_AC #ifndef CONFIG_NO_WMM_AC
if (old_state >= WPA_ASSOCIATED && wpa_s->wpa_state < WPA_ASSOCIATED) if (old_state >= WPA_ASSOCIATED && wpa_s->wpa_state < WPA_ASSOCIATED)
wmm_ac_notify_disassoc(wpa_s); wmm_ac_notify_disassoc(wpa_s);

View file

@ -1310,7 +1310,6 @@ struct wpa_supplicant {
u8 wnm_bss_termination_duration[12]; u8 wnm_bss_termination_duration[12];
struct neighbor_report *wnm_neighbor_report_elements; struct neighbor_report *wnm_neighbor_report_elements;
struct os_reltime wnm_cand_valid_until; struct os_reltime wnm_cand_valid_until;
u8 wnm_cand_from_bss[ETH_ALEN];
struct wpa_bss *wnm_target_bss; struct wpa_bss *wnm_target_bss;
enum bss_trans_mgmt_status_code bss_tm_status; enum bss_trans_mgmt_status_code bss_tm_status;
bool bss_trans_mgmt_in_progress; bool bss_trans_mgmt_in_progress;