mac80211: make scan_sdata pointer usable with RCU
Making the scan_sdata pointer usable with RCU makes it possible to dereference it in the RX path to see if a received frame actually matches the interface that is scanning. This is just preparations, making the pointer __rcu. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
d811b3d556
commit
e2fd5dbc1c
|
@ -972,7 +972,7 @@ struct ieee80211_local {
|
||||||
unsigned long leave_oper_channel_time;
|
unsigned long leave_oper_channel_time;
|
||||||
enum mac80211_scan_state next_scan_state;
|
enum mac80211_scan_state next_scan_state;
|
||||||
struct delayed_work scan_work;
|
struct delayed_work scan_work;
|
||||||
struct ieee80211_sub_if_data *scan_sdata;
|
struct ieee80211_sub_if_data __rcu *scan_sdata;
|
||||||
enum nl80211_channel_type _oper_channel_type;
|
enum nl80211_channel_type _oper_channel_type;
|
||||||
struct ieee80211_channel *oper_channel, *csa_channel;
|
struct ieee80211_channel *oper_channel, *csa_channel;
|
||||||
|
|
||||||
|
|
|
@ -112,10 +112,11 @@ static u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (local->scan_sdata &&
|
sdata = rcu_dereference_protected(local->scan_sdata,
|
||||||
!(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) {
|
lockdep_is_held(&local->mtx));
|
||||||
|
if (sdata && !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) {
|
||||||
scanning = true;
|
scanning = true;
|
||||||
local->scan_sdata->vif.bss_conf.idle = false;
|
sdata->vif.bss_conf.idle = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
list_for_each_entry(sdata, &local->interfaces, list) {
|
||||||
|
@ -628,7 +629,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||||
|
|
||||||
clear_bit(SDATA_STATE_RUNNING, &sdata->state);
|
clear_bit(SDATA_STATE_RUNNING, &sdata->state);
|
||||||
|
|
||||||
if (local->scan_sdata == sdata)
|
if (rcu_access_pointer(local->scan_sdata) == sdata)
|
||||||
ieee80211_scan_cancel(local);
|
ieee80211_scan_cancel(local);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -293,7 +293,13 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) {
|
if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) {
|
||||||
int rc = drv_hw_scan(local, local->scan_sdata, local->hw_scan_req);
|
int rc;
|
||||||
|
|
||||||
|
rc = drv_hw_scan(local,
|
||||||
|
rcu_dereference_protected(local->scan_sdata,
|
||||||
|
lockdep_is_held(&local->mtx)),
|
||||||
|
local->hw_scan_req);
|
||||||
|
|
||||||
if (rc == 0)
|
if (rc == 0)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -394,7 +400,10 @@ void ieee80211_run_deferred_scan(struct ieee80211_local *local)
|
||||||
if (!local->scan_req || local->scanning)
|
if (!local->scan_req || local->scanning)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!ieee80211_can_scan(local, local->scan_sdata))
|
if (!ieee80211_can_scan(local,
|
||||||
|
rcu_dereference_protected(
|
||||||
|
local->scan_sdata,
|
||||||
|
lockdep_is_held(&local->mtx))))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ieee80211_queue_delayed_work(&local->hw, &local->scan_work,
|
ieee80211_queue_delayed_work(&local->hw, &local->scan_work,
|
||||||
|
@ -405,9 +414,12 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
|
||||||
unsigned long *next_delay)
|
unsigned long *next_delay)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct ieee80211_sub_if_data *sdata = local->scan_sdata;
|
struct ieee80211_sub_if_data *sdata;
|
||||||
enum ieee80211_band band = local->hw.conf.channel->band;
|
enum ieee80211_band band = local->hw.conf.channel->band;
|
||||||
|
|
||||||
|
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 < local->scan_req->n_ssids; i++)
|
||||||
ieee80211_send_probe_req(
|
ieee80211_send_probe_req(
|
||||||
sdata, NULL,
|
sdata, NULL,
|
||||||
|
@ -439,7 +451,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
|
||||||
if (!ieee80211_can_scan(local, sdata)) {
|
if (!ieee80211_can_scan(local, sdata)) {
|
||||||
/* wait for the work to finish/time out */
|
/* wait for the work to finish/time out */
|
||||||
local->scan_req = req;
|
local->scan_req = req;
|
||||||
local->scan_sdata = sdata;
|
rcu_assign_pointer(local->scan_sdata, sdata);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -473,7 +485,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
|
||||||
}
|
}
|
||||||
|
|
||||||
local->scan_req = req;
|
local->scan_req = req;
|
||||||
local->scan_sdata = sdata;
|
rcu_assign_pointer(local->scan_sdata, sdata);
|
||||||
|
|
||||||
if (local->ops->hw_scan) {
|
if (local->ops->hw_scan) {
|
||||||
__set_bit(SCAN_HW_SCANNING, &local->scanning);
|
__set_bit(SCAN_HW_SCANNING, &local->scanning);
|
||||||
|
@ -533,7 +545,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
|
||||||
ieee80211_recalc_idle(local);
|
ieee80211_recalc_idle(local);
|
||||||
|
|
||||||
local->scan_req = NULL;
|
local->scan_req = NULL;
|
||||||
local->scan_sdata = NULL;
|
rcu_assign_pointer(local->scan_sdata, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -720,7 +732,8 @@ void ieee80211_scan_work(struct work_struct *work)
|
||||||
|
|
||||||
mutex_lock(&local->mtx);
|
mutex_lock(&local->mtx);
|
||||||
|
|
||||||
sdata = local->scan_sdata;
|
sdata = rcu_dereference_protected(local->scan_sdata,
|
||||||
|
lockdep_is_held(&local->mtx));
|
||||||
|
|
||||||
/* When scanning on-channel, the first-callback means completed. */
|
/* When scanning on-channel, the first-callback means completed. */
|
||||||
if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) {
|
if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) {
|
||||||
|
@ -741,7 +754,7 @@ void ieee80211_scan_work(struct work_struct *work)
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
local->scan_req = NULL;
|
local->scan_req = NULL;
|
||||||
local->scan_sdata = NULL;
|
rcu_assign_pointer(local->scan_sdata, NULL);
|
||||||
|
|
||||||
rc = __ieee80211_start_scan(sdata, req);
|
rc = __ieee80211_start_scan(sdata, req);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
|
@ -893,7 +906,9 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)
|
||||||
|
|
||||||
if (test_bit(SCAN_HW_SCANNING, &local->scanning)) {
|
if (test_bit(SCAN_HW_SCANNING, &local->scanning)) {
|
||||||
if (local->ops->cancel_hw_scan)
|
if (local->ops->cancel_hw_scan)
|
||||||
drv_cancel_hw_scan(local, local->scan_sdata);
|
drv_cancel_hw_scan(local,
|
||||||
|
rcu_dereference_protected(local->scan_sdata,
|
||||||
|
lockdep_is_held(&local->mtx)));
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue