scan.c 12.4 KB
Newer Older
1
/*
2 3
 * Scanning implementation
 *
4 5 6 7 8 9 10 11 12 13 14
 * Copyright 2003, Jouni Malinen <jkmaline@cc.hut.fi>
 * Copyright 2004, Instant802 Networks, Inc.
 * Copyright 2005, Devicescape Software, Inc.
 * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
 * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

15
/* TODO: figure out how to avoid that the "current BSS" expires */
16

17 18
#include <linux/wireless.h>
#include <linux/if_arp.h>
19
#include <linux/rtnetlink.h>
20 21 22 23
#include <net/mac80211.h>
#include <net/iw_handler.h>

#include "ieee80211_i.h"
24
#include "mesh.h"
25 26 27 28 29

#define IEEE80211_PROBE_DELAY (HZ / 33)
#define IEEE80211_CHANNEL_TIME (HZ / 33)
#define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 5)

30
struct ieee80211_bss *
31 32 33
ieee80211_rx_bss_get(struct ieee80211_local *local, u8 *bssid, int freq,
		     u8 *ssid, u8 ssid_len)
{
34 35 36 37 38
	return (void *)cfg80211_get_bss(local->hw.wiphy,
					ieee80211_get_channel(local->hw.wiphy,
							      freq),
					bssid, ssid, ssid_len,
					0, 0);
39 40
}

41
static void ieee80211_rx_bss_free(struct cfg80211_bss *cbss)
42
{
43
	struct ieee80211_bss *bss = (void *)cbss;
44 45 46 47 48 49

	kfree(bss_mesh_id(bss));
	kfree(bss_mesh_cfg(bss));
}

void ieee80211_rx_bss_put(struct ieee80211_local *local,
50
			  struct ieee80211_bss *bss)
51
{
52
	cfg80211_put_bss((struct cfg80211_bss *)bss);
53 54
}

55
struct ieee80211_bss *
56 57 58 59 60
ieee80211_bss_info_update(struct ieee80211_local *local,
			  struct ieee80211_rx_status *rx_status,
			  struct ieee80211_mgmt *mgmt,
			  size_t len,
			  struct ieee802_11_elems *elems,
61 62
			  struct ieee80211_channel *channel,
			  bool beacon)
63
{
64
	struct ieee80211_bss *bss;
65
	int clen;
66 67
	s32 signal = 0;

J
Johannes Berg 已提交
68
	if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
69
		signal = rx_status->signal * 100;
J
Johannes Berg 已提交
70
	else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
71 72
		signal = (rx_status->signal * 100) / local->hw.max_signal;

73
	bss = (void *)cfg80211_inform_bss_frame(local->hw.wiphy, channel,
J
Johannes Berg 已提交
74
						mgmt, len, signal, GFP_ATOMIC);
75

76 77 78 79
	if (!bss)
		return NULL;

	bss->cbss.free_priv = ieee80211_rx_bss_free;
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121

	/* save the ERP value so that it is available at association time */
	if (elems->erp_info && elems->erp_info_len >= 1) {
		bss->erp_value = elems->erp_info[0];
		bss->has_erp_value = 1;
	}

	if (elems->tim) {
		struct ieee80211_tim_ie *tim_ie =
			(struct ieee80211_tim_ie *)elems->tim;
		bss->dtim_period = tim_ie->dtim_period;
	}

	/* set default value for buggy APs */
	if (!elems->tim || bss->dtim_period == 0)
		bss->dtim_period = 1;

	bss->supp_rates_len = 0;
	if (elems->supp_rates) {
		clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
		if (clen > elems->supp_rates_len)
			clen = elems->supp_rates_len;
		memcpy(&bss->supp_rates[bss->supp_rates_len], elems->supp_rates,
		       clen);
		bss->supp_rates_len += clen;
	}
	if (elems->ext_supp_rates) {
		clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
		if (clen > elems->ext_supp_rates_len)
			clen = elems->ext_supp_rates_len;
		memcpy(&bss->supp_rates[bss->supp_rates_len],
		       elems->ext_supp_rates, clen);
		bss->supp_rates_len += clen;
	}

	bss->wmm_used = elems->wmm_param || elems->wmm_info;

	if (!beacon)
		bss->last_probe_resp = jiffies;

	return bss;
}
122

