xref: /linux/net/mac80211/scan.c (revision 9607e6b66a0d25ca63b70d54a4283fa13d8f7c9d)
10a51b27eSJohannes Berg /*
25484e237SJohannes Berg  * Scanning implementation
35484e237SJohannes Berg  *
40a51b27eSJohannes Berg  * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
50a51b27eSJohannes Berg  * Copyright 2004, Instant802 Networks, Inc.
60a51b27eSJohannes Berg  * Copyright 2005, Devicescape Software, Inc.
70a51b27eSJohannes Berg  * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
80a51b27eSJohannes Berg  * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
90a51b27eSJohannes Berg  *
100a51b27eSJohannes Berg  * This program is free software; you can redistribute it and/or modify
110a51b27eSJohannes Berg  * it under the terms of the GNU General Public License version 2 as
120a51b27eSJohannes Berg  * published by the Free Software Foundation.
130a51b27eSJohannes Berg  */
140a51b27eSJohannes Berg 
150a51b27eSJohannes Berg #include <linux/wireless.h>
160a51b27eSJohannes Berg #include <linux/if_arp.h>
17078e1e60SJohannes Berg #include <linux/rtnetlink.h>
180a51b27eSJohannes Berg #include <net/mac80211.h>
190a51b27eSJohannes Berg 
200a51b27eSJohannes Berg #include "ieee80211_i.h"
2124487981SJohannes Berg #include "driver-ops.h"
225484e237SJohannes Berg #include "mesh.h"
230a51b27eSJohannes Berg 
240a51b27eSJohannes Berg #define IEEE80211_PROBE_DELAY (HZ / 33)
250a51b27eSJohannes Berg #define IEEE80211_CHANNEL_TIME (HZ / 33)
2696f7e739SHelmut Schaa #define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 8)
270a51b27eSJohannes Berg 
28c2b13452SJohannes Berg struct ieee80211_bss *
295484e237SJohannes Berg ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
305484e237SJohannes Berg 		     u8 *ssid, u8 ssid_len)
315484e237SJohannes Berg {
3200d3f14cSJohannes Berg 	return (void *)cfg80211_get_bss(local->hw.wiphy,
3300d3f14cSJohannes Berg 					ieee80211_get_channel(local->hw.wiphy,
3400d3f14cSJohannes Berg 							      freq),
3500d3f14cSJohannes Berg 					bssid, ssid, ssid_len,
3600d3f14cSJohannes Berg 					0, 0);
375484e237SJohannes Berg }
385484e237SJohannes Berg 
3900d3f14cSJohannes Berg static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss)
405484e237SJohannes Berg {
4100d3f14cSJohannes Berg 	struct ieee80211_bss *bss = (void *)cbss;
425484e237SJohannes Berg 
435484e237SJohannes Berg 	kfree(bss_mesh_id(bss));
445484e237SJohannes Berg 	kfree(bss_mesh_cfg(bss));
455484e237SJohannes Berg }
465484e237SJohannes Berg 
475484e237SJohannes Berg void ieee80211_rx_bss_put(struct ieee80211_local *local,
48c2b13452SJohannes Berg 			  struct ieee80211_bss *bss)
495484e237SJohannes Berg {
5000d3f14cSJohannes Berg 	cfg80211_put_bss((struct cfg80211_bss *)bss);
515484e237SJohannes Berg }
525484e237SJohannes Berg 
53c2b13452SJohannes Berg struct ieee80211_bss *
545484e237SJohannes Berg ieee80211_bss_info_update(struct ieee80211_local *local,
555484e237SJohannes Berg 			  struct ieee80211_rx_status *rx_status,
565484e237SJohannes Berg 			  struct ieee80211_mgmt *mgmt,
575484e237SJohannes Berg 			  size_t len,
585484e237SJohannes Berg 			  struct ieee802_11_elems *elems,
592a519311SJohannes Berg 			  struct ieee80211_channel *channel,
602a519311SJohannes Berg 			  bool beacon)
615484e237SJohannes Berg {
62c2b13452SJohannes Berg 	struct ieee80211_bss *bss;
6300d3f14cSJohannes Berg 	int clen;
642a519311SJohannes Berg 	s32 signal = 0;
652a519311SJohannes Berg 
6677965c97SJohannes Berg 	if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
672a519311SJohannes Berg 		signal = rx_status->signal * 100;
6877965c97SJohannes Berg 	else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
692a519311SJohannes Berg 		signal = (rx_status->signal * 100) / local->hw.max_signal;
702a519311SJohannes Berg 
7100d3f14cSJohannes Berg 	bss = (void *)cfg80211_inform_bss_frame(local->hw.wiphy, channel,
7277965c97SJohannes Berg 						mgmt, len, signal, GFP_ATOMIC);
735484e237SJohannes Berg 
745484e237SJohannes Berg 	if (!bss)
755484e237SJohannes Berg 		return NULL;
7600d3f14cSJohannes Berg 
7700d3f14cSJohannes Berg 	bss->cbss.free_priv = ieee80211_rx_bss_free;
785484e237SJohannes Berg 
795484e237SJohannes Berg 	/* save the ERP value so that it is available at association time */
805484e237SJohannes Berg 	if (elems->erp_info && elems->erp_info_len >= 1) {
815484e237SJohannes Berg 		bss->erp_value = elems->erp_info[0];
825484e237SJohannes Berg 		bss->has_erp_value = 1;
835484e237SJohannes Berg 	}
845484e237SJohannes Berg 
855484e237SJohannes Berg 	if (elems->tim) {
865484e237SJohannes Berg 		struct ieee80211_tim_ie *tim_ie =
875484e237SJohannes Berg 			(struct ieee80211_tim_ie *)elems->tim;
885484e237SJohannes Berg 		bss->dtim_period = tim_ie->dtim_period;
895484e237SJohannes Berg 	}
905484e237SJohannes Berg 
916a211bf1SJohannes Berg 	/* set default value for buggy AP/no TIM element */
926a211bf1SJohannes Berg 	if (bss->dtim_period == 0)
935484e237SJohannes Berg 		bss->dtim_period = 1;
945484e237SJohannes Berg 
955484e237SJohannes Berg 	bss->supp_rates_len = 0;
965484e237SJohannes Berg 	if (elems->supp_rates) {
975484e237SJohannes Berg 		clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
985484e237SJohannes Berg 		if (clen > elems->supp_rates_len)
995484e237SJohannes Berg 			clen = elems->supp_rates_len;
1005484e237SJohannes Berg 		memcpy(&bss->supp_rates[bss->supp_rates_len], elems->supp_rates,
1015484e237SJohannes Berg 		       clen);
1025484e237SJohannes Berg 		bss->supp_rates_len += clen;
1035484e237SJohannes Berg 	}
1045484e237SJohannes Berg 	if (elems->ext_supp_rates) {
1055484e237SJohannes Berg 		clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
1065484e237SJohannes Berg 		if (clen > elems->ext_supp_rates_len)
1075484e237SJohannes Berg 			clen = elems->ext_supp_rates_len;
1085484e237SJohannes Berg 		memcpy(&bss->supp_rates[bss->supp_rates_len],
1095484e237SJohannes Berg 		       elems->ext_supp_rates, clen);
1105484e237SJohannes Berg 		bss->supp_rates_len += clen;
1115484e237SJohannes Berg 	}
1125484e237SJohannes Berg 
1135484e237SJohannes Berg 	bss->wmm_used = elems->wmm_param || elems->wmm_info;
1145484e237SJohannes Berg 
1155484e237SJohannes Berg 	if (!beacon)
1165484e237SJohannes Berg 		bss->last_probe_resp = jiffies;
1175484e237SJohannes Berg 
1185484e237SJohannes Berg 	return bss;
1195484e237SJohannes Berg }
1200a51b27eSJohannes Berg 
12198c8fccfSJohannes Berg ieee80211_rx_result
122f1d58c25SJohannes Berg ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
12398c8fccfSJohannes Berg {
124f1d58c25SJohannes Berg 	struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
12598c8fccfSJohannes Berg 	struct ieee80211_mgmt *mgmt;
126c2b13452SJohannes Berg 	struct ieee80211_bss *bss;
12798c8fccfSJohannes Berg 	u8 *elements;
12898c8fccfSJohannes Berg 	struct ieee80211_channel *channel;
12998c8fccfSJohannes Berg 	size_t baselen;
13098c8fccfSJohannes Berg 	int freq;
13198c8fccfSJohannes Berg 	__le16 fc;
13298c8fccfSJohannes Berg 	bool presp, beacon = false;
13398c8fccfSJohannes Berg 	struct ieee802_11_elems elems;
13498c8fccfSJohannes Berg 
13598c8fccfSJohannes Berg 	if (skb->len < 2)
13698c8fccfSJohannes Berg 		return RX_DROP_UNUSABLE;
13798c8fccfSJohannes Berg 
13898c8fccfSJohannes Berg 	mgmt = (struct ieee80211_mgmt *) skb->data;
13998c8fccfSJohannes Berg 	fc = mgmt->frame_control;
14098c8fccfSJohannes Berg 
14198c8fccfSJohannes Berg 	if (ieee80211_is_ctl(fc))
14298c8fccfSJohannes Berg 		return RX_CONTINUE;
14398c8fccfSJohannes Berg 
14498c8fccfSJohannes Berg 	if (skb->len < 24)
14598c8fccfSJohannes Berg 		return RX_DROP_MONITOR;
14698c8fccfSJohannes Berg 
14798c8fccfSJohannes Berg 	presp = ieee80211_is_probe_resp(fc);
14898c8fccfSJohannes Berg 	if (presp) {
14998c8fccfSJohannes Berg 		/* ignore ProbeResp to foreign address */
15047846c9bSJohannes Berg 		if (memcmp(mgmt->da, sdata->vif.addr, ETH_ALEN))
15198c8fccfSJohannes Berg 			return RX_DROP_MONITOR;
15298c8fccfSJohannes Berg 
15398c8fccfSJohannes Berg 		presp = true;
15498c8fccfSJohannes Berg 		elements = mgmt->u.probe_resp.variable;
15598c8fccfSJohannes Berg 		baselen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
15698c8fccfSJohannes Berg 	} else {
15798c8fccfSJohannes Berg 		beacon = ieee80211_is_beacon(fc);
15898c8fccfSJohannes Berg 		baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable);
15998c8fccfSJohannes Berg 		elements = mgmt->u.beacon.variable;
16098c8fccfSJohannes Berg 	}
16198c8fccfSJohannes Berg 
16298c8fccfSJohannes Berg 	if (!presp && !beacon)
16398c8fccfSJohannes Berg 		return RX_CONTINUE;
16498c8fccfSJohannes Berg 
16598c8fccfSJohannes Berg 	if (baselen > skb->len)
16698c8fccfSJohannes Berg 		return RX_DROP_MONITOR;
16798c8fccfSJohannes Berg 
16898c8fccfSJohannes Berg 	ieee802_11_parse_elems(elements, skb->len - baselen, &elems);
16998c8fccfSJohannes Berg 
17098c8fccfSJohannes Berg 	if (elems.ds_params && elems.ds_params_len == 1)
17198c8fccfSJohannes Berg 		freq = ieee80211_channel_to_frequency(elems.ds_params[0]);
17298c8fccfSJohannes Berg 	else
17398c8fccfSJohannes Berg 		freq = rx_status->freq;
17498c8fccfSJohannes Berg 
17598c8fccfSJohannes Berg 	channel = ieee80211_get_channel(sdata->local->hw.wiphy, freq);
17698c8fccfSJohannes Berg 
17798c8fccfSJohannes Berg 	if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
17898c8fccfSJohannes Berg 		return RX_DROP_MONITOR;
17998c8fccfSJohannes Berg 
18098c8fccfSJohannes Berg 	bss = ieee80211_bss_info_update(sdata->local, rx_status,
18198c8fccfSJohannes Berg 					mgmt, skb->len, &elems,
1822a519311SJohannes Berg 					channel, beacon);
183d048e503SJouni Malinen 	if (bss)
18498c8fccfSJohannes Berg 		ieee80211_rx_bss_put(sdata->local, bss);
18598c8fccfSJohannes Berg 
18698c8fccfSJohannes Berg 	dev_kfree_skb(skb);
18798c8fccfSJohannes Berg 	return RX_QUEUED;
18898c8fccfSJohannes Berg }
18998c8fccfSJohannes Berg 
1904d36ec58SJohannes Berg /* return false if no more work */
1914d36ec58SJohannes Berg static bool ieee80211_prep_hw_scan(struct ieee80211_local *local)
1924d36ec58SJohannes Berg {
1934d36ec58SJohannes Berg 	struct cfg80211_scan_request *req = local->scan_req;
1944d36ec58SJohannes Berg 	enum ieee80211_band band;
1954d36ec58SJohannes Berg 	int i, ielen, n_chans;
1964d36ec58SJohannes Berg 
1974d36ec58SJohannes Berg 	do {
1984d36ec58SJohannes Berg 		if (local->hw_scan_band == IEEE80211_NUM_BANDS)
1994d36ec58SJohannes Berg 			return false;
2004d36ec58SJohannes Berg 
2014d36ec58SJohannes Berg 		band = local->hw_scan_band;
2024d36ec58SJohannes Berg 		n_chans = 0;
2034d36ec58SJohannes Berg 		for (i = 0; i < req->n_channels; i++) {
2044d36ec58SJohannes Berg 			if (req->channels[i]->band == band) {
2054d36ec58SJohannes Berg 				local->hw_scan_req->channels[n_chans] =
2064d36ec58SJohannes Berg 							req->channels[i];
2074d36ec58SJohannes Berg 				n_chans++;
2084d36ec58SJohannes Berg 			}
2094d36ec58SJohannes Berg 		}
2104d36ec58SJohannes Berg 
2114d36ec58SJohannes Berg 		local->hw_scan_band++;
2124d36ec58SJohannes Berg 	} while (!n_chans);
2134d36ec58SJohannes Berg 
2144d36ec58SJohannes Berg 	local->hw_scan_req->n_channels = n_chans;
2154d36ec58SJohannes Berg 
2164d36ec58SJohannes Berg 	ielen = ieee80211_build_preq_ies(local, (u8 *)local->hw_scan_req->ie,
2174d36ec58SJohannes Berg 					 req->ie, req->ie_len, band);
2184d36ec58SJohannes Berg 	local->hw_scan_req->ie_len = ielen;
2194d36ec58SJohannes Berg 
2204d36ec58SJohannes Berg 	return true;
2214d36ec58SJohannes Berg }
2224d36ec58SJohannes Berg 
2239050bdd8SKalle Valo /*
2249050bdd8SKalle Valo  * inform AP that we will go to sleep so that it will buffer the frames
2259050bdd8SKalle Valo  * while we scan
2269050bdd8SKalle Valo  */
2279050bdd8SKalle Valo static void ieee80211_scan_ps_enable(struct ieee80211_sub_if_data *sdata)
2289050bdd8SKalle Valo {
2299050bdd8SKalle Valo 	struct ieee80211_local *local = sdata->local;
2307c3f4bbeSVivek Natarajan 
2317c3f4bbeSVivek Natarajan 	local->scan_ps_enabled = false;
2329050bdd8SKalle Valo 
2339050bdd8SKalle Valo 	/* FIXME: what to do when local->pspolling is true? */
2349050bdd8SKalle Valo 
2359050bdd8SKalle Valo 	del_timer_sync(&local->dynamic_ps_timer);
2369050bdd8SKalle Valo 	cancel_work_sync(&local->dynamic_ps_enable_work);
2379050bdd8SKalle Valo 
2389050bdd8SKalle Valo 	if (local->hw.conf.flags & IEEE80211_CONF_PS) {
2397c3f4bbeSVivek Natarajan 		local->scan_ps_enabled = true;
2409050bdd8SKalle Valo 		local->hw.conf.flags &= ~IEEE80211_CONF_PS;
2419050bdd8SKalle Valo 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
2429050bdd8SKalle Valo 	}
2439050bdd8SKalle Valo 
2447c3f4bbeSVivek Natarajan 	if (!(local->scan_ps_enabled) ||
2457c3f4bbeSVivek Natarajan 	    !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))
2469050bdd8SKalle Valo 		/*
2479050bdd8SKalle Valo 		 * If power save was enabled, no need to send a nullfunc
2489050bdd8SKalle Valo 		 * frame because AP knows that we are sleeping. But if the
2499050bdd8SKalle Valo 		 * hardware is creating the nullfunc frame for power save
2509050bdd8SKalle Valo 		 * status (ie. IEEE80211_HW_PS_NULLFUNC_STACK is not
2519050bdd8SKalle Valo 		 * enabled) and power save was enabled, the firmware just
2529050bdd8SKalle Valo 		 * sent a null frame with power save disabled. So we need
2539050bdd8SKalle Valo 		 * to send a new nullfunc frame to inform the AP that we
2549050bdd8SKalle Valo 		 * are again sleeping.
2559050bdd8SKalle Valo 		 */
2569050bdd8SKalle Valo 		ieee80211_send_nullfunc(local, sdata, 1);
2579050bdd8SKalle Valo }
2589050bdd8SKalle Valo 
2599050bdd8SKalle Valo /* inform AP that we are awake again, unless power save is enabled */
2609050bdd8SKalle Valo static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata)
2619050bdd8SKalle Valo {
2629050bdd8SKalle Valo 	struct ieee80211_local *local = sdata->local;
2639050bdd8SKalle Valo 
264965bedadSJohannes Berg 	if (!local->ps_sdata)
2659050bdd8SKalle Valo 		ieee80211_send_nullfunc(local, sdata, 0);
2667c3f4bbeSVivek Natarajan 	else if (local->scan_ps_enabled) {
2679050bdd8SKalle Valo 		/*
2689050bdd8SKalle Valo 		 * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware
2699050bdd8SKalle Valo 		 * will send a nullfunc frame with the powersave bit set
2709050bdd8SKalle Valo 		 * even though the AP already knows that we are sleeping.
2719050bdd8SKalle Valo 		 * This could be avoided by sending a null frame with power
2729050bdd8SKalle Valo 		 * save bit disabled before enabling the power save, but
2739050bdd8SKalle Valo 		 * this doesn't gain anything.
2749050bdd8SKalle Valo 		 *
2759050bdd8SKalle Valo 		 * When IEEE80211_HW_PS_NULLFUNC_STACK is enabled, no need
2769050bdd8SKalle Valo 		 * to send a nullfunc frame because AP already knows that
2779050bdd8SKalle Valo 		 * we are sleeping, let's just enable power save mode in
2789050bdd8SKalle Valo 		 * hardware.
2799050bdd8SKalle Valo 		 */
2809050bdd8SKalle Valo 		local->hw.conf.flags |= IEEE80211_CONF_PS;
2819050bdd8SKalle Valo 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
2827c3f4bbeSVivek Natarajan 	} else if (local->hw.conf.dynamic_ps_timeout > 0) {
2837c3f4bbeSVivek Natarajan 		/*
2847c3f4bbeSVivek Natarajan 		 * If IEEE80211_CONF_PS was not set and the dynamic_ps_timer
2857c3f4bbeSVivek Natarajan 		 * had been running before leaving the operating channel,
2867c3f4bbeSVivek Natarajan 		 * restart the timer now and send a nullfunc frame to inform
2877c3f4bbeSVivek Natarajan 		 * the AP that we are awake.
2887c3f4bbeSVivek Natarajan 		 */
2897c3f4bbeSVivek Natarajan 		ieee80211_send_nullfunc(local, sdata, 0);
2907c3f4bbeSVivek Natarajan 		mod_timer(&local->dynamic_ps_timer, jiffies +
2917c3f4bbeSVivek Natarajan 			  msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
2929050bdd8SKalle Valo 	}
2939050bdd8SKalle Valo }
2949050bdd8SKalle Valo 
295f3b85252SJohannes Berg void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
296f3b85252SJohannes Berg {
297f3b85252SJohannes Berg 	struct ieee80211_local *local = hw_to_local(hw);
298f3b85252SJohannes Berg 	struct ieee80211_sub_if_data *sdata;
299f3b85252SJohannes Berg 	bool was_hw_scan;
300f3b85252SJohannes Berg 
301f3b85252SJohannes Berg 	mutex_lock(&local->scan_mtx);
302f3b85252SJohannes Berg 
3036d3560d4SJohannes Berg 	/*
3046d3560d4SJohannes Berg 	 * It's ok to abort a not-yet-running scan (that
3056d3560d4SJohannes Berg 	 * we have one at all will be verified by checking
3066d3560d4SJohannes Berg 	 * local->scan_req next), but not to complete it
3076d3560d4SJohannes Berg 	 * successfully.
3086d3560d4SJohannes Berg 	 */
3096d3560d4SJohannes Berg 	if (WARN_ON(!local->scanning && !aborted))
3106d3560d4SJohannes Berg 		aborted = true;
311f3b85252SJohannes Berg 
312f3b85252SJohannes Berg 	if (WARN_ON(!local->scan_req)) {
313f3b85252SJohannes Berg 		mutex_unlock(&local->scan_mtx);
314f3b85252SJohannes Berg 		return;
315f3b85252SJohannes Berg 	}
316f3b85252SJohannes Berg 
3174d36ec58SJohannes Berg 	was_hw_scan = test_bit(SCAN_HW_SCANNING, &local->scanning);
3184d36ec58SJohannes Berg 	if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) {
3194d36ec58SJohannes Berg 		ieee80211_queue_delayed_work(&local->hw,
3204d36ec58SJohannes Berg 					     &local->scan_work, 0);
3214d36ec58SJohannes Berg 		mutex_unlock(&local->scan_mtx);
3224d36ec58SJohannes Berg 		return;
3234d36ec58SJohannes Berg 	}
3244d36ec58SJohannes Berg 
3254d36ec58SJohannes Berg 	kfree(local->hw_scan_req);
3264d36ec58SJohannes Berg 	local->hw_scan_req = NULL;
327f3b85252SJohannes Berg 
3285ba63533SJohannes Berg 	if (local->scan_req != local->int_scan_req)
3292a519311SJohannes Berg 		cfg80211_scan_done(local->scan_req, aborted);
3302a519311SJohannes Berg 	local->scan_req = NULL;
33115db0b7fSJohannes Berg 	local->scan_sdata = NULL;
3322a519311SJohannes Berg 
333fbe9c429SHelmut Schaa 	local->scanning = 0;
33458905ca5SJohannes Berg 	local->scan_channel = NULL;
335f3b85252SJohannes Berg 
336f3b85252SJohannes Berg 	/* we only have to protect scan_req and hw/sw scan */
337f3b85252SJohannes Berg 	mutex_unlock(&local->scan_mtx);
338f3b85252SJohannes Berg 
339e8975581SJohannes Berg 	ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
3405cff20e6SJohannes Berg 	if (was_hw_scan)
3415cff20e6SJohannes Berg 		goto done;
3420a51b27eSJohannes Berg 
3433ac64beeSJohannes Berg 	ieee80211_configure_filter(local);
3440a51b27eSJohannes Berg 
34524487981SJohannes Berg 	drv_sw_scan_complete(local);
34680e775bfSMichael Buesch 
347078e1e60SJohannes Berg 	mutex_lock(&local->iflist_mtx);
348078e1e60SJohannes Berg 	list_for_each_entry(sdata, &local->interfaces, list) {
349*9607e6b6SJohannes Berg 		if (!ieee80211_sdata_running(sdata))
350fb9ddbf0SJohannes Berg 			continue;
351fb9ddbf0SJohannes Berg 
3520a51b27eSJohannes Berg 		/* Tell AP we're back */
35305c914feSJohannes Berg 		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
35477fdaa12SJohannes Berg 			if (sdata->u.mgd.associated) {
3559050bdd8SKalle Valo 				ieee80211_scan_ps_disable(sdata);
35653623f1aSJohn W. Linville 				netif_wake_queue(sdata->dev);
3570a51b27eSJohannes Berg 			}
3580a51b27eSJohannes Berg 		} else
35953623f1aSJohn W. Linville 			netif_wake_queue(sdata->dev);
360078e1e60SJohannes Berg 
36114b80724SJohannes Berg 		/* re-enable beaconing */
36214b80724SJohannes Berg 		if (sdata->vif.type == NL80211_IFTYPE_AP ||
36314b80724SJohannes Berg 		    sdata->vif.type == NL80211_IFTYPE_ADHOC ||
36414b80724SJohannes Berg 		    sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
3652d0ddec5SJohannes Berg 			ieee80211_bss_info_change_notify(
3662d0ddec5SJohannes Berg 				sdata, BSS_CHANGED_BEACON_ENABLED);
3670a51b27eSJohannes Berg 	}
368078e1e60SJohannes Berg 	mutex_unlock(&local->iflist_mtx);
3690a51b27eSJohannes Berg 
3700a51b27eSJohannes Berg  done:
3715cff20e6SJohannes Berg 	ieee80211_recalc_idle(local);
3720a51b27eSJohannes Berg 	ieee80211_mlme_notify_scan_completed(local);
37346900298SJohannes Berg 	ieee80211_ibss_notify_scan_completed(local);
374472dbc45SJohannes Berg 	ieee80211_mesh_notify_scan_completed(local);
3750a51b27eSJohannes Berg }
3760a51b27eSJohannes Berg EXPORT_SYMBOL(ieee80211_scan_completed);
3770a51b27eSJohannes Berg 
378f3b85252SJohannes Berg static int ieee80211_start_sw_scan(struct ieee80211_local *local)
379f3b85252SJohannes Berg {
380f3b85252SJohannes Berg 	struct ieee80211_sub_if_data *sdata;
381f3b85252SJohannes Berg 
382f3b85252SJohannes Berg 	/*
383f3b85252SJohannes Berg 	 * Hardware/driver doesn't support hw_scan, so use software
384f3b85252SJohannes Berg 	 * scanning instead. First send a nullfunc frame with power save
385f3b85252SJohannes Berg 	 * bit on so that AP will buffer the frames for us while we are not
386f3b85252SJohannes Berg 	 * listening, then send probe requests to each channel and wait for
387f3b85252SJohannes Berg 	 * the responses. After all channels are scanned, tune back to the
388f3b85252SJohannes Berg 	 * original channel and send a nullfunc frame with power save bit
389f3b85252SJohannes Berg 	 * off to trigger the AP to send us all the buffered frames.
390f3b85252SJohannes Berg 	 *
391f3b85252SJohannes Berg 	 * Note that while local->sw_scanning is true everything else but
392f3b85252SJohannes Berg 	 * nullfunc frames and probe requests will be dropped in
393f3b85252SJohannes Berg 	 * ieee80211_tx_h_check_assoc().
394f3b85252SJohannes Berg 	 */
39524487981SJohannes Berg 	drv_sw_scan_start(local);
396f3b85252SJohannes Berg 
397f3b85252SJohannes Berg 	mutex_lock(&local->iflist_mtx);
398f3b85252SJohannes Berg 	list_for_each_entry(sdata, &local->interfaces, list) {
399*9607e6b6SJohannes Berg 		if (!ieee80211_sdata_running(sdata))
400f3b85252SJohannes Berg 			continue;
401f3b85252SJohannes Berg 
402f3b85252SJohannes Berg 		/* disable beaconing */
403f3b85252SJohannes Berg 		if (sdata->vif.type == NL80211_IFTYPE_AP ||
404f3b85252SJohannes Berg 		    sdata->vif.type == NL80211_IFTYPE_ADHOC ||
405f3b85252SJohannes Berg 		    sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
4062d0ddec5SJohannes Berg 			ieee80211_bss_info_change_notify(
4072d0ddec5SJohannes Berg 				sdata, BSS_CHANGED_BEACON_ENABLED);
408f3b85252SJohannes Berg 
409142b9f50SHelmut Schaa 		/*
410142b9f50SHelmut Schaa 		 * only handle non-STA interfaces here, STA interfaces
411142b9f50SHelmut Schaa 		 * are handled in the scan state machine
412142b9f50SHelmut Schaa 		 */
413142b9f50SHelmut Schaa 		if (sdata->vif.type != NL80211_IFTYPE_STATION)
41453623f1aSJohn W. Linville 			netif_stop_queue(sdata->dev);
415f3b85252SJohannes Berg 	}
416f3b85252SJohannes Berg 	mutex_unlock(&local->iflist_mtx);
417f3b85252SJohannes Berg 
418977923b0SHelmut Schaa 	local->next_scan_state = SCAN_DECISION;
419f3b85252SJohannes Berg 	local->scan_channel_idx = 0;
420f3b85252SJohannes Berg 
4213ac64beeSJohannes Berg 	ieee80211_configure_filter(local);
422f3b85252SJohannes Berg 
423f3b85252SJohannes Berg 	/* TODO: start scan as soon as all nullfunc frames are ACKed */
42442935ecaSLuis R. Rodriguez 	ieee80211_queue_delayed_work(&local->hw,
42542935ecaSLuis R. Rodriguez 				     &local->scan_work,
426f3b85252SJohannes Berg 				     IEEE80211_CHANNEL_TIME);
427f3b85252SJohannes Berg 
428f3b85252SJohannes Berg 	return 0;
429f3b85252SJohannes Berg }
430f3b85252SJohannes Berg 
431f3b85252SJohannes Berg 
432f3b85252SJohannes Berg static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
433f3b85252SJohannes Berg 				  struct cfg80211_scan_request *req)
434f3b85252SJohannes Berg {
435f3b85252SJohannes Berg 	struct ieee80211_local *local = sdata->local;
436f3b85252SJohannes Berg 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
437f3b85252SJohannes Berg 	int rc;
438f3b85252SJohannes Berg 
439f3b85252SJohannes Berg 	if (local->scan_req)
440f3b85252SJohannes Berg 		return -EBUSY;
441f3b85252SJohannes Berg 
442f3b85252SJohannes Berg 	if (local->ops->hw_scan) {
443f3b85252SJohannes Berg 		u8 *ies;
444f3b85252SJohannes Berg 
4454d36ec58SJohannes Berg 		local->hw_scan_req = kmalloc(
4464d36ec58SJohannes Berg 				sizeof(*local->hw_scan_req) +
4474d36ec58SJohannes Berg 				req->n_channels * sizeof(req->channels[0]) +
4484d36ec58SJohannes Berg 				2 + IEEE80211_MAX_SSID_LEN + local->scan_ies_len +
4494d36ec58SJohannes Berg 				req->ie_len, GFP_KERNEL);
4504d36ec58SJohannes Berg 		if (!local->hw_scan_req)
451f3b85252SJohannes Berg 			return -ENOMEM;
452f3b85252SJohannes Berg 
4534d36ec58SJohannes Berg 		local->hw_scan_req->ssids = req->ssids;
4544d36ec58SJohannes Berg 		local->hw_scan_req->n_ssids = req->n_ssids;
4554d36ec58SJohannes Berg 		ies = (u8 *)local->hw_scan_req +
4564d36ec58SJohannes Berg 			sizeof(*local->hw_scan_req) +
4574d36ec58SJohannes Berg 			req->n_channels * sizeof(req->channels[0]);
4584d36ec58SJohannes Berg 		local->hw_scan_req->ie = ies;
4594d36ec58SJohannes Berg 
4604d36ec58SJohannes Berg 		local->hw_scan_band = 0;
461f3b85252SJohannes Berg 	}
462f3b85252SJohannes Berg 
463f3b85252SJohannes Berg 	local->scan_req = req;
464f3b85252SJohannes Berg 	local->scan_sdata = sdata;
465f3b85252SJohannes Berg 
4665ba63533SJohannes Berg 	if (req != local->int_scan_req &&
467f3b85252SJohannes Berg 	    sdata->vif.type == NL80211_IFTYPE_STATION &&
46877fdaa12SJohannes Berg 	    !list_empty(&ifmgd->work_list)) {
46977fdaa12SJohannes Berg 		/* actually wait for the work it's doing to finish/time out */
470f3b85252SJohannes Berg 		set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request);
471f3b85252SJohannes Berg 		return 0;
472f3b85252SJohannes Berg 	}
473f3b85252SJohannes Berg 
474f3b85252SJohannes Berg 	if (local->ops->hw_scan)
475fbe9c429SHelmut Schaa 		__set_bit(SCAN_HW_SCANNING, &local->scanning);
476f3b85252SJohannes Berg 	else
477fbe9c429SHelmut Schaa 		__set_bit(SCAN_SW_SCANNING, &local->scanning);
478f3b85252SJohannes Berg 	/*
479f3b85252SJohannes Berg 	 * Kicking off the scan need not be protected,
480f3b85252SJohannes Berg 	 * only the scan variable stuff, since now
481f3b85252SJohannes Berg 	 * local->scan_req is assigned and other callers
482f3b85252SJohannes Berg 	 * will abort their scan attempts.
483f3b85252SJohannes Berg 	 *
484f3b85252SJohannes Berg 	 * This avoids getting a scan_mtx -> iflist_mtx
485f3b85252SJohannes Berg 	 * dependency, so that the scan completed calls
486f3b85252SJohannes Berg 	 * have more locking freedom.
487f3b85252SJohannes Berg 	 */
4885cff20e6SJohannes Berg 
4895cff20e6SJohannes Berg 	ieee80211_recalc_idle(local);
490f3b85252SJohannes Berg 	mutex_unlock(&local->scan_mtx);
491f3b85252SJohannes Berg 
4924d36ec58SJohannes Berg 	if (local->ops->hw_scan) {
4934d36ec58SJohannes Berg 		WARN_ON(!ieee80211_prep_hw_scan(local));
4944d36ec58SJohannes Berg 		rc = drv_hw_scan(local, local->hw_scan_req);
4954d36ec58SJohannes Berg 	} else
496f3b85252SJohannes Berg 		rc = ieee80211_start_sw_scan(local);
497f3b85252SJohannes Berg 
498f3b85252SJohannes Berg 	mutex_lock(&local->scan_mtx);
499f3b85252SJohannes Berg 
500f3b85252SJohannes Berg 	if (rc) {
5014d36ec58SJohannes Berg 		kfree(local->hw_scan_req);
5024d36ec58SJohannes Berg 		local->hw_scan_req = NULL;
503fbe9c429SHelmut Schaa 		local->scanning = 0;
504f3b85252SJohannes Berg 
5055cff20e6SJohannes Berg 		ieee80211_recalc_idle(local);
5065cff20e6SJohannes Berg 
507f3b85252SJohannes Berg 		local->scan_req = NULL;
508f3b85252SJohannes Berg 		local->scan_sdata = NULL;
509f3b85252SJohannes Berg 	}
510f3b85252SJohannes Berg 
511f3b85252SJohannes Berg 	return rc;
512f3b85252SJohannes Berg }
513f3b85252SJohannes Berg 
5142fb3f028SHelmut Schaa static int ieee80211_scan_state_decision(struct ieee80211_local *local,
5152fb3f028SHelmut Schaa 					 unsigned long *next_delay)
5162fb3f028SHelmut Schaa {
517142b9f50SHelmut Schaa 	bool associated = false;
518142b9f50SHelmut Schaa 	struct ieee80211_sub_if_data *sdata;
519142b9f50SHelmut Schaa 
520142b9f50SHelmut Schaa 	/* if no more bands/channels left, complete scan and advance to the idle state */
5212fb3f028SHelmut Schaa 	if (local->scan_channel_idx >= local->scan_req->n_channels) {
5222fb3f028SHelmut Schaa 		ieee80211_scan_completed(&local->hw, false);
5232fb3f028SHelmut Schaa 		return 1;
5242fb3f028SHelmut Schaa 	}
5252fb3f028SHelmut Schaa 
526142b9f50SHelmut Schaa 	/* check if at least one STA interface is associated */
527142b9f50SHelmut Schaa 	mutex_lock(&local->iflist_mtx);
528142b9f50SHelmut Schaa 	list_for_each_entry(sdata, &local->interfaces, list) {
529*9607e6b6SJohannes Berg 		if (!ieee80211_sdata_running(sdata))
530142b9f50SHelmut Schaa 			continue;
531142b9f50SHelmut Schaa 
532142b9f50SHelmut Schaa 		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
533142b9f50SHelmut Schaa 			if (sdata->u.mgd.associated) {
534142b9f50SHelmut Schaa 				associated = true;
535142b9f50SHelmut Schaa 				break;
536142b9f50SHelmut Schaa 			}
537142b9f50SHelmut Schaa 		}
538142b9f50SHelmut Schaa 	}
539142b9f50SHelmut Schaa 	mutex_unlock(&local->iflist_mtx);
540142b9f50SHelmut Schaa 
541142b9f50SHelmut Schaa 	if (local->scan_channel) {
542142b9f50SHelmut Schaa 		/*
543142b9f50SHelmut Schaa 		 * we're currently scanning a different channel, let's
544142b9f50SHelmut Schaa 		 * switch back to the operating channel now if at least
545142b9f50SHelmut Schaa 		 * one interface is associated. Otherwise just scan the
546142b9f50SHelmut Schaa 		 * next channel
547142b9f50SHelmut Schaa 		 */
548142b9f50SHelmut Schaa 		if (associated)
549977923b0SHelmut Schaa 			local->next_scan_state = SCAN_ENTER_OPER_CHANNEL;
550142b9f50SHelmut Schaa 		else
551977923b0SHelmut Schaa 			local->next_scan_state = SCAN_SET_CHANNEL;
552142b9f50SHelmut Schaa 	} else {
553142b9f50SHelmut Schaa 		/*
554142b9f50SHelmut Schaa 		 * we're on the operating channel currently, let's
555142b9f50SHelmut Schaa 		 * leave that channel now to scan another one
556142b9f50SHelmut Schaa 		 */
557977923b0SHelmut Schaa 		local->next_scan_state = SCAN_LEAVE_OPER_CHANNEL;
558142b9f50SHelmut Schaa 	}
559142b9f50SHelmut Schaa 
560142b9f50SHelmut Schaa 	*next_delay = 0;
5612fb3f028SHelmut Schaa 	return 0;
5622fb3f028SHelmut Schaa }
5632fb3f028SHelmut Schaa 
564142b9f50SHelmut Schaa static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local,
565142b9f50SHelmut Schaa 						    unsigned long *next_delay)
566142b9f50SHelmut Schaa {
567142b9f50SHelmut Schaa 	struct ieee80211_sub_if_data *sdata;
568142b9f50SHelmut Schaa 
569142b9f50SHelmut Schaa 	/*
570142b9f50SHelmut Schaa 	 * notify the AP about us leaving the channel and stop all STA interfaces
571142b9f50SHelmut Schaa 	 */
572142b9f50SHelmut Schaa 	mutex_lock(&local->iflist_mtx);
573142b9f50SHelmut Schaa 	list_for_each_entry(sdata, &local->interfaces, list) {
574*9607e6b6SJohannes Berg 		if (!ieee80211_sdata_running(sdata))
575142b9f50SHelmut Schaa 			continue;
576142b9f50SHelmut Schaa 
577142b9f50SHelmut Schaa 		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
57853623f1aSJohn W. Linville 			netif_stop_queue(sdata->dev);
579142b9f50SHelmut Schaa 			if (sdata->u.mgd.associated)
580142b9f50SHelmut Schaa 				ieee80211_scan_ps_enable(sdata);
581142b9f50SHelmut Schaa 		}
582142b9f50SHelmut Schaa 	}
583142b9f50SHelmut Schaa 	mutex_unlock(&local->iflist_mtx);
584142b9f50SHelmut Schaa 
585142b9f50SHelmut Schaa 	__set_bit(SCAN_OFF_CHANNEL, &local->scanning);
586142b9f50SHelmut Schaa 
587142b9f50SHelmut Schaa 	/* advance to the next channel to be scanned */
588142b9f50SHelmut Schaa 	*next_delay = HZ / 10;
589977923b0SHelmut Schaa 	local->next_scan_state = SCAN_SET_CHANNEL;
590142b9f50SHelmut Schaa }
591142b9f50SHelmut Schaa 
592142b9f50SHelmut Schaa static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *local,
593142b9f50SHelmut Schaa 						    unsigned long *next_delay)
594142b9f50SHelmut Schaa {
595142b9f50SHelmut Schaa 	struct ieee80211_sub_if_data *sdata = local->scan_sdata;
596142b9f50SHelmut Schaa 
597142b9f50SHelmut Schaa 	/* switch back to the operating channel */
598142b9f50SHelmut Schaa 	local->scan_channel = NULL;
599142b9f50SHelmut Schaa 	ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
600142b9f50SHelmut Schaa 
601142b9f50SHelmut Schaa 	/*
602142b9f50SHelmut Schaa 	 * notify the AP about us being back and restart all STA interfaces
603142b9f50SHelmut Schaa 	 */
604142b9f50SHelmut Schaa 	mutex_lock(&local->iflist_mtx);
605142b9f50SHelmut Schaa 	list_for_each_entry(sdata, &local->interfaces, list) {
606*9607e6b6SJohannes Berg 		if (!ieee80211_sdata_running(sdata))
607142b9f50SHelmut Schaa 			continue;
608142b9f50SHelmut Schaa 
609142b9f50SHelmut Schaa 		/* Tell AP we're back */
610142b9f50SHelmut Schaa 		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
611142b9f50SHelmut Schaa 			if (sdata->u.mgd.associated)
612142b9f50SHelmut Schaa 				ieee80211_scan_ps_disable(sdata);
61353623f1aSJohn W. Linville 			netif_wake_queue(sdata->dev);
614142b9f50SHelmut Schaa 		}
615142b9f50SHelmut Schaa 	}
616142b9f50SHelmut Schaa 	mutex_unlock(&local->iflist_mtx);
617142b9f50SHelmut Schaa 
618142b9f50SHelmut Schaa 	__clear_bit(SCAN_OFF_CHANNEL, &local->scanning);
619142b9f50SHelmut Schaa 
620142b9f50SHelmut Schaa 	*next_delay = HZ / 5;
621977923b0SHelmut Schaa 	local->next_scan_state = SCAN_DECISION;
622142b9f50SHelmut Schaa }
623142b9f50SHelmut Schaa 
6242fb3f028SHelmut Schaa static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
6257d3be3ccSHelmut Schaa 					     unsigned long *next_delay)
6267d3be3ccSHelmut Schaa {
6277d3be3ccSHelmut Schaa 	int skip;
6287d3be3ccSHelmut Schaa 	struct ieee80211_channel *chan;
6297d3be3ccSHelmut Schaa 
6307d3be3ccSHelmut Schaa 	skip = 0;
6317d3be3ccSHelmut Schaa 	chan = local->scan_req->channels[local->scan_channel_idx];
6327d3be3ccSHelmut Schaa 
6337d3be3ccSHelmut Schaa 	local->scan_channel = chan;
634584991dcSJohannes Berg 	if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL))
6357d3be3ccSHelmut Schaa 		skip = 1;
6367d3be3ccSHelmut Schaa 
6377d3be3ccSHelmut Schaa 	/* advance state machine to next channel/band */
6387d3be3ccSHelmut Schaa 	local->scan_channel_idx++;
6397d3be3ccSHelmut Schaa 
6400ee9c13cSHelmut Schaa 	if (skip) {
6410ee9c13cSHelmut Schaa 		/* if we skip this channel return to the decision state */
6420ee9c13cSHelmut Schaa 		local->next_scan_state = SCAN_DECISION;
6432fb3f028SHelmut Schaa 		return;
6440ee9c13cSHelmut Schaa 	}
6457d3be3ccSHelmut Schaa 
6467d3be3ccSHelmut Schaa 	/*
6477d3be3ccSHelmut Schaa 	 * Probe delay is used to update the NAV, cf. 11.1.3.2.2
6487d3be3ccSHelmut Schaa 	 * (which unfortunately doesn't say _why_ step a) is done,
6497d3be3ccSHelmut Schaa 	 * but it waits for the probe delay or until a frame is
6507d3be3ccSHelmut Schaa 	 * received - and the received frame would update the NAV).
6517d3be3ccSHelmut Schaa 	 * For now, we do not support waiting until a frame is
6527d3be3ccSHelmut Schaa 	 * received.
6537d3be3ccSHelmut Schaa 	 *
6547d3be3ccSHelmut Schaa 	 * In any case, it is not necessary for a passive scan.
6557d3be3ccSHelmut Schaa 	 */
6567d3be3ccSHelmut Schaa 	if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
6577d3be3ccSHelmut Schaa 	    !local->scan_req->n_ssids) {
6587d3be3ccSHelmut Schaa 		*next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
659977923b0SHelmut Schaa 		local->next_scan_state = SCAN_DECISION;
6602fb3f028SHelmut Schaa 		return;
6617d3be3ccSHelmut Schaa 	}
6627d3be3ccSHelmut Schaa 
6632fb3f028SHelmut Schaa 	/* active scan, send probes */
6647d3be3ccSHelmut Schaa 	*next_delay = IEEE80211_PROBE_DELAY;
665977923b0SHelmut Schaa 	local->next_scan_state = SCAN_SEND_PROBE;
6667d3be3ccSHelmut Schaa }
6677d3be3ccSHelmut Schaa 
6687d3be3ccSHelmut Schaa static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
6697d3be3ccSHelmut Schaa 					    unsigned long *next_delay)
6707d3be3ccSHelmut Schaa {
6717d3be3ccSHelmut Schaa 	int i;
6727d3be3ccSHelmut Schaa 	struct ieee80211_sub_if_data *sdata = local->scan_sdata;
6737d3be3ccSHelmut Schaa 
6747d3be3ccSHelmut Schaa 	for (i = 0; i < local->scan_req->n_ssids; i++)
6757d3be3ccSHelmut Schaa 		ieee80211_send_probe_req(
6767d3be3ccSHelmut Schaa 			sdata, NULL,
6777d3be3ccSHelmut Schaa 			local->scan_req->ssids[i].ssid,
6787d3be3ccSHelmut Schaa 			local->scan_req->ssids[i].ssid_len,
6797d3be3ccSHelmut Schaa 			local->scan_req->ie, local->scan_req->ie_len);
6807d3be3ccSHelmut Schaa 
6817d3be3ccSHelmut Schaa 	/*
6827d3be3ccSHelmut Schaa 	 * After sending probe requests, wait for probe responses
6837d3be3ccSHelmut Schaa 	 * on the channel.
6847d3be3ccSHelmut Schaa 	 */
6857d3be3ccSHelmut Schaa 	*next_delay = IEEE80211_CHANNEL_TIME;
686977923b0SHelmut Schaa 	local->next_scan_state = SCAN_DECISION;
6877d3be3ccSHelmut Schaa }
6887d3be3ccSHelmut Schaa 
689c2b13452SJohannes Berg void ieee80211_scan_work(struct work_struct *work)
6900a51b27eSJohannes Berg {
6910a51b27eSJohannes Berg 	struct ieee80211_local *local =
6920a51b27eSJohannes Berg 		container_of(work, struct ieee80211_local, scan_work.work);
6930a51b27eSJohannes Berg 	struct ieee80211_sub_if_data *sdata = local->scan_sdata;
6940a51b27eSJohannes Berg 	unsigned long next_delay = 0;
6950a51b27eSJohannes Berg 
696f3b85252SJohannes Berg 	mutex_lock(&local->scan_mtx);
697f3b85252SJohannes Berg 	if (!sdata || !local->scan_req) {
698f3b85252SJohannes Berg 		mutex_unlock(&local->scan_mtx);
699f3b85252SJohannes Berg 		return;
700f3b85252SJohannes Berg 	}
701f3b85252SJohannes Berg 
7024d36ec58SJohannes Berg 	if (local->hw_scan_req) {
7034d36ec58SJohannes Berg 		int rc = drv_hw_scan(local, local->hw_scan_req);
7044d36ec58SJohannes Berg 		mutex_unlock(&local->scan_mtx);
7054d36ec58SJohannes Berg 		if (rc)
7064d36ec58SJohannes Berg 			ieee80211_scan_completed(&local->hw, true);
7074d36ec58SJohannes Berg 		return;
7084d36ec58SJohannes Berg 	}
7094d36ec58SJohannes Berg 
710fbe9c429SHelmut Schaa 	if (local->scan_req && !local->scanning) {
711f3b85252SJohannes Berg 		struct cfg80211_scan_request *req = local->scan_req;
712f3b85252SJohannes Berg 		int rc;
713f3b85252SJohannes Berg 
714f3b85252SJohannes Berg 		local->scan_req = NULL;
71515db0b7fSJohannes Berg 		local->scan_sdata = NULL;
716f3b85252SJohannes Berg 
717f3b85252SJohannes Berg 		rc = __ieee80211_start_scan(sdata, req);
718f3b85252SJohannes Berg 		mutex_unlock(&local->scan_mtx);
719f3b85252SJohannes Berg 
720f3b85252SJohannes Berg 		if (rc)
721f3b85252SJohannes Berg 			ieee80211_scan_completed(&local->hw, true);
722f3b85252SJohannes Berg 		return;
723f3b85252SJohannes Berg 	}
724f3b85252SJohannes Berg 
725f3b85252SJohannes Berg 	mutex_unlock(&local->scan_mtx);
726f3b85252SJohannes Berg 
7275bc75728SJohannes Berg 	/*
7285bc75728SJohannes Berg 	 * Avoid re-scheduling when the sdata is going away.
7295bc75728SJohannes Berg 	 */
730*9607e6b6SJohannes Berg 	if (!ieee80211_sdata_running(sdata)) {
731f3b85252SJohannes Berg 		ieee80211_scan_completed(&local->hw, true);
7320a51b27eSJohannes Berg 		return;
733f3b85252SJohannes Berg 	}
7340a51b27eSJohannes Berg 
735f502d09bSHelmut Schaa 	/*
736f502d09bSHelmut Schaa 	 * as long as no delay is required advance immediately
737f502d09bSHelmut Schaa 	 * without scheduling a new work
738f502d09bSHelmut Schaa 	 */
739f502d09bSHelmut Schaa 	do {
740977923b0SHelmut Schaa 		switch (local->next_scan_state) {
7412fb3f028SHelmut Schaa 		case SCAN_DECISION:
7422fb3f028SHelmut Schaa 			if (ieee80211_scan_state_decision(local, &next_delay))
7430a51b27eSJohannes Berg 				return;
7440a51b27eSJohannes Berg 			break;
7452fb3f028SHelmut Schaa 		case SCAN_SET_CHANNEL:
7462fb3f028SHelmut Schaa 			ieee80211_scan_state_set_channel(local, &next_delay);
7472fb3f028SHelmut Schaa 			break;
7480a51b27eSJohannes Berg 		case SCAN_SEND_PROBE:
7497d3be3ccSHelmut Schaa 			ieee80211_scan_state_send_probe(local, &next_delay);
7500a51b27eSJohannes Berg 			break;
751142b9f50SHelmut Schaa 		case SCAN_LEAVE_OPER_CHANNEL:
752142b9f50SHelmut Schaa 			ieee80211_scan_state_leave_oper_channel(local, &next_delay);
753142b9f50SHelmut Schaa 			break;
754142b9f50SHelmut Schaa 		case SCAN_ENTER_OPER_CHANNEL:
755142b9f50SHelmut Schaa 			ieee80211_scan_state_enter_oper_channel(local, &next_delay);
756142b9f50SHelmut Schaa 			break;
7570a51b27eSJohannes Berg 		}
758f502d09bSHelmut Schaa 	} while (next_delay == 0);
7590a51b27eSJohannes Berg 
76042935ecaSLuis R. Rodriguez 	ieee80211_queue_delayed_work(&local->hw, &local->scan_work, next_delay);
7610a51b27eSJohannes Berg }
7620a51b27eSJohannes Berg 
763c2b13452SJohannes Berg int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
7642a519311SJohannes Berg 			   struct cfg80211_scan_request *req)
7650a51b27eSJohannes Berg {
766f3b85252SJohannes Berg 	int res;
7670a51b27eSJohannes Berg 
768f3b85252SJohannes Berg 	mutex_lock(&sdata->local->scan_mtx);
769f3b85252SJohannes Berg 	res = __ieee80211_start_scan(sdata, req);
770f3b85252SJohannes Berg 	mutex_unlock(&sdata->local->scan_mtx);
7712a519311SJohannes Berg 
772f3b85252SJohannes Berg 	return res;
7730a51b27eSJohannes Berg }
7740a51b27eSJohannes Berg 
775f3b85252SJohannes Berg int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
776f3b85252SJohannes Berg 				    const u8 *ssid, u8 ssid_len)
777f3b85252SJohannes Berg {
778f3b85252SJohannes Berg 	struct ieee80211_local *local = sdata->local;
779f3b85252SJohannes Berg 	int ret = -EBUSY;
7809116dd01SJohannes Berg 
781f3b85252SJohannes Berg 	mutex_lock(&local->scan_mtx);
782f3b85252SJohannes Berg 
783f3b85252SJohannes Berg 	/* busy scanning */
784f3b85252SJohannes Berg 	if (local->scan_req)
785f3b85252SJohannes Berg 		goto unlock;
786f3b85252SJohannes Berg 
7875ba63533SJohannes Berg 	memcpy(local->int_scan_req->ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN);
7885ba63533SJohannes Berg 	local->int_scan_req->ssids[0].ssid_len = ssid_len;
789f3b85252SJohannes Berg 
7905ba63533SJohannes Berg 	ret = __ieee80211_start_scan(sdata, sdata->local->int_scan_req);
791f3b85252SJohannes Berg  unlock:
792f3b85252SJohannes Berg 	mutex_unlock(&local->scan_mtx);
793f3b85252SJohannes Berg 	return ret;
7940a51b27eSJohannes Berg }
7955bb644a0SJohannes Berg 
7965bb644a0SJohannes Berg void ieee80211_scan_cancel(struct ieee80211_local *local)
7975bb644a0SJohannes Berg {
79815db0b7fSJohannes Berg 	bool abortscan;
7995bb644a0SJohannes Berg 
8005bb644a0SJohannes Berg 	cancel_delayed_work_sync(&local->scan_work);
8015bb644a0SJohannes Berg 
8025bb644a0SJohannes Berg 	/*
8035bb644a0SJohannes Berg 	 * Only call this function when a scan can't be
8045bb644a0SJohannes Berg 	 * queued -- mostly at suspend under RTNL.
8055bb644a0SJohannes Berg 	 */
8065bb644a0SJohannes Berg 	mutex_lock(&local->scan_mtx);
80715db0b7fSJohannes Berg 	abortscan = test_bit(SCAN_SW_SCANNING, &local->scanning) ||
80815db0b7fSJohannes Berg 		    (!local->scanning && local->scan_req);
8095bb644a0SJohannes Berg 	mutex_unlock(&local->scan_mtx);
8105bb644a0SJohannes Berg 
81115db0b7fSJohannes Berg 	if (abortscan)
8125bb644a0SJohannes Berg 		ieee80211_scan_completed(&local->hw, true);
8135bb644a0SJohannes Berg }
814