OCE: Add RSSI based association rejection support (STA)
An AP might refuse to connect a STA if it has a low RSSI. In such case, the AP informs the STA with the desired RSSI delta and a retry timeout. Any subsequent association attempt with that AP (BSS) should be avoided, unless the RSSI level improved by the desired delta or the timeout has expired. Defined in Wi-Fi Alliance Optimized Connectivity Experience technical specification v1.0, section 3.14 (RSSI-based association rejection information). Signed-off-by: Beni Lev <beni.lev@intel.com>
This commit is contained in:
parent
2994ecfb5f
commit
19677b77c3
8 changed files with 88 additions and 17 deletions
|
@ -1538,6 +1538,24 @@ const u8 * get_ie_ext(const u8 *ies, size_t len, u8 ext)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type)
|
||||||
|
{
|
||||||
|
const u8 *pos = ies, *end = ies + len;
|
||||||
|
|
||||||
|
while (end - pos > 1) {
|
||||||
|
if (2 + pos[1] > end - pos)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
|
||||||
|
vendor_type == WPA_GET_BE32(&pos[2]))
|
||||||
|
return pos;
|
||||||
|
pos += 2 + pos[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len)
|
size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -193,6 +193,7 @@ extern size_t global_op_class_size;
|
||||||
|
|
||||||
const u8 * get_ie(const u8 *ies, size_t len, u8 eid);
|
const u8 * get_ie(const u8 *ies, size_t len, u8 eid);
|
||||||
const u8 * get_ie_ext(const u8 *ies, size_t len, u8 ext);
|
const u8 * get_ie_ext(const u8 *ies, size_t len, u8 ext);
|
||||||
|
const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type);
|
||||||
|
|
||||||
size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len);
|
size_t mbo_add_ie(u8 *buf, size_t len, const u8 *attr, size_t attr_len);
|
||||||
|
|
||||||
|
|
|
@ -7959,6 +7959,8 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
|
||||||
wpa_s->ric_ies = NULL;
|
wpa_s->ric_ies = NULL;
|
||||||
|
|
||||||
wpa_supplicant_update_channel_list(wpa_s, NULL);
|
wpa_supplicant_update_channel_list(wpa_s, NULL);
|
||||||
|
|
||||||
|
free_bss_tmp_disallowed(wpa_s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1338,10 +1338,10 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wpa_is_bss_tmp_disallowed(wpa_s, bss->bssid)) {
|
if (wpa_is_bss_tmp_disallowed(wpa_s, bss)) {
|
||||||
if (debug_print)
|
if (debug_print)
|
||||||
wpa_dbg(wpa_s, MSG_DEBUG,
|
wpa_dbg(wpa_s, MSG_DEBUG,
|
||||||
" skip - MBO retry delay has not passed yet");
|
" skip - AP temporarily disallowed");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
#ifdef CONFIG_TESTING_OPTIONS
|
#ifdef CONFIG_TESTING_OPTIONS
|
||||||
|
@ -3060,7 +3060,7 @@ static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
|
||||||
!disallowed_ssid(wpa_s, fast_reconnect->ssid,
|
!disallowed_ssid(wpa_s, fast_reconnect->ssid,
|
||||||
fast_reconnect->ssid_len) &&
|
fast_reconnect->ssid_len) &&
|
||||||
!wpas_temp_disabled(wpa_s, fast_reconnect_ssid) &&
|
!wpas_temp_disabled(wpa_s, fast_reconnect_ssid) &&
|
||||||
!wpa_is_bss_tmp_disallowed(wpa_s, fast_reconnect->bssid)) {
|
!wpa_is_bss_tmp_disallowed(wpa_s, fast_reconnect)) {
|
||||||
#ifndef CONFIG_NO_SCAN_PROCESSING
|
#ifndef CONFIG_NO_SCAN_PROCESSING
|
||||||
wpa_dbg(wpa_s, MSG_DEBUG, "Try to reconnect to the same BSS");
|
wpa_dbg(wpa_s, MSG_DEBUG, "Try to reconnect to the same BSS");
|
||||||
if (wpa_supplicant_connect(wpa_s, fast_reconnect,
|
if (wpa_supplicant_connect(wpa_s, fast_reconnect,
|
||||||
|
@ -4037,6 +4037,32 @@ static void wpas_event_assoc_reject(struct wpa_supplicant *wpa_s,
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_OWE */
|
#endif /* CONFIG_OWE */
|
||||||
|
|
||||||
|
#ifdef CONFIG_MBO
|
||||||
|
if (data->assoc_reject.status_code ==
|
||||||
|
WLAN_STATUS_DENIED_POOR_CHANNEL_CONDITIONS &&
|
||||||
|
wpa_s->current_bss && data->assoc_reject.bssid &&
|
||||||
|
data->assoc_reject.resp_ies) {
|
||||||
|
const u8 *rssi_rej;
|
||||||
|
|
||||||
|
rssi_rej = mbo_get_attr_from_ies(
|
||||||
|
data->assoc_reject.resp_ies,
|
||||||
|
data->assoc_reject.resp_ies_len,
|
||||||
|
OCE_ATTR_ID_RSSI_BASED_ASSOC_REJECT);
|
||||||
|
if (rssi_rej && rssi_rej[1] == 2) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"OCE: RSSI-based association rejection from "
|
||||||
|
MACSTR " (Delta RSSI: %u, Retry Delay: %u)",
|
||||||
|
MAC2STR(data->assoc_reject.bssid),
|
||||||
|
rssi_rej[2], rssi_rej[3]);
|
||||||
|
wpa_bss_tmp_disallow(wpa_s,
|
||||||
|
data->assoc_reject.bssid,
|
||||||
|
rssi_rej[3],
|
||||||
|
rssi_rej[2] +
|
||||||
|
wpa_s->current_bss->level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_MBO */
|
||||||
|
|
||||||
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) {
|
if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) {
|
||||||
sme_event_assoc_reject(wpa_s, data);
|
sme_event_assoc_reject(wpa_s, data);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -51,6 +51,19 @@ const u8 * mbo_attr_from_mbo_ie(const u8 *mbo_ie, enum mbo_attr_id attr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len,
|
||||||
|
enum mbo_attr_id attr)
|
||||||
|
{
|
||||||
|
const u8 *mbo_ie;
|
||||||
|
|
||||||
|
mbo_ie = get_vendor_ie(ies, ies_len, MBO_IE_VENDOR_TYPE);
|
||||||
|
if (!mbo_ie)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return mbo_attr_from_mbo_ie(mbo_ie, attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr)
|
const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr)
|
||||||
{
|
{
|
||||||
const u8 *mbo, *end;
|
const u8 *mbo, *end;
|
||||||
|
@ -501,7 +514,7 @@ void wpas_mbo_ie_trans_req(struct wpa_supplicant *wpa_s, const u8 *mbo_ie,
|
||||||
|
|
||||||
if (disallowed_sec && wpa_s->current_bss)
|
if (disallowed_sec && wpa_s->current_bss)
|
||||||
wpa_bss_tmp_disallow(wpa_s, wpa_s->current_bss->bssid,
|
wpa_bss_tmp_disallow(wpa_s, wpa_s->current_bss->bssid,
|
||||||
disallowed_sec);
|
disallowed_sec, 0);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
fail:
|
fail:
|
||||||
|
|
|
@ -770,7 +770,7 @@ compare_scan_neighbor_results(struct wpa_supplicant *wpa_s, os_time_t age_secs,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wpa_is_bss_tmp_disallowed(wpa_s, target->bssid)) {
|
if (wpa_is_bss_tmp_disallowed(wpa_s, target)) {
|
||||||
wpa_printf(MSG_DEBUG,
|
wpa_printf(MSG_DEBUG,
|
||||||
"MBO: Candidate BSS " MACSTR
|
"MBO: Candidate BSS " MACSTR
|
||||||
" retry delay is not over yet",
|
" retry delay is not over yet",
|
||||||
|
|
|
@ -444,7 +444,7 @@ void free_hw_features(struct wpa_supplicant *wpa_s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s)
|
void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s)
|
||||||
{
|
{
|
||||||
struct wpa_bss_tmp_disallowed *bss, *prev;
|
struct wpa_bss_tmp_disallowed *bss, *prev;
|
||||||
|
|
||||||
|
@ -7264,16 +7264,14 @@ static void wpa_bss_tmp_disallow_timeout(void *eloop_ctx, void *timeout_ctx)
|
||||||
|
|
||||||
|
|
||||||
void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
|
void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
|
||||||
unsigned int sec)
|
unsigned int sec, int rssi_threshold)
|
||||||
{
|
{
|
||||||
struct wpa_bss_tmp_disallowed *bss;
|
struct wpa_bss_tmp_disallowed *bss;
|
||||||
|
|
||||||
bss = wpas_get_disallowed_bss(wpa_s, bssid);
|
bss = wpas_get_disallowed_bss(wpa_s, bssid);
|
||||||
if (bss) {
|
if (bss) {
|
||||||
eloop_cancel_timeout(wpa_bss_tmp_disallow_timeout, wpa_s, bss);
|
eloop_cancel_timeout(wpa_bss_tmp_disallow_timeout, wpa_s, bss);
|
||||||
eloop_register_timeout(sec, 0, wpa_bss_tmp_disallow_timeout,
|
goto finish;
|
||||||
wpa_s, bss);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bss = os_malloc(sizeof(*bss));
|
bss = os_malloc(sizeof(*bss));
|
||||||
|
@ -7286,23 +7284,31 @@ void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
|
||||||
os_memcpy(bss->bssid, bssid, ETH_ALEN);
|
os_memcpy(bss->bssid, bssid, ETH_ALEN);
|
||||||
dl_list_add(&wpa_s->bss_tmp_disallowed, &bss->list);
|
dl_list_add(&wpa_s->bss_tmp_disallowed, &bss->list);
|
||||||
wpa_set_driver_tmp_disallow_list(wpa_s);
|
wpa_set_driver_tmp_disallow_list(wpa_s);
|
||||||
|
|
||||||
|
finish:
|
||||||
|
bss->rssi_threshold = rssi_threshold;
|
||||||
eloop_register_timeout(sec, 0, wpa_bss_tmp_disallow_timeout,
|
eloop_register_timeout(sec, 0, wpa_bss_tmp_disallow_timeout,
|
||||||
wpa_s, bss);
|
wpa_s, bss);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, const u8 *bssid)
|
int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s,
|
||||||
|
struct wpa_bss *bss)
|
||||||
{
|
{
|
||||||
struct wpa_bss_tmp_disallowed *bss = NULL, *tmp, *prev;
|
struct wpa_bss_tmp_disallowed *disallowed = NULL, *tmp, *prev;
|
||||||
|
|
||||||
dl_list_for_each_safe(tmp, prev, &wpa_s->bss_tmp_disallowed,
|
dl_list_for_each_safe(tmp, prev, &wpa_s->bss_tmp_disallowed,
|
||||||
struct wpa_bss_tmp_disallowed, list) {
|
struct wpa_bss_tmp_disallowed, list) {
|
||||||
if (os_memcmp(bssid, tmp->bssid, ETH_ALEN) == 0) {
|
if (os_memcmp(bss->bssid, tmp->bssid, ETH_ALEN) == 0) {
|
||||||
bss = tmp;
|
disallowed = tmp;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!bss)
|
if (!disallowed)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (disallowed->rssi_threshold != 0 &&
|
||||||
|
bss->level > disallowed->rssi_threshold)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -451,6 +451,7 @@ struct icon_entry {
|
||||||
struct wpa_bss_tmp_disallowed {
|
struct wpa_bss_tmp_disallowed {
|
||||||
struct dl_list list;
|
struct dl_list list;
|
||||||
u8 bssid[ETH_ALEN];
|
u8 bssid[ETH_ALEN];
|
||||||
|
int rssi_threshold;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct beacon_rep_data {
|
struct beacon_rep_data {
|
||||||
|
@ -1371,6 +1372,8 @@ int wpas_mbo_ie(struct wpa_supplicant *wpa_s, u8 *buf, size_t len,
|
||||||
int add_oce_capa);
|
int add_oce_capa);
|
||||||
const u8 * mbo_attr_from_mbo_ie(const u8 *mbo_ie, enum mbo_attr_id attr);
|
const u8 * mbo_attr_from_mbo_ie(const u8 *mbo_ie, enum mbo_attr_id attr);
|
||||||
const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr);
|
const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr);
|
||||||
|
const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len,
|
||||||
|
enum mbo_attr_id attr);
|
||||||
int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s,
|
int wpas_mbo_update_non_pref_chan(struct wpa_supplicant *wpa_s,
|
||||||
const char *non_pref_chan);
|
const char *non_pref_chan);
|
||||||
void wpas_mbo_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ie);
|
void wpas_mbo_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ie);
|
||||||
|
@ -1481,8 +1484,10 @@ struct hostapd_hw_modes * get_mode(struct hostapd_hw_modes *modes,
|
||||||
u16 num_modes, enum hostapd_hw_mode mode);
|
u16 num_modes, enum hostapd_hw_mode mode);
|
||||||
|
|
||||||
void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
|
void wpa_bss_tmp_disallow(struct wpa_supplicant *wpa_s, const u8 *bssid,
|
||||||
unsigned int sec);
|
unsigned int sec, int rssi_threshold);
|
||||||
int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s, const u8 *bssid);
|
int wpa_is_bss_tmp_disallowed(struct wpa_supplicant *wpa_s,
|
||||||
|
struct wpa_bss *bss);
|
||||||
|
void free_bss_tmp_disallowed(struct wpa_supplicant *wpa_s);
|
||||||
|
|
||||||
struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
|
struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
|
||||||
int i, struct wpa_bss *bss,
|
int i, struct wpa_bss *bss,
|
||||||
|
|
Loading…
Reference in a new issue