123 124 125 126 127 128 129 130
void ieee80211_rx_bss_remove(struct ieee80211_sub_if_data *sdata, u8 *bssid,
			     int freq, u8 *ssid, u8 ssid_len)
{
	struct ieee80211_bss *bss;
	struct ieee80211_local *local = sdata->local;

	bss = ieee80211_rx_bss_get(local, bssid, freq, ssid, ssid_len);
	if (bss) {
131
		cfg80211_unlink_bss(local->hw.wiphy, (void *)bss);
132 133 134 135
		ieee80211_rx_bss_put(local, bss);
	}
}

136
ieee80211_rx_result
137 138
ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
		  struct ieee80211_rx_status *rx_status)
139 140
{
	struct ieee80211_mgmt *mgmt;
141
	struct ieee80211_bss *bss;
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
	u8 *elements;
	struct ieee80211_channel *channel;
	size_t baselen;
	int freq;
	__le16 fc;
	bool presp, beacon = false;
	struct ieee802_11_elems elems;

	if (skb->len < 2)
		return RX_DROP_UNUSABLE;

	mgmt = (struct ieee80211_mgmt *) skb->data;
	fc = mgmt->frame_control;

	if (ieee80211_is_ctl(fc))
		return RX_CONTINUE;

	if (skb->len < 24)
		return RX_DROP_MONITOR;

	presp = ieee80211_is_probe_resp(fc);
	if (presp) {
		/* ignore ProbeResp to foreign address */
		if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN))
			return RX_DROP_MONITOR;

		presp = true;
		elements = mgmt->u.probe_resp.variable;
		baselen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
	} else {
		beacon = ieee80211_is_beacon(fc);
		baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable);
		elements = mgmt->u.beacon.variable;
	}

	if (!presp && !beacon)
		return RX_CONTINUE;

	if (baselen > skb->len)
		return RX_DROP_MONITOR;

	ieee802_11_parse_elems(elements, skb->len - baselen, &elems);

	if (elems.ds_params && elems.ds_params_len == 1)
		freq = ieee80211_channel_to_frequency(elems.ds_params[0]);
	else
		freq = rx_status->freq;

	channel = ieee80211_get_channel(sdata->local->hw.wiphy, freq);

	if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
		return RX_DROP_MONITOR;

	bss = ieee80211_bss_info_update(sdata->local, rx_status,
					mgmt, skb->len, &elems,
197
					channel, beacon);
198 199
	if (bss)
		ieee80211_rx_bss_put(sdata->local, bss);
200 201 202 203 204

	dev_kfree_skb(skb);
	return RX_QUEUED;
}

205
void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
206 207 208 209
{
	struct ieee80211_local *local = hw_to_local(hw);
	struct ieee80211_sub_if_data *sdata;

210
	if (WARN_ON(!local->hw_scanning && !local->sw_scanning))
211 212
		return;

213 214
	if (WARN_ON(!local->scan_req))
		return;
215

216 217 218 219 220
	if (local->scan_req != &local->int_scan_req)
		cfg80211_scan_done(local->scan_req, aborted);
	local->scan_req = NULL;

	local->last_scan_completed = jiffies;
221

222 223
	if (local->hw_scanning) {
		local->hw_scanning = false;
224 225 226 227 228 229
		/*
		 * Somebody might have requested channel change during scan
		 * that we won't have acted upon, try now. ieee80211_hw_config
		 * will set the flag based on actual changes.
		 */
		ieee80211_hw_config(local, 0);
230 231 232
		goto done;
	}

233
	local->sw_scanning = false;
234
	ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
235 236 237 238 239 240 241 242 243 244 245 246 247

	netif_tx_lock_bh(local->mdev);
	netif_addr_lock(local->mdev);
	local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC;
	local->ops->configure_filter(local_to_hw(local),
				     FIF_BCN_PRBRESP_PROMISC,
				     &local->filter_flags,
				     local->mdev->mc_count,
				     local->mdev->mc_list);

	netif_addr_unlock(local->mdev);
	netif_tx_unlock_bh(local->mdev);

248 249 250
	if (local->ops->sw_scan_complete)
		local->ops->sw_scan_complete(local_to_hw(local));

251 252
	mutex_lock(&local->iflist_mtx);
	list_for_each_entry(sdata, &local->interfaces, list) {
253 254 255
		if (!netif_running(sdata->dev))
			continue;

256
		/* Tell AP we're back */
257
		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
258
			if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) {
259 260 261 262 263
				ieee80211_send_nullfunc(local, sdata, 0);
				netif_tx_wake_all_queues(sdata->dev);
			}
		} else
			netif_tx_wake_all_queues(sdata->dev);
