Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e2fd5dbc authored by Johannes Berg's avatar Johannes Berg
Browse files

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: default avatarJohannes Berg <johannes.berg@intel.com>
parent d811b3d5
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -972,7 +972,7 @@ struct ieee80211_local {
	unsigned long leave_oper_channel_time;
	enum mac80211_scan_state next_scan_state;
	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;
	struct ieee80211_channel *oper_channel, *csa_channel;

+5 −4
Original line number Diff line number Diff line
@@ -112,10 +112,11 @@ static u32 __ieee80211_recalc_idle(struct ieee80211_local *local)
		}
	}

	if (local->scan_sdata &&
	    !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) {
	sdata = rcu_dereference_protected(local->scan_sdata,
					  lockdep_is_held(&local->mtx));
	if (sdata && !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) {
		scanning = true;
		local->scan_sdata->vif.bss_conf.idle = false;
		sdata->vif.bss_conf.idle = false;
	}

	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);

	if (local->scan_sdata == sdata)
	if (rcu_access_pointer(local->scan_sdata) == sdata)
		ieee80211_scan_cancel(local);

	/*
+24 −9
Original line number Diff line number Diff line
@@ -293,7 +293,13 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
		return;

	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)
			return;
	}
@@ -394,7 +400,10 @@ void ieee80211_run_deferred_scan(struct ieee80211_local *local)
	if (!local->scan_req || local->scanning)
		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;

	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)
{
	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;

	sdata = rcu_dereference_protected(local->scan_sdata,
					  lockdep_is_held(&local->mtx));;

	for (i = 0; i < local->scan_req->n_ssids; i++)
		ieee80211_send_probe_req(
			sdata, NULL,
@@ -439,7 +451,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;
		local->scan_sdata = sdata;
		rcu_assign_pointer(local->scan_sdata, sdata);
		return 0;
	}

@@ -473,7 +485,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
	}

	local->scan_req = req;
	local->scan_sdata = sdata;
	rcu_assign_pointer(local->scan_sdata, sdata);

	if (local->ops->hw_scan) {
		__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);

		local->scan_req = NULL;
		local->scan_sdata = NULL;
		rcu_assign_pointer(local->scan_sdata, NULL);
	}

	return rc;
@@ -720,7 +732,8 @@ void ieee80211_scan_work(struct work_struct *work)

	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. */
	if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) {
@@ -741,7 +754,7 @@ void ieee80211_scan_work(struct work_struct *work)
		int rc;

		local->scan_req = NULL;
		local->scan_sdata = NULL;
		rcu_assign_pointer(local->scan_sdata, NULL);

		rc = __ieee80211_start_scan(sdata, req);
		if (rc) {
@@ -893,7 +906,9 @@ void ieee80211_scan_cancel(struct ieee80211_local *local)

	if (test_bit(SCAN_HW_SCANNING, &local->scanning)) {
		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;
	}