wifi: mac80211: fix up link station creation/insertion
authorJohannes Berg <johannes.berg@intel.com>
Thu, 14 Jul 2022 21:40:47 +0000 (23:40 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 15 Jul 2022 09:43:23 +0000 (11:43 +0200)
When we create a station with a non-default link, then
we should have a link address, and we definitely need
to insert it into the link hash table on insertion.

Split the API into with and without link creation and
if it has a link, insert the link into the link hash
table on sta_info_insert().

Fixes: ba6ddab94fc6 ("wifi: mac80211: maintain link-sta hash table")
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/cfg.c
net/mac80211/ibss.c
net/mac80211/mesh_plink.c
net/mac80211/mlme.c
net/mac80211/ocb.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h

index 1545648e2031e40e7805999bb58fac361c1f7515..1cacd1e0fc8524b1e80d17dfb0c2b035f33d766b 100644 (file)
@@ -1850,8 +1850,14 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
            !sdata->u.mgd.associated)
                return -EINVAL;
 
-       sta = sta_info_alloc(sdata, mac, params->link_sta_params.link_id,
-                            GFP_KERNEL);
+       if (params->link_sta_params.link_id >= 0)
+               sta = sta_info_alloc_with_link(sdata, mac,
+                                              params->link_sta_params.link_id,
+                                              params->link_sta_params.link_mac,
+                                              GFP_KERNEL);
+       else
+               sta = sta_info_alloc(sdata, mac, GFP_KERNEL);
+
        if (!sta)
                return -ENOMEM;
 
index 60b5230778a3d2c62d119772270bee92f23ed8f2..d56890e3fabb3d43b1cb0c9cc5dae188f45b1ad6 100644 (file)
@@ -625,7 +625,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid,
        scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def);
        rcu_read_unlock();
 
-       sta = sta_info_alloc(sdata, addr, -1, GFP_KERNEL);
+       sta = sta_info_alloc(sdata, addr, GFP_KERNEL);
        if (!sta) {
                rcu_read_lock();
                return NULL;
@@ -1226,7 +1226,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
        scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def);
        rcu_read_unlock();
 
-       sta = sta_info_alloc(sdata, addr, -1, GFP_ATOMIC);
+       sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
        if (!sta)
                return;
 
index 84e3f43fd5c66993a24e6eb17df12eb8ec2e8900..ddfe5102b9a43c37d3a9a68b187d9c122452ae74 100644 (file)
@@ -511,7 +511,7 @@ __mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *hw_addr)
        if (aid < 0)
                return NULL;
 
-       sta = sta_info_alloc(sdata, hw_addr, -1, GFP_KERNEL);
+       sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL);
        if (!sta)
                return NULL;
 
index 3263bb18828416d94a9df5bd62abdb44b58a601b..c7fb12d6fb173999adfbb02c95a88ffe1fbc9ed9 100644 (file)
@@ -5909,7 +5909,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
        }
 
        if (!have_sta) {
-               new_sta = sta_info_alloc(sdata, cbss->bssid, -1, GFP_KERNEL);
+               new_sta = sta_info_alloc(sdata, cbss->bssid, GFP_KERNEL);
                if (!new_sta)
                        return -ENOMEM;
        }
index 8664fee699e9adf5e5561cbc378f9bde36a01199..a57dcbe99a0dcd005c356ba033321afa52e2f4fc 100644 (file)
@@ -69,7 +69,7 @@ void ieee80211_ocb_rx_no_sta(struct ieee80211_sub_if_data *sdata,
        scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def);
        rcu_read_unlock();
 
-       sta = sta_info_alloc(sdata, addr, -1, GFP_ATOMIC);
+       sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
        if (!sta)
                return;
 
index eed88630594f7ddeb7d99edc08c7ad9d2d48e3b2..75122eced104435fcaa776bbb9c8466553a51984 100644 (file)
@@ -96,6 +96,14 @@ static int sta_info_hash_del(struct ieee80211_local *local,
                               sta_rht_params);
 }
 
