scan.c 12.3 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;

Johannes Berg's avatar
Johannes Berg committed
68
	if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
69
		signal = rx_status->signal * 100;
Johannes Berg's avatar
Johannes Berg committed
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,
Johannes Berg's avatar
Johannes Berg committed
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
	mutex_lock(&local->iflist_mtx);
	list_for_each_entry(sdata, &local->interfaces, list) {
250
251
252
		if (!netif_running(sdata->dev))
			continue;

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

262
263
264
265
266
267
		/* 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);
268
	}
269
	mutex_unlock(&local->iflist_mtx);
270
271
272

 done:
	ieee80211_mlme_notify_scan_completed(local);
273
	ieee80211_ibss_notify_scan_completed(local);
274
	ieee80211_mesh_notify_scan_completed(local);
275
276
277
}
EXPORT_SYMBOL(ieee80211_scan_completed);

278
void ieee80211_scan_work(struct work_struct *work)
279
280
281
282
283
{
	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;
284
	int skip, i;
285
286
	unsigned long next_delay = 0;

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

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

		if (chan->flags & IEEE80211_CHAN_DISABLED ||
304
		    (sdata->vif.type == NL80211_IFTYPE_ADHOC &&
305
306
307
308
309
		     chan->flags & IEEE80211_CHAN_NO_IBSS))
			skip = 1;

		if (!skip) {
			local->scan_channel = chan;
310
311
			if (ieee80211_hw_config(local,
						IEEE80211_CONF_CHANGE_CHANNEL))
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
				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;

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

342
343
	queue_delayed_work(local->hw.workqueue, &local->scan_work,
			   next_delay);
344
345
346
}


347
int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
348
			 struct cfg80211_scan_request *req)
349
350
351
352
{
	struct ieee80211_local *local = scan_sdata->local;
	struct ieee80211_sub_if_data *sdata;

353
	if (!req)
354
355
		return -EINVAL;

356
357
358
359
360
	if (local->scan_req && local->scan_req != req)
		return -EBUSY;

	local->scan_req = req;

361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
	/* 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
	 */

378
	if (local->sw_scanning || local->hw_scanning) {
379
380
381
382
383
384
		if (local->scan_sdata == scan_sdata)
			return 0;
		return -EBUSY;
	}

	if (local->ops->hw_scan) {
385
386
		int rc;

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

397
	local->sw_scanning = true;
398

399
400
	mutex_lock(&local->iflist_mtx);
	list_for_each_entry(sdata, &local->interfaces, list) {
401
402
403
		if (!netif_running(sdata->dev))
			continue;

404
405
406
407
408
409
		/* 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);
410

411
		if (sdata->vif.type == NL80211_IFTYPE_STATION) {
412
			if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) {
413
414
415
416
417
418
				netif_tx_stop_all_queues(sdata->dev);
				ieee80211_send_nullfunc(local, sdata, 1);
			}
		} else
			netif_tx_stop_all_queues(sdata->dev);
	}
419
	mutex_unlock(&local->iflist_mtx);
420
421
422
423

	local->scan_state = SCAN_SET_CHANNEL;
	local->scan_channel_idx = 0;
	local->scan_sdata = scan_sdata;
424
	local->scan_req = req;
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442

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


443
int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
444
			   struct cfg80211_scan_request *req)
445
446
{
	struct ieee80211_local *local = sdata->local;
447
	struct ieee80211_if_managed *ifmgd;
448

449
450
451
452
453
454
455
456
	if (!req)
		return -EINVAL;

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

	local->scan_req = req;

457
	if (sdata->vif.type != NL80211_IFTYPE_STATION)
458
		return ieee80211_start_scan(sdata, req);
459

Johannes Berg's avatar
Johannes Berg committed
460
461
462
463
464
465
	/*
	 * 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.
	 */

466
	if (local->sw_scanning || local->hw_scanning) {
467
468
469
470
471
		if (local->scan_sdata == sdata)
			return 0;
		return -EBUSY;
	}

472
473
474
	ifmgd = &sdata->u.mgd;
	set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request);
	queue_work(local->hw.workqueue, &ifmgd->work);
Johannes Berg's avatar
Johannes Berg committed
475

476
477
	return 0;
}