xref: /linux/net/mac80211/scan.c (revision f3b85252f081581a8f257545ed748062dce7798b)
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 
1500d3f14cSJohannes Berg /* TODO: figure out how to avoid that the "current BSS" expires */
165484e237SJohannes Berg 
170a51b27eSJohannes Berg #include <linux/wireless.h>
180a51b27eSJohannes Berg #include <linux/if_arp.h>
19078e1e60SJohannes Berg #include <linux/rtnetlink.h>
200a51b27eSJohannes Berg #include <net/mac80211.h>
210a51b27eSJohannes Berg #include <net/iw_handler.h>
220a51b27eSJohannes Berg 
230a51b27eSJohannes Berg #include "ieee80211_i.h"
245484e237SJohannes Berg #include "mesh.h"
250a51b27eSJohannes Berg 
260a51b27eSJohannes Berg #define IEEE80211_PROBE_DELAY (HZ / 33)
270a51b27eSJohannes Berg #define IEEE80211_CHANNEL_TIME (HZ / 33)
280a51b27eSJohannes Berg #define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 5)
290a51b27eSJohannes Berg 
30c2b13452SJohannes Berg struct ieee80211_bss *
315484e237SJohannes Berg ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
325484e237SJohannes Berg 		     u8 *ssid, u8 ssid_len)
335484e237SJohannes Berg {
3400d3f14cSJohannes Berg 	return (void *)cfg80211_get_bss(local->hw.wiphy,
3500d3f14cSJohannes Berg 					ieee80211_get_channel(local->hw.wiphy,
3600d3f14cSJohannes Berg 							      freq),
3700d3f14cSJohannes Berg 					bssid, ssid, ssid_len,
3800d3f14cSJohannes Berg 					0, 0);
395484e237SJohannes Berg }
405484e237SJohannes Berg 
4100d3f14cSJohannes Berg static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss)
425484e237SJohannes Berg {
4300d3f14cSJohannes Berg 	struct ieee80211_bss *bss = (void *)cbss;
445484e237SJohannes Berg 
455484e237SJohannes Berg 	kfree(bss_mesh_id(bss));
465484e237SJohannes Berg 	kfree(bss_mesh_cfg(bss));
475484e237SJohannes Berg }
485484e237SJohannes Berg 
495484e237SJohannes Berg void ieee80211_rx_bss_put(struct ieee80211_local *local,
50c2b13452SJohannes Berg 			  struct ieee80211_bss *bss)
515484e237SJohannes Berg {
5200d3f14cSJohannes Berg 	cfg80211_put_bss((struct cfg80211_bss *)bss);
535484e237SJohannes Berg }
545484e237SJohannes Berg 
55c2b13452SJohannes Berg struct ieee80211_bss *
565484e237SJohannes Berg ieee80211_bss_info_update(struct ieee80211_local *local,
575484e237SJohannes Berg 			  struct ieee80211_rx_status *rx_status,
585484e237SJohannes Berg 			  struct ieee80211_mgmt *mgmt,
595484e237SJohannes Berg 			  size_t len,
605484e237SJohannes Berg 			  struct ieee802_11_elems *elems,
612a519311SJohannes Berg 			  struct ieee80211_channel *channel,
622a519311SJohannes Berg 			  bool beacon)
635484e237SJohannes Berg {
64c2b13452SJohannes Berg 	struct ieee80211_bss *bss;
6500d3f14cSJohannes Berg 	int clen;
662a519311SJohannes Berg 	s32 signal = 0;
672a519311SJohannes Berg 
6877965c97SJohannes Berg 	if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
692a519311SJohannes Berg 		signal = rx_status->signal * 100;
7077965c97SJohannes Berg 	else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
712a519311SJohannes Berg 		signal = (rx_status->signal * 100) / local->hw.max_signal;
722a519311SJohannes Berg 
7300d3f14cSJohannes Berg 	bss = (void *)cfg80211_inform_bss_frame(local->hw.wiphy, channel,
7477965c97SJohannes Berg 						mgmt, len, signal, GFP_ATOMIC);
755484e237SJohannes Berg 
765484e237SJohannes Berg 	if (!bss)
775484e237SJohannes Berg 		return NULL;
7800d3f14cSJohannes Berg 
7900d3f14cSJohannes Berg 	bss->cbss.free_priv = ieee80211_rx_bss_free;
805484e237SJohannes Berg 
815484e237SJohannes Berg 	/* save the ERP value so that it is available at association time */
825484e237SJohannes Berg 	if (elems->erp_info && elems->erp_info_len >= 1) {
835484e237SJohannes Berg 		bss->erp_value = elems->erp_info[0];
845484e237SJohannes Berg 		bss->has_erp_value = 1;
855484e237SJohannes Berg 	}
865484e237SJohannes Berg 
875484e237SJohannes Berg 	if (elems->tim) {
885484e237SJohannes Berg 		struct ieee80211_tim_ie *tim_ie =
895484e237SJohannes Berg 			(struct ieee80211_tim_ie *)elems->tim;
905484e237SJohannes Berg 		bss->dtim_period = tim_ie->dtim_period;
915484e237SJohannes Berg 	}
925484e237SJohannes Berg 
935484e237SJohannes Berg 	/* set default value for buggy APs */
945484e237SJohannes Berg 	if (!elems->tim || bss->dtim_period == 0)
955484e237SJohannes Berg 		bss->dtim_period = 1;
965484e237SJohannes Berg 
975484e237SJohannes Berg 	bss->supp_rates_len = 0;
985484e237SJohannes Berg 	if (elems->supp_rates) {
995484e237SJohannes Berg 		clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
1005484e237SJohannes Berg 		if (clen > elems->supp_rates_len)
1015484e237SJohannes Berg 			clen = elems->supp_rates_len;
1025484e237SJohannes Berg 		memcpy(&bss->supp_rates[bss->supp_rates_len], elems->supp_rates,
1035484e237SJohannes Berg 		       clen);
1045484e237SJohannes Berg 		bss->supp_rates_len += clen;
1055484e237SJohannes Berg 	}
1065484e237SJohannes Berg 	if (elems->ext_supp_rates) {
1075484e237SJohannes Berg 		clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
1085484e237SJohannes Berg 		if (clen > elems->ext_supp_rates_len)
1095484e237SJohannes Berg 			clen = elems->ext_supp_rates_len;
1105484e237SJohannes Berg 		memcpy(&bss->supp_rates[bss->supp_rates_len],
1115484e237SJohannes Berg 		       elems->ext_supp_rates, clen);
1125484e237SJohannes Berg 		bss->supp_rates_len += clen;
1135484e237SJohannes Berg 	}
1145484e237SJohannes Berg 
1155484e237SJohannes Berg 	bss->wmm_used = elems->wmm_param || elems->wmm_info;
1165484e237SJohannes Berg 
1175484e237SJohannes Berg 	if (!beacon)
1185484e237SJohannes Berg 		bss->last_probe_resp = jiffies;
1195484e237SJohannes Berg 
1205484e237SJohannes Berg 	return bss;
1215484e237SJohannes Berg }
1220a51b27eSJohannes Berg 
1237a947080SVasanthakumar Thiagarajan void ieee80211_rx_bss_remove(struct ieee80211_sub_if_data *sdata, u8 *bssid,
1247a947080SVasanthakumar Thiagarajan 			     int freq, u8 *ssid, u8 ssid_len)
1257a947080SVasanthakumar Thiagarajan {
1267a947080SVasanthakumar Thiagarajan 	struct ieee80211_bss *bss;
1277a947080SVasanthakumar Thiagarajan 	struct ieee80211_local *local = sdata->local;
1287a947080SVasanthakumar Thiagarajan 
1297a947080SVasanthakumar Thiagarajan 	bss = ieee80211_rx_bss_get(local, bssid, freq, ssid, ssid_len);
1307a947080SVasanthakumar Thiagarajan 	if (bss) {
13100d3f14cSJohannes Berg 		cfg80211_unlink_bss(local->hw.wiphy, (void *)bss);
1327a947080SVasanthakumar Thiagarajan 		ieee80211_rx_bss_put(local, bss);
1337a947080SVasanthakumar Thiagarajan 	}
1347a947080SVasanthakumar Thiagarajan }
1357a947080SVasanthakumar Thiagarajan 
13698c8fccfSJohannes Berg ieee80211_rx_result
137c2b13452SJohannes Berg ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
13898c8fccfSJohannes Berg 		  struct ieee80211_rx_status *rx_status)
13998c8fccfSJohannes Berg {
14098c8fccfSJohannes Berg 	struct ieee80211_mgmt *mgmt;
141c2b13452SJohannes Berg 	struct ieee80211_bss *bss;
14298c8fccfSJohannes Berg 	u8 *elements;
14398c8fccfSJohannes Berg 	struct ieee80211_channel *channel;
14498c8fccfSJohannes Berg 	size_t baselen;
14598c8fccfSJohannes Berg 	int freq;
14698c8fccfSJohannes Berg 	__le16 fc;
14798c8fccfSJohannes Berg 	bool presp, beacon = false;
14898c8fccfSJohannes Berg 	struct ieee802_11_elems elems;
14998c8fccfSJohannes Berg 
15098c8fccfSJohannes Berg 	if (skb->len < 2)
15198c8fccfSJohannes Berg 		return RX_DROP_UNUSABLE;
15298c8fccfSJohannes Berg 
15398c8fccfSJohannes Berg 	mgmt = (struct ieee80211_mgmt *) skb->data;
15498c8fccfSJohannes Berg 	fc = mgmt->frame_control;
15598c8fccfSJohannes Berg 
15698c8fccfSJohannes Berg 	if (ieee80211_is_ctl(fc))
15798c8fccfSJohannes Berg 		return RX_CONTINUE;
15898c8fccfSJohannes Berg 
15998c8fccfSJohannes Berg 	if (skb->len < 24)
16098c8fccfSJohannes Berg 		return RX_DROP_MONITOR;
16198c8fccfSJohannes Berg 
16298c8fccfSJohannes Berg 	presp = ieee80211_is_probe_resp(fc);
16398c8fccfSJohannes Berg 	if (presp) {
16498c8fccfSJohannes Berg 		/* ignore ProbeResp to foreign address */
16598c8fccfSJohannes Berg 		if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN))
16698c8fccfSJohannes Berg 			return RX_DROP_MONITOR;
16798c8fccfSJohannes Berg 
16898c8fccfSJohannes Berg 		presp = true;
16998c8fccfSJohannes Berg 		elements = mgmt->u.probe_resp.variable;
17098c8fccfSJohannes Berg 		baselen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
17198c8fccfSJohannes Berg 	} else {
17298c8fccfSJohannes Berg 		beacon = ieee80211_is_beacon(fc);
17398c8fccfSJohannes Berg 		baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable);
17498c8fccfSJohannes Berg 		elements = mgmt->u.beacon.variable;
17598c8fccfSJohannes Berg 	}
17698c8fccfSJohannes Berg 
17798c8fccfSJohannes Berg 	if (!presp && !beacon)
17898c8fccfSJohannes Berg 		return RX_CONTINUE;
17998c8fccfSJohannes Berg 
18098c8fccfSJohannes Berg 	if (baselen > skb->len)
18198c8fccfSJohannes Berg 		return RX_DROP_MONITOR;
18298c8fccfSJohannes Berg 
18398c8fccfSJohannes Berg 	ieee802_11_parse_elems(elements, skb->len - baselen, &elems);
18498c8fccfSJohannes Berg 
18598c8fccfSJohannes Berg 	if (elems.ds_params && elems.ds_params_len == 1)
18698c8fccfSJohannes Berg 		freq = ieee80211_channel_to_frequency(elems.ds_params[0]);
18798c8fccfSJohannes Berg 	else
18898c8fccfSJohannes Berg 		freq = rx_status->freq;
18998c8fccfSJohannes Berg 
19098c8fccfSJohannes Berg 	channel = ieee80211_get_channel(sdata->local->hw.wiphy, freq);
19198c8fccfSJohannes Berg 
19298c8fccfSJohannes Berg 	if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
19398c8fccfSJohannes Berg 		return RX_DROP_MONITOR;
19498c8fccfSJohannes Berg 
19598c8fccfSJohannes Berg 	bss = ieee80211_bss_info_update(sdata->local, rx_status,
19698c8fccfSJohannes Berg 					mgmt, skb->len, &elems,
1972a519311SJohannes Berg 					channel, beacon);
198d048e503SJouni Malinen 	if (bss)
19998c8fccfSJohannes Berg 		ieee80211_rx_bss_put(sdata->local, bss);
20098c8fccfSJohannes Berg 
20198c8fccfSJohannes Berg 	dev_kfree_skb(skb);
20298c8fccfSJohannes Berg 	return RX_QUEUED;
20398c8fccfSJohannes Berg }
20498c8fccfSJohannes Berg 
2059050bdd8SKalle Valo /*
2069050bdd8SKalle Valo  * inform AP that we will go to sleep so that it will buffer the frames
2079050bdd8SKalle Valo  * while we scan
2089050bdd8SKalle Valo  */
2099050bdd8SKalle Valo static void ieee80211_scan_ps_enable(struct ieee80211_sub_if_data *sdata)
2109050bdd8SKalle Valo {
2119050bdd8SKalle Valo 	struct ieee80211_local *local = sdata->local;
2129050bdd8SKalle Valo 	bool ps = false;
2139050bdd8SKalle Valo 
2149050bdd8SKalle Valo 	/* FIXME: what to do when local->pspolling is true? */
2159050bdd8SKalle Valo 
2169050bdd8SKalle Valo 	del_timer_sync(&local->dynamic_ps_timer);
2179050bdd8SKalle Valo 	cancel_work_sync(&local->dynamic_ps_enable_work);
2189050bdd8SKalle Valo 
2199050bdd8SKalle Valo 	if (local->hw.conf.flags & IEEE80211_CONF_PS) {
2209050bdd8SKalle Valo 		ps = true;
2219050bdd8SKalle Valo 		local->hw.conf.flags &= ~IEEE80211_CONF_PS;
2229050bdd8SKalle Valo 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
2239050bdd8SKalle Valo 	}
2249050bdd8SKalle Valo 
2259050bdd8SKalle Valo 	if (!ps || !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))
2269050bdd8SKalle Valo 		/*
2279050bdd8SKalle Valo 		 * If power save was enabled, no need to send a nullfunc
2289050bdd8SKalle Valo 		 * frame because AP knows that we are sleeping. But if the
2299050bdd8SKalle Valo 		 * hardware is creating the nullfunc frame for power save
2309050bdd8SKalle Valo 		 * status (ie. IEEE80211_HW_PS_NULLFUNC_STACK is not
2319050bdd8SKalle Valo 		 * enabled) and power save was enabled, the firmware just
2329050bdd8SKalle Valo 		 * sent a null frame with power save disabled. So we need
2339050bdd8SKalle Valo 		 * to send a new nullfunc frame to inform the AP that we
2349050bdd8SKalle Valo 		 * are again sleeping.
2359050bdd8SKalle Valo 		 */
2369050bdd8SKalle Valo 		ieee80211_send_nullfunc(local, sdata, 1);
2379050bdd8SKalle Valo }
2389050bdd8SKalle Valo 
2399050bdd8SKalle Valo /* inform AP that we are awake again, unless power save is enabled */
2409050bdd8SKalle Valo static void ieee80211_scan_ps_disable(struct ieee80211_sub_if_data *sdata)
2419050bdd8SKalle Valo {
2429050bdd8SKalle Valo 	struct ieee80211_local *local = sdata->local;
2439050bdd8SKalle Valo 
244965bedadSJohannes Berg 	if (!local->ps_sdata)
2459050bdd8SKalle Valo 		ieee80211_send_nullfunc(local, sdata, 0);
2469050bdd8SKalle Valo 	else {
2479050bdd8SKalle Valo 		/*
2489050bdd8SKalle Valo 		 * In !IEEE80211_HW_PS_NULLFUNC_STACK case the hardware
2499050bdd8SKalle Valo 		 * will send a nullfunc frame with the powersave bit set
2509050bdd8SKalle Valo 		 * even though the AP already knows that we are sleeping.
2519050bdd8SKalle Valo 		 * This could be avoided by sending a null frame with power
2529050bdd8SKalle Valo 		 * save bit disabled before enabling the power save, but
2539050bdd8SKalle Valo 		 * this doesn't gain anything.
2549050bdd8SKalle Valo 		 *
2559050bdd8SKalle Valo 		 * When IEEE80211_HW_PS_NULLFUNC_STACK is enabled, no need
2569050bdd8SKalle Valo 		 * to send a nullfunc frame because AP already knows that
2579050bdd8SKalle Valo 		 * we are sleeping, let's just enable power save mode in
2589050bdd8SKalle Valo 		 * hardware.
2599050bdd8SKalle Valo 		 */
2609050bdd8SKalle Valo 		local->hw.conf.flags |= IEEE80211_CONF_PS;
2619050bdd8SKalle Valo 		ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
2629050bdd8SKalle Valo 	}
2639050bdd8SKalle Valo }
2649050bdd8SKalle Valo 
265*f3b85252SJohannes Berg static void ieee80211_restore_scan_ies(struct ieee80211_local *local)
2660a51b27eSJohannes Berg {
267de95a54bSJohannes Berg 	kfree(local->scan_req->ie);
268de95a54bSJohannes Berg 	local->scan_req->ie = local->orig_ies;
269de95a54bSJohannes Berg 	local->scan_req->ie_len = local->orig_ies_len;
270de95a54bSJohannes Berg }
271de95a54bSJohannes Berg 
272*f3b85252SJohannes Berg void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
273*f3b85252SJohannes Berg {
274*f3b85252SJohannes Berg 	struct ieee80211_local *local = hw_to_local(hw);
275*f3b85252SJohannes Berg 	struct ieee80211_sub_if_data *sdata;
276*f3b85252SJohannes Berg 	bool was_hw_scan;
277*f3b85252SJohannes Berg 
278*f3b85252SJohannes Berg 	mutex_lock(&local->scan_mtx);
279*f3b85252SJohannes Berg 
280*f3b85252SJohannes Berg 	if (WARN_ON(!local->hw_scanning && !local->sw_scanning)) {
281*f3b85252SJohannes Berg 		mutex_unlock(&local->scan_mtx);
282*f3b85252SJohannes Berg 		return;
283*f3b85252SJohannes Berg 	}
284*f3b85252SJohannes Berg 
285*f3b85252SJohannes Berg 	if (WARN_ON(!local->scan_req)) {
286*f3b85252SJohannes Berg 		mutex_unlock(&local->scan_mtx);
287*f3b85252SJohannes Berg 		return;
288*f3b85252SJohannes Berg 	}
289*f3b85252SJohannes Berg 
290*f3b85252SJohannes Berg 	if (local->hw_scanning)
291*f3b85252SJohannes Berg 		ieee80211_restore_scan_ies(local);
292*f3b85252SJohannes Berg 
2932a519311SJohannes Berg 	if (local->scan_req != &local->int_scan_req)
2942a519311SJohannes Berg 		cfg80211_scan_done(local->scan_req, aborted);
2952a519311SJohannes Berg 	local->scan_req = NULL;
2962a519311SJohannes Berg 
297*f3b85252SJohannes Berg 	was_hw_scan = local->hw_scanning;
298c2b13452SJohannes Berg 	local->hw_scanning = false;
299*f3b85252SJohannes Berg 	local->sw_scanning = false;
300*f3b85252SJohannes Berg 
301*f3b85252SJohannes Berg 	/* we only have to protect scan_req and hw/sw scan */
302*f3b85252SJohannes Berg 	mutex_unlock(&local->scan_mtx);
303*f3b85252SJohannes Berg 
304*f3b85252SJohannes Berg 	if (was_hw_scan) {
305e8975581SJohannes Berg 		/*
306e8975581SJohannes Berg 		 * Somebody might have requested channel change during scan
307e8975581SJohannes Berg 		 * that we won't have acted upon, try now. ieee80211_hw_config
308e8975581SJohannes Berg 		 * will set the flag based on actual changes.
309e8975581SJohannes Berg 		 */
310e8975581SJohannes Berg 		ieee80211_hw_config(local, 0);
3110a51b27eSJohannes Berg 		goto done;
3120a51b27eSJohannes Berg 	}
3130a51b27eSJohannes Berg 
314e8975581SJohannes Berg 	ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
3150a51b27eSJohannes Berg 
3160a51b27eSJohannes Berg 	netif_tx_lock_bh(local->mdev);
3170a51b27eSJohannes Berg 	netif_addr_lock(local->mdev);
3180a51b27eSJohannes Berg 	local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC;
3190a51b27eSJohannes Berg 	local->ops->configure_filter(local_to_hw(local),
3200a51b27eSJohannes Berg 				     FIF_BCN_PRBRESP_PROMISC,
3210a51b27eSJohannes Berg 				     &local->filter_flags,
3220a51b27eSJohannes Berg 				     local->mdev->mc_count,
3230a51b27eSJohannes Berg 				     local->mdev->mc_list);
3240a51b27eSJohannes Berg 
3250a51b27eSJohannes Berg 	netif_addr_unlock(local->mdev);
3260a51b27eSJohannes Berg 	netif_tx_unlock_bh(local->mdev);
3270a51b27eSJohannes Berg 
32880e775bfSMichael Buesch 	if (local->ops->sw_scan_complete)
32980e775bfSMichael Buesch 		local->ops->sw_scan_complete(local_to_hw(local));
33080e775bfSMichael Buesch 
331078e1e60SJohannes Berg 	mutex_lock(&local->iflist_mtx);
332078e1e60SJohannes Berg 	list_for_each_entry(sdata, &local->interfaces, list) {
333fb9ddbf0SJohannes Berg 		if (!netif_running(sdata->dev))
334fb9ddbf0SJohannes Berg 			continue;
335fb9ddbf0SJohannes Berg 
3360a51b27eSJohannes Berg 		/* Tell AP we're back */
33705c914feSJohannes Berg 		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
33846900298SJohannes Berg 			if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) {
3399050bdd8SKalle Valo 				ieee80211_scan_ps_disable(sdata);
3400a51b27eSJohannes Berg 				netif_tx_wake_all_queues(sdata->dev);
3410a51b27eSJohannes Berg 			}
3420a51b27eSJohannes Berg 		} else
3430a51b27eSJohannes Berg 			netif_tx_wake_all_queues(sdata->dev);
344078e1e60SJohannes Berg 
34514b80724SJohannes Berg 		/* re-enable beaconing */
34614b80724SJohannes Berg 		if (sdata->vif.type == NL80211_IFTYPE_AP ||
34714b80724SJohannes Berg 		    sdata->vif.type == NL80211_IFTYPE_ADHOC ||
34814b80724SJohannes Berg 		    sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
34914b80724SJohannes Berg 			ieee80211_if_config(sdata,
35014b80724SJohannes Berg 					    IEEE80211_IFCC_BEACON_ENABLED);
3510a51b27eSJohannes Berg 	}
352078e1e60SJohannes Berg 	mutex_unlock(&local->iflist_mtx);
3530a51b27eSJohannes Berg 
3540a51b27eSJohannes Berg  done:
3550a51b27eSJohannes Berg 	ieee80211_mlme_notify_scan_completed(local);
35646900298SJohannes Berg 	ieee80211_ibss_notify_scan_completed(local);
357472dbc45SJohannes Berg 	ieee80211_mesh_notify_scan_completed(local);
3580a51b27eSJohannes Berg }
3590a51b27eSJohannes Berg EXPORT_SYMBOL(ieee80211_scan_completed);
3600a51b27eSJohannes Berg 
361*f3b85252SJohannes Berg static int ieee80211_start_sw_scan(struct ieee80211_local *local)
362*f3b85252SJohannes Berg {
363*f3b85252SJohannes Berg 	struct ieee80211_sub_if_data *sdata;
364*f3b85252SJohannes Berg 
365*f3b85252SJohannes Berg 	/*
366*f3b85252SJohannes Berg 	 * Hardware/driver doesn't support hw_scan, so use software
367*f3b85252SJohannes Berg 	 * scanning instead. First send a nullfunc frame with power save
368*f3b85252SJohannes Berg 	 * bit on so that AP will buffer the frames for us while we are not
369*f3b85252SJohannes Berg 	 * listening, then send probe requests to each channel and wait for
370*f3b85252SJohannes Berg 	 * the responses. After all channels are scanned, tune back to the
371*f3b85252SJohannes Berg 	 * original channel and send a nullfunc frame with power save bit
372*f3b85252SJohannes Berg 	 * off to trigger the AP to send us all the buffered frames.
373*f3b85252SJohannes Berg 	 *
374*f3b85252SJohannes Berg 	 * Note that while local->sw_scanning is true everything else but
375*f3b85252SJohannes Berg 	 * nullfunc frames and probe requests will be dropped in
376*f3b85252SJohannes Berg 	 * ieee80211_tx_h_check_assoc().
377*f3b85252SJohannes Berg 	 */
378*f3b85252SJohannes Berg 	if (local->ops->sw_scan_start)
379*f3b85252SJohannes Berg 		local->ops->sw_scan_start(local_to_hw(local));
380*f3b85252SJohannes Berg 
381*f3b85252SJohannes Berg 	mutex_lock(&local->iflist_mtx);
382*f3b85252SJohannes Berg 	list_for_each_entry(sdata, &local->interfaces, list) {
383*f3b85252SJohannes Berg 		if (!netif_running(sdata->dev))
384*f3b85252SJohannes Berg 			continue;
385*f3b85252SJohannes Berg 
386*f3b85252SJohannes Berg 		/* disable beaconing */
387*f3b85252SJohannes Berg 		if (sdata->vif.type == NL80211_IFTYPE_AP ||
388*f3b85252SJohannes Berg 		    sdata->vif.type == NL80211_IFTYPE_ADHOC ||
389*f3b85252SJohannes Berg 		    sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
390*f3b85252SJohannes Berg 			ieee80211_if_config(sdata,
391*f3b85252SJohannes Berg 					    IEEE80211_IFCC_BEACON_ENABLED);
392*f3b85252SJohannes Berg 
393*f3b85252SJohannes Berg 		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
394*f3b85252SJohannes Berg 			if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) {
395*f3b85252SJohannes Berg 				netif_tx_stop_all_queues(sdata->dev);
396*f3b85252SJohannes Berg 				ieee80211_scan_ps_enable(sdata);
397*f3b85252SJohannes Berg 			}
398*f3b85252SJohannes Berg 		} else
399*f3b85252SJohannes Berg 			netif_tx_stop_all_queues(sdata->dev);
400*f3b85252SJohannes Berg 	}
401*f3b85252SJohannes Berg 	mutex_unlock(&local->iflist_mtx);
402*f3b85252SJohannes Berg 
403*f3b85252SJohannes Berg 	local->scan_state = SCAN_SET_CHANNEL;
404*f3b85252SJohannes Berg 	local->scan_channel_idx = 0;
405*f3b85252SJohannes Berg 
406*f3b85252SJohannes Berg 	netif_addr_lock_bh(local->mdev);
407*f3b85252SJohannes Berg 	local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
408*f3b85252SJohannes Berg 	local->ops->configure_filter(local_to_hw(local),
409*f3b85252SJohannes Berg 				     FIF_BCN_PRBRESP_PROMISC,
410*f3b85252SJohannes Berg 				     &local->filter_flags,
411*f3b85252SJohannes Berg 				     local->mdev->mc_count,
412*f3b85252SJohannes Berg 				     local->mdev->mc_list);
413*f3b85252SJohannes Berg 	netif_addr_unlock_bh(local->mdev);
414*f3b85252SJohannes Berg 
415*f3b85252SJohannes Berg 	/* TODO: start scan as soon as all nullfunc frames are ACKed */
416*f3b85252SJohannes Berg 	queue_delayed_work(local->hw.workqueue, &local->scan_work,
417*f3b85252SJohannes Berg 			   IEEE80211_CHANNEL_TIME);
418*f3b85252SJohannes Berg 
419*f3b85252SJohannes Berg 	return 0;
420*f3b85252SJohannes Berg }
421*f3b85252SJohannes Berg 
422*f3b85252SJohannes Berg 
423*f3b85252SJohannes Berg static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
424*f3b85252SJohannes Berg 				  struct cfg80211_scan_request *req)
425*f3b85252SJohannes Berg {
426*f3b85252SJohannes Berg 	struct ieee80211_local *local = sdata->local;
427*f3b85252SJohannes Berg 	struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
428*f3b85252SJohannes Berg 	int rc;
429*f3b85252SJohannes Berg 
430*f3b85252SJohannes Berg 	if (local->scan_req)
431*f3b85252SJohannes Berg 		return -EBUSY;
432*f3b85252SJohannes Berg 
433*f3b85252SJohannes Berg 	if (local->ops->hw_scan) {
434*f3b85252SJohannes Berg 		u8 *ies;
435*f3b85252SJohannes Berg 		int ielen;
436*f3b85252SJohannes Berg 
437*f3b85252SJohannes Berg 		ies = kmalloc(2 + IEEE80211_MAX_SSID_LEN +
438*f3b85252SJohannes Berg 			      local->scan_ies_len + req->ie_len, GFP_KERNEL);
439*f3b85252SJohannes Berg 		if (!ies)
440*f3b85252SJohannes Berg 			return -ENOMEM;
441*f3b85252SJohannes Berg 
442*f3b85252SJohannes Berg 		ielen = ieee80211_build_preq_ies(local, ies,
443*f3b85252SJohannes Berg 						 req->ie, req->ie_len);
444*f3b85252SJohannes Berg 		local->orig_ies = req->ie;
445*f3b85252SJohannes Berg 		local->orig_ies_len = req->ie_len;
446*f3b85252SJohannes Berg 		req->ie = ies;
447*f3b85252SJohannes Berg 		req->ie_len = ielen;
448*f3b85252SJohannes Berg 	}
449*f3b85252SJohannes Berg 
450*f3b85252SJohannes Berg 	local->scan_req = req;
451*f3b85252SJohannes Berg 	local->scan_sdata = sdata;
452*f3b85252SJohannes Berg 
453*f3b85252SJohannes Berg 	if (req != &local->int_scan_req &&
454*f3b85252SJohannes Berg 	    sdata->vif.type == NL80211_IFTYPE_STATION &&
455*f3b85252SJohannes Berg 	    (ifmgd->state == IEEE80211_STA_MLME_DIRECT_PROBE ||
456*f3b85252SJohannes Berg 	     ifmgd->state == IEEE80211_STA_MLME_AUTHENTICATE ||
457*f3b85252SJohannes Berg 	     ifmgd->state == IEEE80211_STA_MLME_ASSOCIATE)) {
458*f3b85252SJohannes Berg 		/* actually wait for the assoc to finish/time out */
459*f3b85252SJohannes Berg 		set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request);
460*f3b85252SJohannes Berg 		return 0;
461*f3b85252SJohannes Berg 	}
462*f3b85252SJohannes Berg 
463*f3b85252SJohannes Berg 	if (local->ops->hw_scan)
464*f3b85252SJohannes Berg 		local->hw_scanning = true;
465*f3b85252SJohannes Berg 	else
466*f3b85252SJohannes Berg 		local->sw_scanning = true;
467*f3b85252SJohannes Berg 	/*
468*f3b85252SJohannes Berg 	 * Kicking off the scan need not be protected,
469*f3b85252SJohannes Berg 	 * only the scan variable stuff, since now
470*f3b85252SJohannes Berg 	 * local->scan_req is assigned and other callers
471*f3b85252SJohannes Berg 	 * will abort their scan attempts.
472*f3b85252SJohannes Berg 	 *
473*f3b85252SJohannes Berg 	 * This avoids getting a scan_mtx -> iflist_mtx
474*f3b85252SJohannes Berg 	 * dependency, so that the scan completed calls
475*f3b85252SJohannes Berg 	 * have more locking freedom.
476*f3b85252SJohannes Berg 	 */
477*f3b85252SJohannes Berg 	mutex_unlock(&local->scan_mtx);
478*f3b85252SJohannes Berg 
479*f3b85252SJohannes Berg 	if (local->ops->hw_scan)
480*f3b85252SJohannes Berg 		rc = local->ops->hw_scan(local_to_hw(local),
481*f3b85252SJohannes Berg 					 local->scan_req);
482*f3b85252SJohannes Berg 	else
483*f3b85252SJohannes Berg 		rc = ieee80211_start_sw_scan(local);
484*f3b85252SJohannes Berg 
485*f3b85252SJohannes Berg 	mutex_lock(&local->scan_mtx);
486*f3b85252SJohannes Berg 
487*f3b85252SJohannes Berg 	if (rc) {
488*f3b85252SJohannes Berg 		if (local->ops->hw_scan) {
489*f3b85252SJohannes Berg 			local->hw_scanning = false;
490*f3b85252SJohannes Berg 			ieee80211_restore_scan_ies(local);
491*f3b85252SJohannes Berg 		} else
492*f3b85252SJohannes Berg 			local->sw_scanning = false;
493*f3b85252SJohannes Berg 
494*f3b85252SJohannes Berg 		local->scan_req = NULL;
495*f3b85252SJohannes Berg 		local->scan_sdata = NULL;
496*f3b85252SJohannes Berg 	}
497*f3b85252SJohannes Berg 
498*f3b85252SJohannes Berg 	return rc;
499*f3b85252SJohannes Berg }
500*f3b85252SJohannes Berg 
501c2b13452SJohannes Berg void ieee80211_scan_work(struct work_struct *work)
5020a51b27eSJohannes Berg {
5030a51b27eSJohannes Berg 	struct ieee80211_local *local =
5040a51b27eSJohannes Berg 		container_of(work, struct ieee80211_local, scan_work.work);
5050a51b27eSJohannes Berg 	struct ieee80211_sub_if_data *sdata = local->scan_sdata;
5060a51b27eSJohannes Berg 	struct ieee80211_channel *chan;
5072a519311SJohannes Berg 	int skip, i;
5080a51b27eSJohannes Berg 	unsigned long next_delay = 0;
5090a51b27eSJohannes Berg 
510*f3b85252SJohannes Berg 	mutex_lock(&local->scan_mtx);
511*f3b85252SJohannes Berg 	if (!sdata || !local->scan_req) {
512*f3b85252SJohannes Berg 		mutex_unlock(&local->scan_mtx);
513*f3b85252SJohannes Berg 		return;
514*f3b85252SJohannes Berg 	}
515*f3b85252SJohannes Berg 
516*f3b85252SJohannes Berg 	if (local->scan_req && !(local->sw_scanning || local->hw_scanning)) {
517*f3b85252SJohannes Berg 		struct cfg80211_scan_request *req = local->scan_req;
518*f3b85252SJohannes Berg 		int rc;
519*f3b85252SJohannes Berg 
520*f3b85252SJohannes Berg 		local->scan_req = NULL;
521*f3b85252SJohannes Berg 
522*f3b85252SJohannes Berg 		rc = __ieee80211_start_scan(sdata, req);
523*f3b85252SJohannes Berg 		mutex_unlock(&local->scan_mtx);
524*f3b85252SJohannes Berg 
525*f3b85252SJohannes Berg 		if (rc)
526*f3b85252SJohannes Berg 			ieee80211_scan_completed(&local->hw, true);
527*f3b85252SJohannes Berg 		return;
528*f3b85252SJohannes Berg 	}
529*f3b85252SJohannes Berg 
530*f3b85252SJohannes Berg 	mutex_unlock(&local->scan_mtx);
531*f3b85252SJohannes Berg 
5325bc75728SJohannes Berg 	/*
5335bc75728SJohannes Berg 	 * Avoid re-scheduling when the sdata is going away.
5345bc75728SJohannes Berg 	 */
535*f3b85252SJohannes Berg 	if (!netif_running(sdata->dev)) {
536*f3b85252SJohannes Berg 		ieee80211_scan_completed(&local->hw, true);
5370a51b27eSJohannes Berg 		return;
538*f3b85252SJohannes Berg 	}
5390a51b27eSJohannes Berg 
5400a51b27eSJohannes Berg 	switch (local->scan_state) {
5410a51b27eSJohannes Berg 	case SCAN_SET_CHANNEL:
5420a51b27eSJohannes Berg 		/* if no more bands/channels left, complete scan */
5432a519311SJohannes Berg 		if (local->scan_channel_idx >= local->scan_req->n_channels) {
544*f3b85252SJohannes Berg 			ieee80211_scan_completed(&local->hw, false);
5450a51b27eSJohannes Berg 			return;
5460a51b27eSJohannes Berg 		}
5470a51b27eSJohannes Berg 		skip = 0;
5482a519311SJohannes Berg 		chan = local->scan_req->channels[local->scan_channel_idx];
5490a51b27eSJohannes Berg 
5500a51b27eSJohannes Berg 		if (chan->flags & IEEE80211_CHAN_DISABLED ||
55105c914feSJohannes Berg 		    (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
5520a51b27eSJohannes Berg 		     chan->flags & IEEE80211_CHAN_NO_IBSS))
5530a51b27eSJohannes Berg 			skip = 1;
5540a51b27eSJohannes Berg 
5550a51b27eSJohannes Berg 		if (!skip) {
5560a51b27eSJohannes Berg 			local->scan_channel = chan;
557e8975581SJohannes Berg 			if (ieee80211_hw_config(local,
558e8975581SJohannes Berg 						IEEE80211_CONF_CHANGE_CHANNEL))
5590a51b27eSJohannes Berg 				skip = 1;
5600a51b27eSJohannes Berg 		}
5610a51b27eSJohannes Berg 
5620a51b27eSJohannes Berg 		/* advance state machine to next channel/band */
5630a51b27eSJohannes Berg 		local->scan_channel_idx++;
5640a51b27eSJohannes Berg 
5650a51b27eSJohannes Berg 		if (skip)
5660a51b27eSJohannes Berg 			break;
5670a51b27eSJohannes Berg 
5680a51b27eSJohannes Berg 		next_delay = IEEE80211_PROBE_DELAY +
5690a51b27eSJohannes Berg 			     usecs_to_jiffies(local->hw.channel_change_time);
5700a51b27eSJohannes Berg 		local->scan_state = SCAN_SEND_PROBE;
5710a51b27eSJohannes Berg 		break;
5720a51b27eSJohannes Berg 	case SCAN_SEND_PROBE:
5730a51b27eSJohannes Berg 		next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
5740a51b27eSJohannes Berg 		local->scan_state = SCAN_SET_CHANNEL;
5750a51b27eSJohannes Berg 
5762a519311SJohannes Berg 		if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
5772a519311SJohannes Berg 		    !local->scan_req->n_ssids)
5780a51b27eSJohannes Berg 			break;
5792a519311SJohannes Berg 		for (i = 0; i < local->scan_req->n_ssids; i++)
5802a519311SJohannes Berg 			ieee80211_send_probe_req(
5812a519311SJohannes Berg 				sdata, NULL,
5822a519311SJohannes Berg 				local->scan_req->ssids[i].ssid,
58370692ad2SJouni Malinen 				local->scan_req->ssids[i].ssid_len,
58470692ad2SJouni Malinen 				local->scan_req->ie, local->scan_req->ie_len);
5850a51b27eSJohannes Berg 		next_delay = IEEE80211_CHANNEL_TIME;
5860a51b27eSJohannes Berg 		break;
5870a51b27eSJohannes Berg 	}
5880a51b27eSJohannes Berg 
5890a51b27eSJohannes Berg 	queue_delayed_work(local->hw.workqueue, &local->scan_work,
5900a51b27eSJohannes Berg 			   next_delay);
5910a51b27eSJohannes Berg }
5920a51b27eSJohannes Berg 
593c2b13452SJohannes Berg int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
5942a519311SJohannes Berg 			   struct cfg80211_scan_request *req)
5950a51b27eSJohannes Berg {
596*f3b85252SJohannes Berg 	int res;
5970a51b27eSJohannes Berg 
598*f3b85252SJohannes Berg 	mutex_lock(&sdata->local->scan_mtx);
599*f3b85252SJohannes Berg 	res = __ieee80211_start_scan(sdata, req);
600*f3b85252SJohannes Berg 	mutex_unlock(&sdata->local->scan_mtx);
6012a519311SJohannes Berg 
602*f3b85252SJohannes Berg 	return res;
6030a51b27eSJohannes Berg }
6040a51b27eSJohannes Berg 
605*f3b85252SJohannes Berg int ieee80211_request_internal_scan(struct ieee80211_sub_if_data *sdata,
606*f3b85252SJohannes Berg 				    const u8 *ssid, u8 ssid_len)
607*f3b85252SJohannes Berg {
608*f3b85252SJohannes Berg 	struct ieee80211_local *local = sdata->local;
609*f3b85252SJohannes Berg 	int ret = -EBUSY;
6109116dd01SJohannes Berg 
611*f3b85252SJohannes Berg 	mutex_lock(&local->scan_mtx);
612*f3b85252SJohannes Berg 
613*f3b85252SJohannes Berg 	/* busy scanning */
614*f3b85252SJohannes Berg 	if (local->scan_req)
615*f3b85252SJohannes Berg 		goto unlock;
616*f3b85252SJohannes Berg 
617*f3b85252SJohannes Berg 	memcpy(local->int_scan_req.ssids[0].ssid, ssid, IEEE80211_MAX_SSID_LEN);
618*f3b85252SJohannes Berg 	local->int_scan_req.ssids[0].ssid_len = ssid_len;
619*f3b85252SJohannes Berg 
620*f3b85252SJohannes Berg 	ret = __ieee80211_start_scan(sdata, &sdata->local->int_scan_req);
621*f3b85252SJohannes Berg  unlock:
622*f3b85252SJohannes Berg 	mutex_unlock(&local->scan_mtx);
623*f3b85252SJohannes Berg 	return ret;
6240a51b27eSJohannes Berg }
625