To avoid unexpected IOT issues, only enable EMLSR for APs that advertise a vendor IE whose OUI is on an allowlist. The emlsr_ap_gating and emlsr_oui module parameters disable or extend it. Signed-off-by: Emery Hsin --- .../net/wireless/mediatek/mt76/mt7925/mcu.c | 76 ++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 1d59c02645c6..8323c821d4d8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -20,6 +20,75 @@ static bool mt7925_vif_is_nan(struct ieee80211_vif *vif) vif->type == NL80211_IFTYPE_NAN_DATA; } +/* Only APs advertising a vendor IE with one of these OUIs may use EMLSR. */ +static bool mt7925_emlsr_ap_gating = true; +module_param_named(emlsr_ap_gating, mt7925_emlsr_ap_gating, bool, 0644); +MODULE_PARM_DESC(emlsr_ap_gating, + "gate EMLSR by the AP OUI allowlist (default on; set 0 to allow all)"); + +static u32 mt7925_emlsr_oui_allowlist_extra[8]; +static unsigned int mt7925_emlsr_oui_num; +module_param_array_named(emlsr_oui, mt7925_emlsr_oui_allowlist_extra, uint, + &mt7925_emlsr_oui_num, 0644); +MODULE_PARM_DESC(emlsr_oui, + "extra EMLSR-permitted AP OUIs, e.g. 0x000ce7,0x00037f"); + +static const u32 mt7925_emlsr_oui_allowlist_default[] = { + 0x000ce7, 0x000a00, 0x0017a5, 0x000c43, 0x00620b, 0x5c6f69, + 0xbc97e1, 0x001be9, 0x0005b5, 0x8c8474, 0x1423f3, 0x405b7f, + 0xd404e6, 0xe03e44, 0x6c92cf, 0x043201, 0x70b7e4, 0x1423f2, + 0x4857d2, 0x9c2183, 0x84160c, 0xe43d1a, 0x000db6, 0x000af7, + 0xd40129, 0x6c8375, 0xb02628, 0x001018, 0x18c086, 0x38bab0, +}; + +static bool mt7925_emlsr_oui_match(const struct cfg80211_bss_ies *ies, + const u32 *oui, unsigned int num) +{ + unsigned int i; + + /* oui_type -1 matches any vendor-specific type */ + for (i = 0; i < num; i++) { + if (cfg80211_find_vendor_ie(oui[i], -1, ies->data, ies->len)) + return true; + } + + return false; +} + +/* Return true if EMLSR is permitted for the associated AP. */ +static bool mt7925_emlsr_oui_allowed(struct wiphy *wiphy, + struct ieee80211_channel *chan, + const u8 *bssid) +{ + const struct cfg80211_bss_ies *ies; + struct cfg80211_bss *bss; + bool allowed = false; + + if (!mt7925_emlsr_ap_gating) + return true; + + /* a NULL chan matches the BSS on any channel */ + bss = cfg80211_get_bss(wiphy, chan, bssid, NULL, 0, + IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY); + if (!bss) + return false; + + rcu_read_lock(); + ies = rcu_dereference(bss->beacon_ies); + if (!ies) + ies = rcu_dereference(bss->ies); + if (ies) + allowed = mt7925_emlsr_oui_match(ies, mt7925_emlsr_oui_allowlist_default, + ARRAY_SIZE(mt7925_emlsr_oui_allowlist_default)) || + mt7925_emlsr_oui_match(ies, mt7925_emlsr_oui_allowlist_extra, + mt7925_emlsr_oui_num); + rcu_read_unlock(); + + cfg80211_put_bss(wiphy, bss); + + return allowed; +} + int mt7925_mcu_parse_response(struct mt76_dev *mdev, int cmd, struct sk_buff *skb, int seq) { @@ -3056,6 +3125,7 @@ mt7925_mcu_bss_mld_tlv(struct sk_buff *skb, struct bss_mld_tlv *mld; struct tlv *tlv; bool is_mld; + bool is_supported_ap = false; is_mld = ieee80211_vif_is_mld(link_conf->vif) || (hweight16(mvif->valid_links) > 1); @@ -3070,8 +3140,12 @@ mt7925_mcu_bss_mld_tlv(struct sk_buff *skb, mld->remap_idx = 0xff; if (phy->chip_cap & BIT(MT792x_CHIP_CAP_MLO_EML_EN)) { + is_supported_ap = mt7925_emlsr_oui_allowed(phy->mt76->hw->wiphy, + link_conf->chanreq.oper.chan, + link_conf->bssid); mld->eml_enable = !!(link_conf->vif->cfg.eml_cap & - IEEE80211_EML_CAP_EMLSR_SUPP); + IEEE80211_EML_CAP_EMLSR_SUPP) && + is_supported_ap; } else { mld->eml_enable = 0; } -- 2.45.2