264

J
Johannes Berg 已提交
265 266 267 268 269 270
		/* re-enable beaconing */
		if (sdata->vif.type == NL80211_IFTYPE_AP ||
		    sdata->vif.type == NL80211_IFTYPE_ADHOC ||
		    sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
			ieee80211_if_config(sdata,
					    IEEE80211_IFCC_BEACON_ENABLED);
271
	}
272
	mutex_unlock(&local->iflist_mtx);
273 274 275

 done:
	ieee80211_mlme_notify_scan_completed(local);
276
	ieee80211_ibss_notify_scan_completed(local);
277
	ieee80211_mesh_notify_scan_completed(local);
278 279 280
}
EXPORT_SYMBOL(ieee80211_scan_completed);

281
void ieee80211_scan_work(struct work_struct *work)
282 283 284 285 286
{
	struct ieee80211_local *local =
		container_of(work, struct ieee80211_local, scan_work.work);
	struct ieee80211_sub_if_data *sdata = local->scan_sdata;
	struct ieee80211_channel *chan;
287
	int skip, i;
288 289
	unsigned long next_delay = 0;

290 291 292 293
	/*
	 * Avoid re-scheduling when the sdata is going away.
	 */
	if (!netif_running(sdata->dev))
294 295 296 297 298
		return;

	switch (local->scan_state) {
	case SCAN_SET_CHANNEL:
		/* if no more bands/channels left, complete scan */
299 300
		if (local->scan_channel_idx >= local->scan_req->n_channels) {
			ieee80211_scan_completed(local_to_hw(local), false);
301 302 303
			return;
		}
		skip = 0;
304
		chan = local->scan_req->channels[local->scan_channel_idx];
305 306

		if (chan->flags & IEEE80211_CHAN_DISABLED ||
307
		    (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
308 309 310 311 312
		     chan->flags & IEEE80211_CHAN_NO_IBSS))
			skip = 1;

		if (!skip) {
			local->scan_channel = chan;
313 314
			if (ieee80211_hw_config(local,
						IEEE80211_CONF_CHANGE_CHANNEL))
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
				skip = 1;
		}

		/* advance state machine to next channel/band */
		local->scan_channel_idx++;

		if (skip)
			break;

		next_delay = IEEE80211_PROBE_DELAY +
			     usecs_to_jiffies(local->hw.channel_change_time);
		local->scan_state = SCAN_SEND_PROBE;
		break;
	case SCAN_SEND_PROBE:
		next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
		local->scan_state = SCAN_SET_CHANNEL;

332 333
		if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
		    !local->scan_req->n_ssids)
334
			break;
335 336 337 338
		for (i = 0; i < local->scan_req->n_ssids; i++)
			ieee80211_send_probe_req(
				sdata, NULL,
				local->scan_req->ssids[i].ssid,
339 340
				local->scan_req->ssids[i].ssid_len,
				local->scan_req->ie, local->scan_req->ie_len);
341 342 343 344
		next_delay = IEEE80211_CHANNEL_TIME;
		break;
	}

345 346
	queue_delayed_work(local->hw.workqueue, &local->scan_work,
			   next_delay);
347 348 349
}


350
int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
351
			 struct cfg80211_scan_request *req)
