diff options
author | Sara Sharon <sara.sharon@intel.com> | 2019-01-21 05:22:21 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2019-02-08 07:51:50 -0500 |
commit | a3584f56de1c808d4383a275b4a74467b19e5645 (patch) | |
tree | 940309fe34cc6be5288298610121a0ca02926844 /net/wireless | |
parent | 1c8745f3ec6f46f5fa99dbcdf92381144ae1b37f (diff) |
cfg80211: Properly track transmitting and non-transmitting BSS
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>
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/core.h | 12 | ||||
-rw-r--r-- | net/wireless/scan.c | 36 |
2 files changed, 46 insertions, 2 deletions
diff --git a/net/wireless/core.h b/net/wireless/core.h index a50b92ac77a1..c20c75df60f5 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -153,6 +153,7 @@ struct cfg80211_internal_bss { | |||
153 | struct list_head list; | 153 | struct list_head list; |
154 | struct list_head hidden_list; | 154 | struct list_head hidden_list; |
155 | struct list_head nontrans_list; | 155 | struct list_head nontrans_list; |
156 | struct cfg80211_bss *transmitted_bss; | ||
156 | struct rb_node rbn; | 157 | struct rb_node rbn; |
157 | u64 ts_boottime; | 158 | u64 ts_boottime; |
158 | unsigned long ts; | 159 | unsigned long ts; |
@@ -183,12 +184,23 @@ static inline struct cfg80211_internal_bss *bss_from_pub(struct cfg80211_bss *pu | |||
183 | static inline void cfg80211_hold_bss(struct cfg80211_internal_bss *bss) | 184 | static inline void cfg80211_hold_bss(struct cfg80211_internal_bss *bss) |
184 | { | 185 | { |
185 | atomic_inc(&bss->hold); | 186 | atomic_inc(&bss->hold); |
187 | if (bss->transmitted_bss) { | ||
188 | bss = container_of(bss->transmitted_bss, | ||
189 | struct cfg80211_internal_bss, pub); | ||
190 | atomic_inc(&bss->hold); | ||
191 | } | ||
186 | } | 192 | } |
187 | 193 | ||
188 | static inline void cfg80211_unhold_bss(struct cfg80211_internal_bss *bss) | 194 | static inline void cfg80211_unhold_bss(struct cfg80211_internal_bss *bss) |
189 | { | 195 | { |
190 | int r = atomic_dec_return(&bss->hold); | 196 | int r = atomic_dec_return(&bss->hold); |
191 | WARN_ON(r < 0); | 197 | WARN_ON(r < 0); |
198 | if (bss->transmitted_bss) { | ||
199 | bss = container_of(bss->transmitted_bss, | ||
200 | struct cfg80211_internal_bss, pub); | ||
201 | r = atomic_dec_return(&bss->hold); | ||
202 | WARN_ON(r < 0); | ||
203 | } | ||
192 | } | 204 | } |
193 | 205 | ||
194 | 206 | ||
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 54feb7741c26..d5950a23e619 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -110,6 +110,12 @@ static inline void bss_ref_get(struct cfg80211_registered_device *rdev, | |||
110 | pub); | 110 | pub); |
111 | bss->refcount++; | 111 | bss->refcount++; |
112 | } | 112 | } |
113 | if (bss->transmitted_bss) { | ||
114 | bss = container_of(bss->transmitted_bss, | ||
115 | struct cfg80211_internal_bss, | ||
116 | pub); | ||
117 | bss->refcount++; | ||
118 | } | ||
113 | } | 119 | } |
114 | 120 | ||
115 | static inline void bss_ref_put(struct cfg80211_registered_device *rdev, | 121 | 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, | |||
126 | if (hbss->refcount == 0) | 132 | if (hbss->refcount == 0) |
127 | bss_free(hbss); | 133 | bss_free(hbss); |
128 | } | 134 | } |
135 | |||
136 | if (bss->transmitted_bss) { | ||
137 | struct cfg80211_internal_bss *tbss; | ||
138 | |||
139 | tbss = container_of(bss->transmitted_bss, | ||
140 | struct cfg80211_internal_bss, | ||
141 | pub); | ||
142 | tbss->refcount--; | ||
143 | if (tbss->refcount == 0) | ||
144 | bss_free(tbss); | ||
145 | } | ||
146 | |||
129 | bss->refcount--; | 147 | bss->refcount--; |
130 | if (bss->refcount == 0) | 148 | if (bss->refcount == 0) |
131 | bss_free(bss); | 149 | bss_free(bss); |
@@ -1024,6 +1042,7 @@ static bool cfg80211_combine_bsses(struct cfg80211_registered_device *rdev, | |||
1024 | static struct cfg80211_internal_bss * | 1042 | static struct cfg80211_internal_bss * |
1025 | cfg80211_bss_update(struct cfg80211_registered_device *rdev, | 1043 | cfg80211_bss_update(struct cfg80211_registered_device *rdev, |
1026 | struct cfg80211_internal_bss *tmp, | 1044 | struct cfg80211_internal_bss *tmp, |
1045 | struct cfg80211_bss *trans_bss, | ||
1027 | bool signal_valid) | 1046 | bool signal_valid) |
1028 | { | 1047 | { |
1029 | struct cfg80211_internal_bss *found = NULL; | 1048 | struct cfg80211_internal_bss *found = NULL; |
@@ -1181,6 +1200,17 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev, | |||
1181 | goto drop; | 1200 | goto drop; |
1182 | } | 1201 | } |
1183 | 1202 | ||
1203 | /* This must be before the call to bss_ref_get */ | ||
1204 | if (trans_bss) { | ||
1205 | struct cfg80211_internal_bss *pbss = | ||
1206 | container_of(trans_bss, | ||
1207 | struct cfg80211_internal_bss, | ||
1208 | pub); | ||
1209 | |||
1210 | new->transmitted_bss = trans_bss; | ||
1211 | bss_ref_get(rdev, pbss); | ||
1212 | } | ||
1213 | |||
1184 | list_add_tail(&new->list, &rdev->bss_list); | 1214 | list_add_tail(&new->list, &rdev->bss_list); |
1185 | rdev->bss_entries++; | 1215 | rdev->bss_entries++; |
1186 | rb_insert_bss(rdev, new); | 1216 | rb_insert_bss(rdev, new); |
@@ -1336,7 +1366,8 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy, | |||
1336 | 1366 | ||
1337 | signal_valid = abs(data->chan->center_freq - channel->center_freq) <= | 1367 | signal_valid = abs(data->chan->center_freq - channel->center_freq) <= |
1338 | wiphy->max_adj_channel_rssi_comp; | 1368 | wiphy->max_adj_channel_rssi_comp; |
1339 | res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid); | 1369 | res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, trans_bss, |
1370 | signal_valid); | ||
1340 | if (!res) | 1371 | if (!res) |
1341 | return NULL; | 1372 | return NULL; |
1342 | 1373 | ||
@@ -1639,7 +1670,8 @@ cfg80211_inform_single_bss_frame_data(struct wiphy *wiphy, | |||
1639 | 1670 | ||
1640 | signal_valid = abs(data->chan->center_freq - channel->center_freq) <= | 1671 | signal_valid = abs(data->chan->center_freq - channel->center_freq) <= |
1641 | wiphy->max_adj_channel_rssi_comp; | 1672 | wiphy->max_adj_channel_rssi_comp; |
1642 | res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, signal_valid); | 1673 | res = cfg80211_bss_update(wiphy_to_rdev(wiphy), &tmp, trans_bss, |
1674 | signal_valid); | ||
1643 | if (!res) | 1675 | if (!res) |
1644 | return NULL; | 1676 | return NULL; |
1645 | 1677 | ||