mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-17 17:53:56 +08:00
mac80211: rcu-ify scan and scheduled scan request pointers
In order to use the scan and scheduled scan request pointers during RX to check for randomisation, make them accessible using RCU. Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
ad2b26abc1
commit
6ea0a69ca2
@ -1238,7 +1238,7 @@ struct ieee80211_local {
|
||||
unsigned long scanning;
|
||||
struct cfg80211_ssid scan_ssid;
|
||||
struct cfg80211_scan_request *int_scan_req;
|
||||
struct cfg80211_scan_request *scan_req;
|
||||
struct cfg80211_scan_request __rcu *scan_req;
|
||||
struct ieee80211_scan_request *hw_scan_req;
|
||||
struct cfg80211_chan_def scan_chandef;
|
||||
enum ieee80211_band hw_scan_band;
|
||||
@ -1248,7 +1248,7 @@ struct ieee80211_local {
|
||||
|
||||
struct work_struct sched_scan_stopped_work;
|
||||
struct ieee80211_sub_if_data __rcu *sched_scan_sdata;
|
||||
struct cfg80211_sched_scan_request *sched_scan_req;
|
||||
struct cfg80211_sched_scan_request __rcu *sched_scan_req;
|
||||
|
||||
unsigned long leave_oper_channel_time;
|
||||
enum mac80211_scan_state next_scan_state;
|
||||
|
@ -234,11 +234,14 @@ ieee80211_prepare_scan_chandef(struct cfg80211_chan_def *chandef,
|
||||
/* return false if no more work */
|
||||
static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
|
||||
{
|
||||
struct cfg80211_scan_request *req = local->scan_req;
|
||||
struct cfg80211_scan_request *req;
|
||||
struct cfg80211_chan_def chandef;
|
||||
u8 bands_used = 0;
|
||||
int i, ielen, n_chans;
|
||||
|
||||
req = rcu_dereference_protected(local->scan_req,
|
||||
lockdep_is_held(&local->mtx));
|
||||
|
||||
if (test_bit(SCAN_HW_CANCELLED, &local->scanning))
|
||||
return false;
|
||||
|
||||
@ -290,6 +293,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
bool hw_scan = local->ops->hw_scan;
|
||||
bool was_scanning = local->scanning;
|
||||
struct cfg80211_scan_request *scan_req;
|
||||
|
||||
lockdep_assert_held(&local->mtx);
|
||||
|
||||
@ -322,9 +326,12 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
|
||||
kfree(local->hw_scan_req);
|
||||
local->hw_scan_req = NULL;
|
||||
|
||||
if (local->scan_req != local->int_scan_req)
|
||||
cfg80211_scan_done(local->scan_req, aborted);
|
||||
local->scan_req = NULL;
|
||||
scan_req = rcu_dereference_protected(local->scan_req,
|
||||
lockdep_is_held(&local->mtx));
|
||||
|
||||
if (scan_req != local->int_scan_req)
|
||||
cfg80211_scan_done(scan_req, aborted);
|
||||
RCU_INIT_POINTER(local->scan_req, NULL);
|
||||
RCU_INIT_POINTER(local->scan_sdata, NULL);
|
||||
|
||||
local->scanning = 0;
|
||||
@ -440,23 +447,26 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
|
||||
{
|
||||
int i;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct cfg80211_scan_request *scan_req;
|
||||
enum ieee80211_band band = local->hw.conf.chandef.chan->band;
|
||||
u32 tx_flags;
|
||||
|
||||
scan_req = rcu_dereference_protected(local->scan_req,
|
||||
lockdep_is_held(&local->mtx));
|
||||
|
||||
tx_flags = IEEE80211_TX_INTFL_OFFCHAN_TX_OK;
|
||||
if (local->scan_req->no_cck)
|
||||
if (scan_req->no_cck)
|
||||
tx_flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
|
||||
|
||||
sdata = rcu_dereference_protected(local->scan_sdata,
|
||||
lockdep_is_held(&local->mtx));
|
||||
|
||||
for (i = 0; i < local->scan_req->n_ssids; i++)
|
||||
for (i = 0; i < scan_req->n_ssids; i++)
|
||||
ieee80211_send_probe_req(
|
||||
sdata, NULL,
|
||||
local->scan_req->ssids[i].ssid,
|
||||
local->scan_req->ssids[i].ssid_len,
|
||||
local->scan_req->ie, local->scan_req->ie_len,
|
||||
local->scan_req->rates[band], false,
|
||||
scan_req->ssids[i].ssid, scan_req->ssids[i].ssid_len,
|
||||
scan_req->ie, scan_req->ie_len,
|
||||
scan_req->rates[band], false,
|
||||
tx_flags, local->hw.conf.chandef.chan, true);
|
||||
|
||||
/*
|
||||
@ -480,7 +490,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
if (!ieee80211_can_scan(local, sdata)) {
|
||||
/* wait for the work to finish/time out */
|
||||
local->scan_req = req;
|
||||
rcu_assign_pointer(local->scan_req, req);
|
||||
rcu_assign_pointer(local->scan_sdata, sdata);
|
||||
return 0;
|
||||
}
|
||||
@ -530,7 +540,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
|
||||
*/
|
||||
}
|
||||
|
||||
local->scan_req = req;
|
||||
rcu_assign_pointer(local->scan_req, req);
|
||||
rcu_assign_pointer(local->scan_sdata, sdata);
|
||||
|
||||
if (local->ops->hw_scan) {
|
||||
@ -558,7 +568,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
if ((req->channels[0]->flags &
|
||||
IEEE80211_CHAN_NO_IR) ||
|
||||
!local->scan_req->n_ssids) {
|
||||
!req->n_ssids) {
|
||||
next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
|
||||
} else {
|
||||
ieee80211_scan_state_send_probe(local, &next_delay);
|
||||
@ -617,6 +627,7 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct ieee80211_channel *next_chan;
|
||||
enum mac80211_scan_state next_scan_state;
|
||||
struct cfg80211_scan_request *scan_req;
|
||||
|
||||
/*
|
||||
* check if at least one STA interface is associated,
|
||||
@ -641,7 +652,10 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
|
||||
}
|
||||
mutex_unlock(&local->iflist_mtx);
|
||||
|
||||
next_chan = local->scan_req->channels[local->scan_channel_idx];
|
||||
scan_req = rcu_dereference_protected(local->scan_req,
|
||||
lockdep_is_held(&local->mtx));
|
||||
|
||||
next_chan = scan_req->channels[local->scan_channel_idx];
|
||||
|
||||
/*
|
||||
* we're currently scanning a different channel, let's
|
||||
@ -656,7 +670,7 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
|
||||
local->leave_oper_channel_time + HZ / 8);
|
||||
|
||||
if (associated && !tx_empty) {
|
||||
if (local->scan_req->flags & NL80211_SCAN_FLAG_LOW_PRIORITY)
|
||||
if (scan_req->flags & NL80211_SCAN_FLAG_LOW_PRIORITY)
|
||||
next_scan_state = SCAN_ABORT;
|
||||
else
|
||||
next_scan_state = SCAN_SUSPEND;
|
||||
@ -677,14 +691,18 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
|
||||
int skip;
|
||||
struct ieee80211_channel *chan;
|
||||
enum nl80211_bss_scan_width oper_scan_width;
|
||||
struct cfg80211_scan_request *scan_req;
|
||||
|
||||
scan_req = rcu_dereference_protected(local->scan_req,
|
||||
lockdep_is_held(&local->mtx));
|
||||
|
||||
skip = 0;
|
||||
chan = local->scan_req->channels[local->scan_channel_idx];
|
||||
chan = scan_req->channels[local->scan_channel_idx];
|
||||
|
||||
local->scan_chandef.chan = chan;
|
||||
local->scan_chandef.center_freq1 = chan->center_freq;
|
||||
local->scan_chandef.center_freq2 = 0;
|
||||
switch (local->scan_req->scan_width) {
|
||||
switch (scan_req->scan_width) {
|
||||
case NL80211_BSS_CHAN_WIDTH_5:
|
||||
local->scan_chandef.width = NL80211_CHAN_WIDTH_5;
|
||||
break;
|
||||
@ -698,7 +716,7 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
|
||||
oper_scan_width = cfg80211_chandef_to_scan_width(
|
||||
&local->_oper_chandef);
|
||||
if (chan == local->_oper_chandef.chan &&
|
||||
oper_scan_width == local->scan_req->scan_width)
|
||||
oper_scan_width == scan_req->scan_width)
|
||||
local->scan_chandef = local->_oper_chandef;
|
||||
else
|
||||
local->scan_chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
|
||||
@ -727,8 +745,7 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
|
||||
*
|
||||
* In any case, it is not necessary for a passive scan.
|
||||
*/
|
||||
if (chan->flags & IEEE80211_CHAN_NO_IR ||
|
||||
!local->scan_req->n_ssids) {
|
||||
if (chan->flags & IEEE80211_CHAN_NO_IR || !scan_req->n_ssids) {
|
||||
*next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
|
||||
local->next_scan_state = SCAN_DECISION;
|
||||
return;
|
||||
@ -777,6 +794,7 @@ void ieee80211_scan_work(struct work_struct *work)
|
||||
struct ieee80211_local *local =
|
||||
container_of(work, struct ieee80211_local, scan_work.work);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
struct cfg80211_scan_request *scan_req;
|
||||
unsigned long next_delay = 0;
|
||||
bool aborted;
|
||||
|
||||
@ -784,6 +802,8 @@ void ieee80211_scan_work(struct work_struct *work)
|
||||
|
||||
sdata = rcu_dereference_protected(local->scan_sdata,
|
||||
lockdep_is_held(&local->mtx));
|
||||
scan_req = rcu_dereference_protected(local->scan_req,
|
||||
lockdep_is_held(&local->mtx));
|
||||
|
||||
/* When scanning on-channel, the first-callback means completed. */
|
||||
if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) {
|
||||
@ -796,20 +816,19 @@ void ieee80211_scan_work(struct work_struct *work)
|
||||
goto out_complete;
|
||||
}
|
||||
|
||||
if (!sdata || !local->scan_req)
|
||||
if (!sdata || !scan_req)
|
||||
goto out;
|
||||
|
||||
if (!local->scanning) {
|
||||
struct cfg80211_scan_request *req = local->scan_req;
|
||||
int rc;
|
||||
|
||||
local->scan_req = NULL;
|
||||
RCU_INIT_POINTER(local->scan_req, NULL);
|
||||
RCU_INIT_POINTER(local->scan_sdata, NULL);
|
||||
|
||||
rc = __ieee80211_start_scan(sdata, req);
|
||||
rc = __ieee80211_start_scan(sdata, scan_req);
|
||||
if (rc) {
|
||||
/* need to complete scan in cfg80211 */
|
||||
local->scan_req = req;
|
||||
rcu_assign_pointer(local->scan_req, scan_req);
|
||||
aborted = true;
|
||||
goto out_complete;
|
||||
} else
|
||||
@ -829,7 +848,7 @@ void ieee80211_scan_work(struct work_struct *work)
|
||||
switch (local->next_scan_state) {
|
||||
case SCAN_DECISION:
|
||||
/* if no more bands/channels left, complete scan */
|
||||
if (local->scan_channel_idx >= local->scan_req->n_channels) {
|
||||
if (local->scan_channel_idx >= scan_req->n_channels) {
|
||||
aborted = false;
|
||||
goto out_complete;
|
||||
}
|
||||
@ -1043,7 +1062,7 @@ int __ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
|
||||
ret = drv_sched_scan_start(local, sdata, req, &sched_scan_ies);
|
||||
if (ret == 0) {
|
||||
rcu_assign_pointer(local->sched_scan_sdata, sdata);
|
||||
local->sched_scan_req = req;
|
||||
rcu_assign_pointer(local->sched_scan_req, req);
|
||||
}
|
||||
|
||||
kfree(ie);
|
||||
@ -1052,7 +1071,7 @@ out:
|
||||
if (ret) {
|
||||
/* Clean in case of failure after HW restart or upon resume. */
|
||||
RCU_INIT_POINTER(local->sched_scan_sdata, NULL);
|
||||
local->sched_scan_req = NULL;
|
||||
RCU_INIT_POINTER(local->sched_scan_req, NULL);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -1090,7 +1109,7 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata)
|
||||
}
|
||||
|
||||
/* We don't want to restart sched scan anymore. */
|
||||
local->sched_scan_req = NULL;
|
||||
RCU_INIT_POINTER(local->sched_scan_req, NULL);
|
||||
|
||||
if (rcu_access_pointer(local->sched_scan_sdata)) {
|
||||
ret = drv_sched_scan_stop(local, sdata);
|
||||
@ -1125,7 +1144,7 @@ void ieee80211_sched_scan_end(struct ieee80211_local *local)
|
||||
RCU_INIT_POINTER(local->sched_scan_sdata, NULL);
|
||||
|
||||
/* If sched scan was aborted by the driver. */
|
||||
local->sched_scan_req = NULL;
|
||||
RCU_INIT_POINTER(local->sched_scan_req, NULL);
|
||||
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
|
@ -1721,6 +1721,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
||||
int res, i;
|
||||
bool reconfig_due_to_wowlan = false;
|
||||
struct ieee80211_sub_if_data *sched_scan_sdata;
|
||||
struct cfg80211_sched_scan_request *sched_scan_req;
|
||||
bool sched_scan_stopped = false;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
@ -2011,13 +2012,15 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
||||
mutex_lock(&local->mtx);
|
||||
sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata,
|
||||
lockdep_is_held(&local->mtx));
|
||||
if (sched_scan_sdata && local->sched_scan_req)
|
||||
sched_scan_req = rcu_dereference_protected(local->sched_scan_req,
|
||||
lockdep_is_held(&local->mtx));
|
||||
if (sched_scan_sdata && sched_scan_req)
|
||||
/*
|
||||
* Sched scan stopped, but we don't want to report it. Instead,
|
||||
* we're trying to reschedule.
|
||||
*/
|
||||
if (__ieee80211_request_sched_scan_start(sched_scan_sdata,
|
||||
local->sched_scan_req))
|
||||
sched_scan_req))
|
||||
sched_scan_stopped = true;
|
||||
mutex_unlock(&local->mtx);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user