cfg80211: Properly track transmitting and non-transmitting BSS
authorSara Sharon <sara.sharon@intel.com>
Mon, 21 Jan 2019 10:22:21 +0000 (12:22 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 8 Feb 2019 12:51:50 +0000 (13:51 +0100)
When holding data of the non-transmitting BSS, we need to keep the
transmitting BSS data on. Otherwise it will be released, and release
the non-transmitting BSS with it.

Signed-off-by: Sara Sharon <sara.sharon@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/wireless/core.h
net/wireless/scan.c

index a50b92ac77a15484da0d11226918f9fc7b2018a9..c20c75df60f5ec129db142edd47aa65fad10f0c4 100644 (file)
@@ -153,6 +153,7 @@ struct cfg80211_internal_bss {
        struct list_head list;
        struct list_head hidden_list;
        struct list_head nontrans_list;
+       struct cfg80211_bss *transmitted_bss;
        struct rb_node rbn;
        u64 ts_boottime;
        unsigned long ts;
@@ -183,12 +184,23 @@ static inline struct cfg80211_internal_bss *bss_from_pub(struct cfg80211_bss *pu
 static inline void cfg80211_hold_bss(struct cfg80211_internal_bss *bss)
 {
        atomic_inc(&bss->hold);
+       if (bss->transmitted_bss) {
+               bss = container_of(bss->transmitted_bss,
+                                  struct cfg80211_internal_bss, pub);
+               atomic_inc(&bss->hold);
+       }
 }
 
 static inline void cfg80211_unhold_bss(struct cfg80211_internal_bss *bss)
 {
        int r = atomic_dec_return(&bss->hold);
        WARN_ON(r < 0);
+       if (bss->transmitted_bss) {
+               bss = container_of(bss->transmitted_bss,
+                                  struct cfg80211_internal_bss, pub);
+               r = atomic_dec_return(&bss->hold);
+               WARN_ON(r < 0);
+       }
 }
 
 
index 54feb7741c26c1961172f2bae83ecfe105014d39..d5950a23e619ca05d0f5f9b774d61a1ca2b2a6d9 100644 (file)
@@ -110,6 +110,12 @@ static inline void bss_ref_get(struct cfg80211_registered_device *rdev,
                                   pub);
                bss->refcount++;
        }
+       if (bss->transmitted_bss) {
+               bss = container_of(bss->transmitted_bss,
+                                  struct cfg80211_internal_bss,
+                                  pub);
+               bss->refcount++;
+       }
 }
 
 static inline void bss_ref_put(struct cfg80211_registered_device *rdev,
@@ -126,6 +132,18 @@ static inline void bss_ref_put(struct cfg80211_registered_device *rdev,
                if (hbss->refcount == 0)
                        bss_free(hbss);
        }
+
+       if (bss->transmitted_bss) {
+               struct cfg80211_internal_bss *tbss;
+
+               tbss = container_of(bss->transmitted_bss,
+                                   struct cfg80211_internal_bss,
+                                   pub);
+               tbss->refcount--;
+               if (tbss->refcount == 0)
+                       bss_free(tbss);
+       }
+
        bss->refcount--;
        if (bss->refcount == 0)
                bss_free(bss);
@@ -1024,6 +1042,7 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev,
 static struct cfg80211_internal_bss *
 cfg80211_bss_update(struct cfg80211_registered_device *rdev,
                    struct cfg80211_internal_bss *tmp,
+                   struct cfg80211_bss *trans_bss,
                    bool signal_valid)
 {
        struct cfg80211_internal_bss *found = NULL;
@@ -1181,6 +1200,17 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
                        goto drop;
                }
 
+               /* This must be before the call to bss_ref_get */
+               if (trans_bss) {
+                       struct cfg80211_internal_bss *pbss =
+                               container_of(trans_bss,
+                                            struct cfg80211_internal_bss,
+                                            pub);
+
+                       new->transmitted_bss = trans_bss;
+                       bss_ref_get(rdev, pbss);
+               }
+
                list_add_tail(&new->list, &rdev->bss_list);
                rdev->bss_entries++;
                rb_insert_bss(rdev, new);
@@ -1336,7 +1366,8 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy,
 
        signal_valid = abs(data->chan->center_freq - channel->center_freq) <=
                wiphy->max_adj_channel_rssi_comp;
-       res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid);
+       res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, trans_bss,
+                                 signal_valid);
        if (!res)
                return NULL;
 
@@ -1639,7 +1670,8 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy,
 
        signal_valid = abs(data->chan->center_freq - channel->center_freq) <=
                wiphy->max_adj_channel_rssi_comp;
-       res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid);
+       res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, trans_bss,
+                                 signal_valid);
        if (!res)
                return NULL;