@@ -143,18 +143,12 @@ static inline void bss_ref_get(struct cfg80211_registered_device *rdev,
143143 lockdep_assert_held (& rdev -> bss_lock );
144144
145145 bss -> refcount ++ ;
146- if (bss -> pub .hidden_beacon_bss ) {
147- bss = container_of (bss -> pub .hidden_beacon_bss ,
148- struct cfg80211_internal_bss ,
149- pub );
150- bss -> refcount ++ ;
151- }
152- if (bss -> pub .transmitted_bss ) {
153- bss = container_of (bss -> pub .transmitted_bss ,
154- struct cfg80211_internal_bss ,
155- pub );
156- bss -> refcount ++ ;
157- }
146+
147+ if (bss -> pub .hidden_beacon_bss )
148+ bss_from_pub (bss -> pub .hidden_beacon_bss )-> refcount ++ ;
149+
150+ if (bss -> pub .transmitted_bss )
151+ bss_from_pub (bss -> pub .transmitted_bss )-> refcount ++ ;
158152}
159153
160154static inline void bss_ref_put (struct cfg80211_registered_device * rdev ,
@@ -304,7 +298,8 @@ static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
304298 tmp_old = cfg80211_find_ie (WLAN_EID_SSID , ie , ielen );
305299 tmp_old = (tmp_old ) ? tmp_old + tmp_old [1 ] + 2 : ie ;
306300
307- while (tmp_old + tmp_old [1 ] + 2 - ie <= ielen ) {
301+ while (tmp_old + 2 - ie <= ielen &&
302+ tmp_old + tmp_old [1 ] + 2 - ie <= ielen ) {
308303 if (tmp_old [0 ] == 0 ) {
309304 tmp_old ++ ;
310305 continue ;
@@ -364,7 +359,8 @@ static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
364359 * copied to new ie, skip ssid, capability, bssid-index ie
365360 */
366361 tmp_new = sub_copy ;
367- while (tmp_new + tmp_new [1 ] + 2 - sub_copy <= subie_len ) {
362+ while (tmp_new + 2 - sub_copy <= subie_len &&
363+ tmp_new + tmp_new [1 ] + 2 - sub_copy <= subie_len ) {
368364 if (!(tmp_new [0 ] == WLAN_EID_NON_TX_BSSID_CAP ||
369365 tmp_new [0 ] == WLAN_EID_SSID )) {
370366 memcpy (pos , tmp_new , tmp_new [1 ] + 2 );
@@ -427,6 +423,15 @@ cfg80211_add_nontrans_list(struct cfg80211_bss *trans_bss,
427423
428424 rcu_read_unlock ();
429425
426+ /*
427+ * This is a bit weird - it's not on the list, but already on another
428+ * one! The only way that could happen is if there's some BSSID/SSID
429+ * shared by multiple APs in their multi-BSSID profiles, potentially
430+ * with hidden SSID mixed in ... ignore it.
431+ */
432+ if (!list_empty (& nontrans_bss -> nontrans_list ))
433+ return - EINVAL ;
434+
430435 /* add to the list */
431436 list_add_tail (& nontrans_bss -> nontrans_list , & trans_bss -> nontrans_list );
432437 return 0 ;
@@ -1602,6 +1607,23 @@ struct cfg80211_non_tx_bss {
16021607 u8 bssid_index ;
16031608};
16041609
1610+ static void cfg80211_update_hidden_bsses (struct cfg80211_internal_bss * known ,
1611+ const struct cfg80211_bss_ies * new_ies ,
1612+ const struct cfg80211_bss_ies * old_ies )
1613+ {
1614+ struct cfg80211_internal_bss * bss ;
1615+
1616+ /* Assign beacon IEs to all sub entries */
1617+ list_for_each_entry (bss , & known -> hidden_list , hidden_list ) {
1618+ const struct cfg80211_bss_ies * ies ;
1619+
1620+ ies = rcu_access_pointer (bss -> pub .beacon_ies );
1621+ WARN_ON (ies != old_ies );
1622+
1623+ rcu_assign_pointer (bss -> pub .beacon_ies , new_ies );
1624+ }
1625+ }
1626+
16051627static bool
16061628cfg80211_update_known_bss (struct cfg80211_registered_device * rdev ,
16071629 struct cfg80211_internal_bss * known ,
@@ -1625,7 +1647,6 @@ cfg80211_update_known_bss(struct cfg80211_registered_device *rdev,
16251647 kfree_rcu ((struct cfg80211_bss_ies * )old , rcu_head );
16261648 } else if (rcu_access_pointer (new -> pub .beacon_ies )) {
16271649 const struct cfg80211_bss_ies * old ;
1628- struct cfg80211_internal_bss * bss ;
16291650
16301651 if (known -> pub .hidden_beacon_bss &&
16311652 !list_empty (& known -> hidden_list )) {
@@ -1653,16 +1674,7 @@ cfg80211_update_known_bss(struct cfg80211_registered_device *rdev,
16531674 if (old == rcu_access_pointer (known -> pub .ies ))
16541675 rcu_assign_pointer (known -> pub .ies , new -> pub .beacon_ies );
16551676
1656- /* Assign beacon IEs to all sub entries */
1657- list_for_each_entry (bss , & known -> hidden_list , hidden_list ) {
1658- const struct cfg80211_bss_ies * ies ;
1659-
1660- ies = rcu_access_pointer (bss -> pub .beacon_ies );
1661- WARN_ON (ies != old );
1662-
1663- rcu_assign_pointer (bss -> pub .beacon_ies ,
1664- new -> pub .beacon_ies );
1665- }
1677+ cfg80211_update_hidden_bsses (known , new -> pub .beacon_ies , old );
16661678
16671679 if (old )
16681680 kfree_rcu ((struct cfg80211_bss_ies * )old , rcu_head );
@@ -1739,6 +1751,8 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
17391751 new -> refcount = 1 ;
17401752 INIT_LIST_HEAD (& new -> hidden_list );
17411753 INIT_LIST_HEAD (& new -> pub .nontrans_list );
1754+ /* we'll set this later if it was non-NULL */
1755+ new -> pub .transmitted_bss = NULL ;
17421756
17431757 if (rcu_access_pointer (tmp -> pub .proberesp_ies )) {
17441758 hidden = rb_find_bss (rdev , tmp , BSS_CMP_HIDE_ZLEN );
@@ -2021,10 +2035,15 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy,
20212035 spin_lock_bh (& rdev -> bss_lock );
20222036 if (cfg80211_add_nontrans_list (non_tx_data -> tx_bss ,
20232037 & res -> pub )) {
2024- if (__cfg80211_unlink_bss (rdev , res ))
2038+ if (__cfg80211_unlink_bss (rdev , res )) {
20252039 rdev -> bss_generation ++ ;
2040+ res = NULL ;
2041+ }
20262042 }
20272043 spin_unlock_bh (& rdev -> bss_lock );
2044+
2045+ if (!res )
2046+ return NULL ;
20282047 }
20292048
20302049 trace_cfg80211_return_bss (& res -> pub );
@@ -2143,6 +2162,8 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
21432162 for_each_element_id (elem , WLAN_EID_MULTIPLE_BSSID , ie , ielen ) {
21442163 if (elem -> datalen < 4 )
21452164 continue ;
2165+ if (elem -> data [0 ] < 1 || (int )elem -> data [0 ] > 8 )
2166+ continue ;
21462167 for_each_element (sub , elem -> data + 1 , elem -> datalen - 1 ) {
21472168 u8 profile_len ;
21482169
@@ -2279,7 +2300,7 @@ cfg80211_update_notlisted_nontrans(struct wiphy *wiphy,
22792300 size_t new_ie_len ;
22802301 struct cfg80211_bss_ies * new_ies ;
22812302 const struct cfg80211_bss_ies * old ;
2282- u8 cpy_len ;
2303+ size_t cpy_len ;
22832304
22842305 lockdep_assert_held (& wiphy_to_rdev (wiphy )-> bss_lock );
22852306
@@ -2346,6 +2367,8 @@ cfg80211_update_notlisted_nontrans(struct wiphy *wiphy,
23462367 } else {
23472368 old = rcu_access_pointer (nontrans_bss -> beacon_ies );
23482369 rcu_assign_pointer (nontrans_bss -> beacon_ies , new_ies );
2370+ cfg80211_update_hidden_bsses (bss_from_pub (nontrans_bss ),
2371+ new_ies , old );
23492372 rcu_assign_pointer (nontrans_bss -> ies , new_ies );
23502373 if (old )
23512374 kfree_rcu ((struct cfg80211_bss_ies * )old , rcu_head );
0 commit comments