diff options
Diffstat (limited to 'net/wireless/scan.c')
-rw-r--r-- | net/wireless/scan.c | 115 |
1 files changed, 76 insertions, 39 deletions
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 0222ede0feb6..d99319d82205 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -1604,7 +1604,7 @@ struct cfg80211_bss *__cfg80211_get_bss(struct wiphy *wiphy, } EXPORT_SYMBOL(__cfg80211_get_bss); -static void rb_insert_bss(struct cfg80211_registered_device *rdev, +static bool rb_insert_bss(struct cfg80211_registered_device *rdev, struct cfg80211_internal_bss *bss) { struct rb_node **p = &rdev->bss_tree.rb_node; @@ -1620,7 +1620,7 @@ static void rb_insert_bss(struct cfg80211_registered_device *rdev, if (WARN_ON(!cmp)) { /* will sort of leak this BSS */ - return; + return false; } if (cmp < 0) @@ -1631,6 +1631,7 @@ static void rb_insert_bss(struct cfg80211_registered_device *rdev, rb_link_node(&bss->rbn, parent, p); rb_insert_color(&bss->rbn, &rdev->bss_tree); + return true; } static struct cfg80211_internal_bss * @@ -1657,6 +1658,34 @@ rb_find_bss(struct cfg80211_registered_device *rdev, return NULL; } +static void cfg80211_insert_bss(struct cfg80211_registered_device *rdev, + struct cfg80211_internal_bss *bss) +{ + lockdep_assert_held(&rdev->bss_lock); + + if (!rb_insert_bss(rdev, bss)) + return; + list_add_tail(&bss->list, &rdev->bss_list); + rdev->bss_entries++; +} + +static void cfg80211_rehash_bss(struct cfg80211_registered_device *rdev, + struct cfg80211_internal_bss *bss) +{ + lockdep_assert_held(&rdev->bss_lock); + + rb_erase(&bss->rbn, &rdev->bss_tree); + if (!rb_insert_bss(rdev, bss)) { + list_del(&bss->list); + if (!list_empty(&bss->hidden_list)) + list_del_init(&bss->hidden_list); + if (!list_empty(&bss->pub.nontrans_list)) + list_del_init(&bss->pub.nontrans_list); + rdev->bss_entries--; + } + rdev->bss_generation++; +} + static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev, struct cfg80211_internal_bss *new) { @@ -1969,9 +1998,7 @@ __cfg80211_bss_update(struct cfg80211_registered_device *rdev, bss_ref_get(rdev, bss_from_pub(tmp->pub.transmitted_bss)); } - list_add_tail(&new->list, &rdev->bss_list); - rdev->bss_entries++; - rb_insert_bss(rdev, new); + cfg80211_insert_bss(rdev, new); found = new; } @@ -2136,38 +2163,53 @@ struct cfg80211_inform_single_bss_data { u64 cannot_use_reasons; }; -static bool cfg80211_6ghz_power_type_valid(const u8 *ie, size_t ielen, - const u32 flags) +enum ieee80211_ap_reg_power +cfg80211_get_6ghz_power_type(const u8 *elems, size_t elems_len) { - const struct element *tmp; + const struct ieee80211_he_6ghz_oper *he_6ghz_oper; struct ieee80211_he_operation *he_oper; + const struct element *tmp; - tmp = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION, ie, ielen); - if (tmp && tmp->datalen >= sizeof(*he_oper) + 1 && - tmp->datalen >= ieee80211_he_oper_size(tmp->data + 1)) { - const struct ieee80211_he_6ghz_oper *he_6ghz_oper; - - he_oper = (void *)&tmp->data[1]; - he_6ghz_oper = ieee80211_he_6ghz_oper(he_oper); - - if (!he_6ghz_oper) - return false; + tmp = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION, + elems, elems_len); + if (!tmp || tmp->datalen < sizeof(*he_oper) + 1 || + tmp->datalen < ieee80211_he_oper_size(tmp->data + 1)) + return IEEE80211_REG_UNSET_AP; + + he_oper = (void *)&tmp->data[1]; + he_6ghz_oper = ieee80211_he_6ghz_oper(he_oper); + + if (!he_6ghz_oper) + return IEEE80211_REG_UNSET_AP; + + switch (u8_get_bits(he_6ghz_oper->control, + IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO)) { + case IEEE80211_6GHZ_CTRL_REG_LPI_AP: + case IEEE80211_6GHZ_CTRL_REG_INDOOR_LPI_AP: + return IEEE80211_REG_LPI_AP; + case IEEE80211_6GHZ_CTRL_REG_SP_AP: + case IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP: + return IEEE80211_REG_SP_AP; + case IEEE80211_6GHZ_CTRL_REG_VLP_AP: + return IEEE80211_REG_VLP_AP; + default: + return IEEE80211_REG_UNSET_AP; + } +} - switch (u8_get_bits(he_6ghz_oper->control, - IEEE80211_HE_6GHZ_OPER_CTRL_REG_INFO)) { - case IEEE80211_6GHZ_CTRL_REG_LPI_AP: - case IEEE80211_6GHZ_CTRL_REG_INDOOR_LPI_AP: - return true; - case IEEE80211_6GHZ_CTRL_REG_SP_AP: - case IEEE80211_6GHZ_CTRL_REG_INDOOR_SP_AP: - return !(flags & IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT); - case IEEE80211_6GHZ_CTRL_REG_VLP_AP: - return !(flags & IEEE80211_CHAN_NO_6GHZ_VLP_CLIENT); - default: - return false; - } +static bool cfg80211_6ghz_power_type_valid(const u8 *elems, size_t elems_len, + const u32 flags) +{ + switch (cfg80211_get_6ghz_power_type(elems, elems_len)) { + case IEEE80211_REG_LPI_AP: + return true; + case IEEE80211_REG_SP_AP: + return !(flags & IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT); + case IEEE80211_REG_VLP_AP: + return !(flags & IEEE80211_CHAN_NO_6GHZ_VLP_CLIENT); + default: + return false; } - return false; } /* Returned bss is reference counted and must be cleaned up appropriately. */ @@ -3349,19 +3391,14 @@ void cfg80211_update_assoc_bss_entry(struct wireless_dev *wdev, if (!WARN_ON(!__cfg80211_unlink_bss(rdev, new))) rdev->bss_generation++; } - - rb_erase(&cbss->rbn, &rdev->bss_tree); - rb_insert_bss(rdev, cbss); - rdev->bss_generation++; + cfg80211_rehash_bss(rdev, cbss); list_for_each_entry_safe(nontrans_bss, tmp, &cbss->pub.nontrans_list, nontrans_list) { bss = bss_from_pub(nontrans_bss); bss->pub.channel = chan; - rb_erase(&bss->rbn, &rdev->bss_tree); - rb_insert_bss(rdev, bss); - rdev->bss_generation++; + cfg80211_rehash_bss(rdev, bss); } done: |