352 353 354 355
{
	struct ieee80211_local *local = scan_sdata->local;
	struct ieee80211_sub_if_data *sdata;

356
	if (!req)
357 358
		return -EINVAL;

359 360 361 362 363
	if (local->scan_req && local->scan_req != req)
		return -EBUSY;

	local->scan_req = req;

364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380
	/* MLME-SCAN.request (page 118)  page 144 (11.1.3.1)
	 * BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS
	 * BSSID: MACAddress
	 * SSID
	 * ScanType: ACTIVE, PASSIVE
	 * ProbeDelay: delay (in microseconds) to be used prior to transmitting
	 *    a Probe frame during active scanning
	 * ChannelList
	 * MinChannelTime (>= ProbeDelay), in TU
	 * MaxChannelTime: (>= MinChannelTime), in TU
	 */

	 /* MLME-SCAN.confirm
	  * BSSDescriptionSet
	  * ResultCode: SUCCESS, INVALID_PARAMETERS
	 */

381
	if (local->sw_scanning || local->hw_scanning) {
382 383 384 385 386 387
		if (local->scan_sdata == scan_sdata)
			return 0;
		return -EBUSY;
	}

	if (local->ops->hw_scan) {
388 389
		int rc;

390
		local->hw_scanning = true;
391
		rc = local->ops->hw_scan(local_to_hw(local), req);
392
		if (rc) {
393
			local->hw_scanning = false;
394
			return rc;
395
		}
396 397
		local->scan_sdata = scan_sdata;
		return 0;
398 399
	}

400
	local->sw_scanning = true;
401 402
	if (local->ops->sw_scan_start)
		local->ops->sw_scan_start(local_to_hw(local));
403

404 405
	mutex_lock(&local->iflist_mtx);
	list_for_each_entry(sdata, &local->interfaces, list) {
406 407 408
		if (!netif_running(sdata->dev))
			continue;

J
Johannes Berg 已提交
409 410 411 412 413 414
		/* disable beaconing */
		if (sdata->vif.type == NL80211_IFTYPE_AP ||
		    sdata->vif.type == NL80211_IFTYPE_ADHOC ||
		    sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
			ieee80211_if_config(sdata,
					    IEEE80211_IFCC_BEACON_ENABLED);
415

416
		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
417
			if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) {
418 419 420 421 422 423
				netif_tx_stop_all_queues(sdata->dev);
				ieee80211_send_nullfunc(local, sdata, 1);
			}
		} else
			netif_tx_stop_all_queues(sdata->dev);
	}
424
	mutex_unlock(&local->iflist_mtx);
425 426 427 428

	local->scan_state = SCAN_SET_CHANNEL;
	local->scan_channel_idx = 0;
	local->scan_sdata = scan_sdata;
429
	local->scan_req = req;
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447

	netif_addr_lock_bh(local->mdev);
	local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
	local->ops->configure_filter(local_to_hw(local),
				     FIF_BCN_PRBRESP_PROMISC,
				     &local->filter_flags,
				     local->mdev->mc_count,
				     local->mdev->mc_list);
	netif_addr_unlock_bh(local->mdev);

	/* TODO: start scan as soon as all nullfunc frames are ACKed */
	queue_delayed_work(local->hw.workqueue, &local->scan_work,
			   IEEE80211_CHANNEL_TIME);

	return 0;
}


448
int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
449
			   struct cfg80211_scan_request *req)
450 451
{
	struct ieee80211_local *local = sdata->local;
452
	struct ieee80211_if_managed *ifmgd;
453

454 455 456 457 458 459 460 461
	if (!req)
		return -EINVAL;

	if (local->scan_req && local->scan_req != req)
		return -EBUSY;

	local->scan_req = req;

462
	if (sdata->vif.type != NL80211_IFTYPE_STATION)
463
		return ieee80211_start_scan(sdata, req);
464

J
Johannes Berg 已提交
465 466 467 468 469 470
	/*
	 * STA has a state machine that might need to defer scanning
	 * while it's trying to associate/authenticate, therefore we
	 * queue it up to the state machine in that case.
	 */

471
	if (local->sw_scanning || local->hw_scanning) {
472 473 474 475 476
		if (local->scan_sdata == sdata)
			return 0;
		return -EBUSY;
	}

477 478 479
	ifmgd = &sdata->u.mgd;
	set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request);
	queue_work(local->hw.workqueue, &ifmgd->work);
J
Johannes Berg 已提交
480

481 482
	return 0;
}