MBO/OCE: Work around misbehaving MBO/OCE APs that use RSN without PMF
The MBO and OCE specification require the station to mandate use of PMF when connecting to an MBO/OCE AP that uses WPA2. The earlier implementation prevented such misbehaving APs from being selected for connection completely. This looks like the safest approach to take, but unfortunately, there are deployed APs that are not compliant with the MBO/OCE requirements and this strict interpretation of the station requirements results in interoperability issues by preventing the association completely. Relax the approach by allowing noncompliant MBO/OCE APs to be selected for RSN connection without PMF to avoid the main impact of this interoperability issue. However, disable MBO/OCE functionality when PMF cannot be negotiated to try to be as compliant as practical with the MBO/OCE tech spec requirements (i.e., stop being an MBO/OCE STA for the duration of such workaround association). Also disable support for BTM in this workaround state since MBO would expect all BTM frames to be protected. Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
This commit is contained in:
parent
722c7d1958
commit
2e06cef80a
6 changed files with 43 additions and 23 deletions
|
@ -327,6 +327,7 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
|
||||||
wpas_rrm_reset(wpa_s);
|
wpas_rrm_reset(wpa_s);
|
||||||
wpa_s->wnmsleep_used = 0;
|
wpa_s->wnmsleep_used = 0;
|
||||||
wnm_clear_coloc_intf_reporting(wpa_s);
|
wnm_clear_coloc_intf_reporting(wpa_s);
|
||||||
|
wpa_s->disable_mbo_oce = 0;
|
||||||
|
|
||||||
#ifdef CONFIG_TESTING_OPTIONS
|
#ifdef CONFIG_TESTING_OPTIONS
|
||||||
wpa_s->last_tk_alg = WPA_ALG_NONE;
|
wpa_s->last_tk_alg = WPA_ALG_NONE;
|
||||||
|
@ -540,9 +541,6 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
|
||||||
const u8 *rsn_ie, *wpa_ie;
|
const u8 *rsn_ie, *wpa_ie;
|
||||||
int ret;
|
int ret;
|
||||||
int wep_ok;
|
int wep_ok;
|
||||||
#ifdef CONFIG_MBO
|
|
||||||
const u8 *oce_capa_attr;
|
|
||||||
#endif /* CONFIG_MBO */
|
|
||||||
|
|
||||||
ret = wpas_wps_ssid_bss_match(wpa_s, ssid, bss);
|
ret = wpas_wps_ssid_bss_match(wpa_s, ssid, bss);
|
||||||
if (ret >= 0)
|
if (ret >= 0)
|
||||||
|
@ -631,21 +629,6 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
|
||||||
" skip RSN IE - no mgmt frame protection enabled but AP requires it");
|
" skip RSN IE - no mgmt frame protection enabled but AP requires it");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#ifdef CONFIG_MBO
|
|
||||||
oce_capa_attr = wpas_mbo_get_bss_attr(bss,
|
|
||||||
OCE_ATTR_ID_CAPA_IND);
|
|
||||||
if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
|
|
||||||
(wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND) ||
|
|
||||||
(oce_capa_attr && oce_capa_attr[1] >= 1 &&
|
|
||||||
!(oce_capa_attr[2] & OCE_IS_STA_CFON))) &&
|
|
||||||
wpas_get_ssid_pmf(wpa_s, ssid) !=
|
|
||||||
NO_MGMT_FRAME_PROTECTION) {
|
|
||||||
if (debug_print)
|
|
||||||
wpa_dbg(wpa_s, MSG_DEBUG,
|
|
||||||
" skip RSN IE - no mgmt frame protection enabled on MBO/OCE AP");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_MBO */
|
|
||||||
|
|
||||||
if (debug_print)
|
if (debug_print)
|
||||||
wpa_dbg(wpa_s, MSG_DEBUG,
|
wpa_dbg(wpa_s, MSG_DEBUG,
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "utils/common.h"
|
#include "utils/common.h"
|
||||||
#include "common/ieee802_11_defs.h"
|
#include "common/ieee802_11_defs.h"
|
||||||
#include "common/gas.h"
|
#include "common/gas.h"
|
||||||
|
#include "rsn_supp/wpa.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "wpa_supplicant_i.h"
|
#include "wpa_supplicant_i.h"
|
||||||
#include "driver_i.h"
|
#include "driver_i.h"
|
||||||
|
@ -82,6 +83,35 @@ const u8 * wpas_mbo_get_bss_attr(struct wpa_bss *bss, enum mbo_attr_id attr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void wpas_mbo_check_pmf(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
|
||||||
|
struct wpa_ssid *ssid)
|
||||||
|
{
|
||||||
|
const u8 *rsne, *mbo, *oce;
|
||||||
|
struct wpa_ie_data ie;
|
||||||
|
|
||||||
|
wpa_s->disable_mbo_oce = 0;
|
||||||
|
if (!bss)
|
||||||
|
return;
|
||||||
|
mbo = wpas_mbo_get_bss_attr(bss, MBO_ATTR_ID_AP_CAPA_IND);
|
||||||
|
oce = wpas_mbo_get_bss_attr(bss, OCE_ATTR_ID_CAPA_IND);
|
||||||
|
if (!mbo && !oce)
|
||||||
|
return;
|
||||||
|
if (oce && oce[1] >= 1 && (oce[2] & OCE_IS_STA_CFON))
|
||||||
|
return; /* STA-CFON is not required to enable PMF */
|
||||||
|
rsne = wpa_bss_get_ie(bss, WLAN_EID_RSN);
|
||||||
|
if (!rsne || wpa_parse_wpa_ie(rsne, 2 + rsne[1], &ie) < 0)
|
||||||
|
return; /* AP is not using RSN */
|
||||||
|
|
||||||
|
if (!(ie.capabilities & WPA_CAPABILITY_MFPC))
|
||||||
|
wpa_s->disable_mbo_oce = 1; /* AP uses RSN without PMF */
|
||||||
|
if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION)
|
||||||
|
wpa_s->disable_mbo_oce = 1; /* STA uses RSN without PMF */
|
||||||
|
if (wpa_s->disable_mbo_oce)
|
||||||
|
wpa_printf(MSG_INFO,
|
||||||
|
"MBO: Disable MBO/OCE due to misbehaving AP not having enabled PMF");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void wpas_mbo_non_pref_chan_attr_body(struct wpa_supplicant *wpa_s,
|
static void wpas_mbo_non_pref_chan_attr_body(struct wpa_supplicant *wpa_s,
|
||||||
struct wpabuf *mbo,
|
struct wpabuf *mbo,
|
||||||
u8 start, u8 end)
|
u8 start, u8 end)
|
||||||
|
|
|
@ -619,7 +619,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
|
||||||
|
|
||||||
#ifdef CONFIG_MBO
|
#ifdef CONFIG_MBO
|
||||||
mbo_ie = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
|
mbo_ie = wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE);
|
||||||
if (mbo_ie) {
|
if (!wpa_s->disable_mbo_oce && mbo_ie) {
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
len = wpas_mbo_ie(wpa_s, wpa_s->sme.assoc_req_ie +
|
len = wpas_mbo_ie(wpa_s, wpa_s->sme.assoc_req_ie +
|
||||||
|
|
|
@ -1369,7 +1369,7 @@ static void ieee802_11_rx_bss_trans_mgmt_req(struct wpa_supplicant *wpa_s,
|
||||||
const u8 *vendor;
|
const u8 *vendor;
|
||||||
#endif /* CONFIG_MBO */
|
#endif /* CONFIG_MBO */
|
||||||
|
|
||||||
if (wpa_s->conf->disable_btm)
|
if (wpa_s->disable_mbo_oce || wpa_s->conf->disable_btm)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (end - pos < 5)
|
if (end - pos < 5)
|
||||||
|
|
|
@ -1720,7 +1720,7 @@ static void wpas_ext_capab_byte(struct wpa_supplicant *wpa_s, u8 *pos, int idx)
|
||||||
case 2: /* Bits 16-23 */
|
case 2: /* Bits 16-23 */
|
||||||
#ifdef CONFIG_WNM
|
#ifdef CONFIG_WNM
|
||||||
*pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
|
*pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
|
||||||
if (!wpa_s->conf->disable_btm)
|
if (!wpa_s->disable_mbo_oce && !wpa_s->conf->disable_btm)
|
||||||
*pos |= 0x08; /* Bit 19 - BSS Transition */
|
*pos |= 0x08; /* Bit 19 - BSS Transition */
|
||||||
#endif /* CONFIG_WNM */
|
#endif /* CONFIG_WNM */
|
||||||
break;
|
break;
|
||||||
|
@ -2074,6 +2074,10 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
|
||||||
bss->ie_len);
|
bss->ie_len);
|
||||||
#endif /* CONFIG_TDLS */
|
#endif /* CONFIG_TDLS */
|
||||||
|
|
||||||
|
#ifdef CONFIG_MBO
|
||||||
|
wpas_mbo_check_pmf(wpa_s, bss, ssid);
|
||||||
|
#endif /* CONFIG_MBO */
|
||||||
|
|
||||||
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
|
if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
|
||||||
ssid->mode == WPAS_MODE_INFRA) {
|
ssid->mode == WPAS_MODE_INFRA) {
|
||||||
sme_authenticate(wpa_s, bss, ssid);
|
sme_authenticate(wpa_s, bss, ssid);
|
||||||
|
@ -2832,7 +2836,7 @@ static u8 * wpas_populate_assoc_ies(
|
||||||
|
|
||||||
#ifdef CONFIG_MBO
|
#ifdef CONFIG_MBO
|
||||||
mbo_ie = bss ? wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE) : NULL;
|
mbo_ie = bss ? wpa_bss_get_vendor_ie(bss, MBO_IE_VENDOR_TYPE) : NULL;
|
||||||
if (mbo_ie) {
|
if (!wpa_s->disable_mbo_oce && mbo_ie) {
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len,
|
len = wpas_mbo_ie(wpa_s, wpa_ie + wpa_ie_len,
|
||||||
|
@ -5985,7 +5989,7 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
|
||||||
hs20_init(wpa_s);
|
hs20_init(wpa_s);
|
||||||
#endif /* CONFIG_HS20 */
|
#endif /* CONFIG_HS20 */
|
||||||
#ifdef CONFIG_MBO
|
#ifdef CONFIG_MBO
|
||||||
if (wpa_s->conf->oce) {
|
if (!wpa_s->disable_mbo_oce && wpa_s->conf->oce) {
|
||||||
if ((wpa_s->conf->oce & OCE_STA) &&
|
if ((wpa_s->conf->oce & OCE_STA) &&
|
||||||
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_OCE_STA))
|
(wpa_s->drv_flags & WPA_DRIVER_FLAGS_OCE_STA))
|
||||||
wpa_s->enable_oce = OCE_STA;
|
wpa_s->enable_oce = OCE_STA;
|
||||||
|
|
|
@ -756,6 +756,7 @@ struct wpa_supplicant {
|
||||||
unsigned int connection_ht:1;
|
unsigned int connection_ht:1;
|
||||||
unsigned int connection_vht:1;
|
unsigned int connection_vht:1;
|
||||||
unsigned int connection_he:1;
|
unsigned int connection_he:1;
|
||||||
|
unsigned int disable_mbo_oce:1;
|
||||||
|
|
||||||
struct os_reltime last_mac_addr_change;
|
struct os_reltime last_mac_addr_change;
|
||||||
int last_mac_addr_style;
|
int last_mac_addr_style;
|
||||||
|
@ -1396,6 +1397,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);
|
||||||
|
void wpas_mbo_check_pmf(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
|
||||||
|
struct wpa_ssid *ssid);
|
||||||
const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len,
|
const u8 * mbo_get_attr_from_ies(const u8 *ies, size_t ies_len,
|
||||||
enum mbo_attr_id attr);
|
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,
|
||||||
|
|
Loading…
Reference in a new issue