+static int link_sta_info_hash_add(struct ieee80211_local *local,
+                                 struct link_sta_info *link_sta)
+{
+       return rhltable_insert(&local->link_sta_hash,
+                              &link_sta->link_hash_node,
+                              link_sta_rht_params);
+}
+
 static int link_sta_info_hash_del(struct ieee80211_local *local,
                                  struct link_sta_info *link_sta)
 {
@@ -466,8 +474,10 @@ static void sta_info_add_link(struct sta_info *sta,
        rcu_assign_pointer(sta->sta.link[link_id], link_sta);
 }
 
-struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
-                               const u8 *addr, int link_id, gfp_t gfp)
+static struct sta_info *
+__sta_info_alloc(struct ieee80211_sub_if_data *sdata,
+                const u8 *addr, int link_id, const u8 *link_addr,
+                gfp_t gfp)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_hw *hw = &local->hw;
@@ -513,8 +523,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
 
        memcpy(sta->addr, addr, ETH_ALEN);
        memcpy(sta->sta.addr, addr, ETH_ALEN);
-       memcpy(sta->deflink.addr, addr, ETH_ALEN);
-       memcpy(sta->sta.deflink.addr, addr, ETH_ALEN);
+       memcpy(sta->deflink.addr, link_addr, ETH_ALEN);
+       memcpy(sta->sta.deflink.addr, link_addr, ETH_ALEN);
        sta->sta.max_rx_aggregation_subframes =
                local->hw.max_rx_aggregation_subframes;
 
@@ -641,6 +651,21 @@ free:
        return NULL;
 }
 
+struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
+                               const u8 *addr, gfp_t gfp)
+{
+       return __sta_info_alloc(sdata, addr, -1, addr, gfp);
+}
+
+struct sta_info *sta_info_alloc_with_link(struct ieee80211_sub_if_data *sdata,
+                                         const u8 *mld_addr,
+                                         unsigned int link_id,
+                                         const u8 *link_addr,
+                                         gfp_t gfp)
+{
+       return __sta_info_alloc(sdata, mld_addr, link_id, link_addr, gfp);
+}
+
 static int sta_info_insert_check(struct sta_info *sta)
 {
        struct ieee80211_sub_if_data *sdata = sta->sdata;
@@ -774,6 +799,14 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
        if (err)
                goto out_drop_sta;
 
+       if (sta->sta.valid_links) {
+               err = link_sta_info_hash_add(local, &sta->deflink);
+               if (err) {
+                       sta_info_hash_del(local, sta);
+                       goto out_drop_sta;
+               }
+       }
+
        list_add_tail_rcu(&sta->list, &local->sta_list);
 
        /* update channel context before notifying the driver about state
@@ -2697,14 +2730,6 @@ int ieee80211_sta_allocate_link(struct sta_info *sta, unsigned int link_id)
        return 0;
 }
 
-static int link_sta_info_hash_add(struct ieee80211_local *local,
-                                 struct link_sta_info *link_sta)
-{
-       return rhltable_insert(&local->link_sta_hash,
-                              &link_sta->link_hash_node,
-                              link_sta_rht_params);
-}
-
 void ieee80211_sta_free_link(struct sta_info *sta, unsigned int link_id)
 {
        lockdep_assert_held(&sta->sdata->local->sta_mtx);
index 6bc26a2c46073ea29d5eda4b2260348aa6a6547b..2eb3a9452e075e0f89e91bfd7d679e8988560950 100644 (file)
@@ -840,7 +840,12 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata,
  * until sta_info_insert().
  */
 struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
-                               const u8 *addr, int link_id, gfp_t gfp);
+                               const u8 *addr, gfp_t gfp);
+struct sta_info *sta_info_alloc_with_link(struct ieee80211_sub_if_data *sdata,
+                                         const u8 *mld_addr,
+                                         unsigned int link_id,
+                                         const u8 *link_addr,
+                                         gfp_t gfp);
 
 void sta_info_free(struct ieee80211_local *local, struct sta_info *sta);