@@ -12815,7 +12815,8 @@ static int nl80211_set_cqm_txe(struct genl_info *info,
12815
12815
}
12816
12816
12817
12817
static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
12818
- struct net_device *dev)
12818
+ struct net_device *dev,
12819
+ struct cfg80211_cqm_config *cqm_config)
12819
12820
{
12820
12821
struct wireless_dev *wdev = dev->ieee80211_ptr;
12821
12822
s32 last, low, high;
@@ -12824,7 +12825,7 @@ static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
12824
12825
int err;
12825
12826
12826
12827
/* RSSI reporting disabled? */
12827
- if (!wdev-> cqm_config)
12828
+ if (!cqm_config)
12828
12829
return rdev_set_cqm_rssi_range_config(rdev, dev, 0, 0);
12829
12830
12830
12831
/*
@@ -12833,7 +12834,7 @@ static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
12833
12834
* connection is established and enough beacons received to calculate
12834
12835
* the average.
12835
12836
*/
12836
- if (!wdev-> cqm_config->last_rssi_event_value &&
12837
+ if (!cqm_config->last_rssi_event_value &&
12837
12838
wdev->links[0].client.current_bss &&
12838
12839
rdev->ops->get_station) {
12839
12840
struct station_info sinfo = {};
@@ -12847,30 +12848,30 @@ static int cfg80211_cqm_rssi_update(struct cfg80211_registered_device *rdev,
12847
12848
12848
12849
cfg80211_sinfo_release_content(&sinfo);
12849
12850
if (sinfo.filled & BIT_ULL(NL80211_STA_INFO_BEACON_SIGNAL_AVG))
12850
- wdev-> cqm_config->last_rssi_event_value =
12851
+ cqm_config->last_rssi_event_value =
12851
12852
(s8) sinfo.rx_beacon_signal_avg;
12852
12853
}
12853
12854
12854
- last = wdev-> cqm_config->last_rssi_event_value;
12855
- hyst = wdev-> cqm_config->rssi_hyst;
12856
- n = wdev-> cqm_config->n_rssi_thresholds;
12855
+ last = cqm_config->last_rssi_event_value;
12856
+ hyst = cqm_config->rssi_hyst;
12857
+ n = cqm_config->n_rssi_thresholds;
12857
12858
12858
12859
for (i = 0; i < n; i++) {
12859
12860
i = array_index_nospec(i, n);
12860
- if (last < wdev-> cqm_config->rssi_thresholds[i])
12861
+ if (last < cqm_config->rssi_thresholds[i])
12861
12862
break;
12862
12863
}
12863
12864
12864
12865
low_index = i - 1;
12865
12866
if (low_index >= 0) {
12866
12867
low_index = array_index_nospec(low_index, n);
12867
- low = wdev-> cqm_config->rssi_thresholds[low_index] - hyst;
12868
+ low = cqm_config->rssi_thresholds[low_index] - hyst;
12868
12869
} else {
12869
12870
low = S32_MIN;
12870
12871
}
12871
12872
if (i < n) {
12872
12873
i = array_index_nospec(i, n);
12873
- high = wdev-> cqm_config->rssi_thresholds[i] + hyst - 1;
12874
+ high = cqm_config->rssi_thresholds[i] + hyst - 1;
12874
12875
} else {
12875
12876
high = S32_MAX;
12876
12877
}
@@ -12883,6 +12884,7 @@ static int nl80211_set_cqm_rssi(struct genl_info *info,
12883
12884
u32 hysteresis)
12884
12885
{
12885
12886
struct cfg80211_registered_device *rdev = info->user_ptr[0];
12887
+ struct cfg80211_cqm_config *cqm_config = NULL, *old;
12886
12888
struct net_device *dev = info->user_ptr[1];
12887
12889
struct wireless_dev *wdev = dev->ieee80211_ptr;
12888
12890
int i, err;
@@ -12900,10 +12902,6 @@ static int nl80211_set_cqm_rssi(struct genl_info *info,
12900
12902
wdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
12901
12903
return -EOPNOTSUPP;
12902
12904
12903
- wdev_lock(wdev);
12904
- cfg80211_cqm_config_free(wdev);
12905
- wdev_unlock(wdev);
12906
-
12907
12905
if (n_thresholds <= 1 && rdev->ops->set_cqm_rssi_config) {
12908
12906
if (n_thresholds == 0 || thresholds[0] == 0) /* Disabling */
12909
12907
return rdev_set_cqm_rssi_config(rdev, dev, 0, 0);
@@ -12920,9 +12918,10 @@ static int nl80211_set_cqm_rssi(struct genl_info *info,
12920
12918
n_thresholds = 0;
12921
12919
12922
12920
wdev_lock(wdev);
12923
- if (n_thresholds) {
12924
- struct cfg80211_cqm_config *cqm_config ;
12921
+ old = rcu_dereference_protected(wdev->cqm_config,
12922
+ lockdep_is_held(&wdev->mtx)) ;
12925
12923
12924
+ if (n_thresholds) {
12926
12925
cqm_config = kzalloc(struct_size(cqm_config, rssi_thresholds,
12927
12926
n_thresholds),
12928
12927
GFP_KERNEL);
@@ -12937,11 +12936,18 @@ static int nl80211_set_cqm_rssi(struct genl_info *info,
12937
12936
flex_array_size(cqm_config, rssi_thresholds,
12938
12937
n_thresholds));
12939
12938
12940
- wdev->cqm_config = cqm_config;
12939
+ rcu_assign_pointer(wdev->cqm_config, cqm_config);
12940
+ } else {
12941
+ RCU_INIT_POINTER(wdev->cqm_config, NULL);
12941
12942
}
12942
12943
12943
- err = cfg80211_cqm_rssi_update(rdev, dev);
12944
-
12944
+ err = cfg80211_cqm_rssi_update(rdev, dev, cqm_config);
12945
+ if (err) {
12946
+ rcu_assign_pointer(wdev->cqm_config, old);
12947
+ kfree_rcu(cqm_config, rcu_head);
12948
+ } else {
12949
+ kfree_rcu(old, rcu_head);
12950
+ }
12945
12951
unlock:
12946
12952
wdev_unlock(wdev);
12947
12953
@@ -19092,28 +19098,50 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
19092
19098
enum nl80211_cqm_rssi_threshold_event rssi_event,
19093
19099
s32 rssi_level, gfp_t gfp)
19094
19100
{
19095
- struct sk_buff *msg;
19096
19101
struct wireless_dev *wdev = dev->ieee80211_ptr;
19097
- struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy) ;
19102
+ struct cfg80211_cqm_config *cqm_config ;
19098
19103
19099
19104
trace_cfg80211_cqm_rssi_notify(dev, rssi_event, rssi_level);
19100
19105
19101
19106
if (WARN_ON(rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW &&
19102
19107
rssi_event != NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH))
19103
19108
return;
19104
19109
19105
- if (wdev->cqm_config) {
19106
- wdev->cqm_config->last_rssi_event_value = rssi_level;
19110
+ rcu_read_lock();
19111
+ cqm_config = rcu_dereference(wdev->cqm_config);
19112
+ if (cqm_config) {
19113
+ cqm_config->last_rssi_event_value = rssi_level;
19114
+ cqm_config->last_rssi_event_type = rssi_event;
19115
+ wiphy_work_queue(wdev->wiphy, &wdev->cqm_rssi_work);
19116
+ }
19117
+ rcu_read_unlock();
19118
+ }
19119
+ EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
19120
+
19121
+ void cfg80211_cqm_rssi_notify_work(struct wiphy *wiphy, struct wiphy_work *work)
19122
+ {
19123
+ struct wireless_dev *wdev = container_of(work, struct wireless_dev,
19124
+ cqm_rssi_work);
19125
+ struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
19126
+ enum nl80211_cqm_rssi_threshold_event rssi_event;
19127
+ struct cfg80211_cqm_config *cqm_config;
19128
+ struct sk_buff *msg;
19129
+ s32 rssi_level;
19107
19130
19108
- cfg80211_cqm_rssi_update(rdev, dev);
19131
+ wdev_lock(wdev);
19132
+ cqm_config = rcu_dereference_protected(wdev->cqm_config,
19133
+ lockdep_is_held(&wdev->mtx));
19134
+ if (!wdev->cqm_config)
19135
+ goto unlock;
19109
19136
19110
- if (rssi_level == 0)
19111
- rssi_level = wdev->cqm_config->last_rssi_event_value;
19112
- }
19137
+ cfg80211_cqm_rssi_update(rdev, wdev->netdev, cqm_config);
19113
19138
19114
- msg = cfg80211_prepare_cqm(dev, NULL, gfp);
19139
+ rssi_level = cqm_config->last_rssi_event_value;
19140
+ rssi_event = cqm_config->last_rssi_event_type;
19141
+
19142
+ msg = cfg80211_prepare_cqm(wdev->netdev, NULL, GFP_KERNEL);
19115
19143
if (!msg)
19116
- return ;
19144
+ goto unlock ;
19117
19145
19118
19146
if (nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
19119
19147
rssi_event))
@@ -19123,14 +19151,15 @@ void cfg80211_cqm_rssi_notify(struct net_device *dev,
19123
19151
rssi_level))
19124
19152
goto nla_put_failure;
19125
19153
19126
- cfg80211_send_cqm(msg, gfp );
19154
+ cfg80211_send_cqm(msg, GFP_KERNEL );
19127
19155
19128
- return ;
19156
+ goto unlock ;
19129
19157
19130
19158
nla_put_failure:
19131
19159
nlmsg_free(msg);
19160
+ unlock:
19161
+ wdev_unlock(wdev);
19132
19162
}
19133
- EXPORT_SYMBOL(cfg80211_cqm_rssi_notify);
19134
19163
19135
19164
void cfg80211_cqm_txe_notify(struct net_device *dev,
19136
19165
const u8 *peer, u32 num_packets,
0 commit comments