iwl-scan.c 16.9 KB
Newer Older
1 2 3 4
/******************************************************************************
 *
 * GPL LICENSE SUMMARY
 *
5
 * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved.
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
 * USA
 *
 * The full GNU General Public License is included in this distribution
 * in the file called LICENSE.GPL.
 *
 * Contact Information:
25
 *  Intel Linux Wireless <ilw@linux.intel.com>
26 27
 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
 *****************************************************************************/
28
#include <linux/slab.h>
29
#include <linux/types.h>
30
#include <linux/etherdevice.h>
31
#include <net/mac80211.h>
32 33 34 35 36 37 38 39 40 41 42

#include "iwl-eeprom.h"
#include "iwl-dev.h"
#include "iwl-core.h"
#include "iwl-sta.h"
#include "iwl-io.h"
#include "iwl-helpers.h"

/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
 * sending probe req.  This should be set long enough to hear probe responses
 * from more than one AP.  */
T
Tomas Winkler 已提交
43 44 45 46 47
#define IWL_ACTIVE_DWELL_TIME_24    (30)       /* all times in msec */
#define IWL_ACTIVE_DWELL_TIME_52    (20)

#define IWL_ACTIVE_DWELL_FACTOR_24GHZ (3)
#define IWL_ACTIVE_DWELL_FACTOR_52GHZ (2)
48 49 50 51 52 53 54 55 56

/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel.
 * Must be set longer than active dwell time.
 * For the most reliable scan, set > AP beacon interval (typically 100msec). */
#define IWL_PASSIVE_DWELL_TIME_24   (20)       /* all times in msec */
#define IWL_PASSIVE_DWELL_TIME_52   (10)
#define IWL_PASSIVE_DWELL_BASE      (100)
#define IWL_CHANNEL_TUNE_TIME       5

57 58 59 60 61 62 63 64
static int iwl_send_scan_abort(struct iwl_priv *priv)
{
	int ret;
	struct iwl_rx_packet *pkt;
	struct iwl_host_cmd cmd = {
		.id = REPLY_SCAN_ABORT_CMD,
		.flags = CMD_WANT_SKB,
	};
T
Tomas Winkler 已提交
65

66 67 68 69 70 71 72 73 74
	/* Exit instantly with error when device is not ready
	 * to receive scan abort command or it does not perform
	 * hardware scan currently */
	if (!test_bit(STATUS_READY, &priv->status) ||
	    !test_bit(STATUS_GEO_CONFIGURED, &priv->status) ||
	    !test_bit(STATUS_SCAN_HW, &priv->status) ||
	    test_bit(STATUS_FW_ERROR, &priv->status) ||
	    test_bit(STATUS_EXIT_PENDING, &priv->status))
		return -EIO;
T
Tomas Winkler 已提交
75

76 77 78 79 80 81 82 83 84 85 86 87 88 89
	ret = iwl_send_cmd_sync(priv, &cmd);
	if (ret)
		return ret;

	pkt = (struct iwl_rx_packet *)cmd.reply_page;
	if (pkt->u.status != CAN_ABORT_STATUS) {
		/* The scan abort will return 1 for success or
		 * 2 for "failure".  A failure condition can be
		 * due to simply not being in an active scan which
		 * can occur if we send the scan abort before we
		 * the microcode has notified us that a scan is
		 * completed. */
		IWL_DEBUG_INFO(priv, "SCAN_ABORT ret %d.\n", pkt->u.status);
		ret = -EIO;
90 91
	}

92 93 94
	iwl_free_pages(priv, cmd.reply_page);
	return ret;
}
95

96 97 98
static void iwl_do_scan_abort(struct iwl_priv *priv)
{
	int ret;
99

100 101 102 103 104
	lockdep_assert_held(&priv->mutex);

	if (!test_bit(STATUS_SCANNING, &priv->status)) {
		IWL_DEBUG_SCAN(priv, "Not performing scan to abort\n");
		return;
105 106
	}

107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
	if (test_and_set_bit(STATUS_SCAN_ABORTING, &priv->status)) {
		IWL_DEBUG_SCAN(priv, "Scan abort in progress\n");
		return;
	}

	ret = iwl_send_scan_abort(priv);
	if (ret) {
		IWL_DEBUG_SCAN(priv, "Send scan abort failed %d\n", ret);
		clear_bit(STATUS_SCANNING, &priv->status);
		clear_bit(STATUS_SCAN_HW, &priv->status);
		clear_bit(STATUS_SCAN_ABORTING, &priv->status);
		ieee80211_scan_completed(priv->hw, true);
	} else
		IWL_DEBUG_SCAN(priv, "Sucessfully send scan abort\n");
}

/**
 * iwl_scan_cancel - Cancel any currently executing HW scan
 */
int iwl_scan_cancel(struct iwl_priv *priv)
{
	IWL_DEBUG_SCAN(priv, "Queuing abort scan\n");
129
	queue_work(priv->workqueue, &priv->abort_scan);
130 131 132
	return 0;
}
EXPORT_SYMBOL(iwl_scan_cancel);
133

134 135 136 137 138 139 140
/**
 * iwl_scan_cancel_timeout - Cancel any currently executing HW scan
 * @ms: amount of time to wait (in milliseconds) for scan to abort
 *
 */
int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
{
141 142 143
	unsigned long timeout = jiffies + msecs_to_jiffies(ms);

	lockdep_assert_held(&priv->mutex);
144

145
	IWL_DEBUG_SCAN(priv, "Scan cancel timeout\n");
146

147 148 149 150 151 152
	iwl_do_scan_abort(priv);

	while (time_before_eq(jiffies, timeout)) {
		if (!test_bit(STATUS_SCAN_HW, &priv->status))
			break;
		msleep(20);
153 154
	}

155
	return test_bit(STATUS_SCAN_HW, &priv->status);
156 157 158 159 160 161 162 163
}
EXPORT_SYMBOL(iwl_scan_cancel_timeout);

/* Service response to REPLY_SCAN_CMD (0x80) */
static void iwl_rx_reply_scan(struct iwl_priv *priv,
			      struct iwl_rx_mem_buffer *rxb)
{
#ifdef CONFIG_IWLWIFI_DEBUG
Z
Zhu Yi 已提交
164
	struct iwl_rx_packet *pkt = rxb_addr(rxb);
165 166 167
	struct iwl_scanreq_notification *notif =
	    (struct iwl_scanreq_notification *)pkt->u.raw;

168
	IWL_DEBUG_RX(priv, "Scan request status = 0x%x\n", notif->status);
169 170 171 172 173 174 175
#endif
}

/* Service SCAN_START_NOTIFICATION (0x82) */
static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
				    struct iwl_rx_mem_buffer *rxb)
{
Z
Zhu Yi 已提交
176
	struct iwl_rx_packet *pkt = rxb_addr(rxb);
177 178 179
	struct iwl_scanstart_notification *notif =
	    (struct iwl_scanstart_notification *)pkt->u.raw;
	priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
180
	IWL_DEBUG_SCAN(priv, "Scan start: "
181 182 183 184
		       "%d [802.11%s] "
		       "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n",
		       notif->channel,
		       notif->band ? "bg" : "a",
T
Tomas Winkler 已提交
185 186 187
		       le32_to_cpu(notif->tsf_high),
		       le32_to_cpu(notif->tsf_low),
		       notif->status, notif->beacon_timer);
188 189 190 191 192 193 194
}

/* Service SCAN_RESULTS_NOTIFICATION (0x83) */
static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
				      struct iwl_rx_mem_buffer *rxb)
{
#ifdef CONFIG_IWLWIFI_DEBUG
Z
Zhu Yi 已提交
195
	struct iwl_rx_packet *pkt = rxb_addr(rxb);
196 197 198
	struct iwl_scanresults_notification *notif =
	    (struct iwl_scanresults_notification *)pkt->u.raw;

199
	IWL_DEBUG_SCAN(priv, "Scan ch.res: "
200 201
		       "%d [802.11%s] "
		       "(TSF: 0x%08X:%08X) - %d "
202
		       "elapsed=%lu usec\n",
203 204 205 206 207
		       notif->channel,
		       notif->band ? "bg" : "a",
		       le32_to_cpu(notif->tsf_high),
		       le32_to_cpu(notif->tsf_low),
		       le32_to_cpu(notif->statistics[0]),
208
		       le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf);
209 210 211 212 213 214 215
#endif
}

/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
				       struct iwl_rx_mem_buffer *rxb)
{
Z
Zhu Yi 已提交
216
	struct iwl_rx_packet *pkt = rxb_addr(rxb);
217 218
	struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw;

219
	IWL_DEBUG_SCAN(priv, "Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
220 221 222 223 224 225 226
		       scan_notif->scanned_channels,
		       scan_notif->tsf_low,
		       scan_notif->tsf_high, scan_notif->status);

	/* The HW is no longer scanning */
	clear_bit(STATUS_SCAN_HW, &priv->status);

J
Johannes Berg 已提交
227
	IWL_DEBUG_INFO(priv, "Scan on %sGHz took %dms\n",
J
Johannes Berg 已提交
228
		       (priv->scan_band == IEEE80211_BAND_2GHZ) ? "2.4" : "5.2",
229
		       jiffies_to_msecs(elapsed_jiffies
J
Johannes Berg 已提交
230
					(priv->scan_start, jiffies)));
231

232
	queue_work(priv->workqueue, &priv->scan_completed);
233

234
	if (priv->iw_mode != NL80211_IFTYPE_ADHOC &&
235 236
	    priv->cfg->advanced_bt_coexist &&
	    priv->bt_status != scan_notif->bt_status) {
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
		if (scan_notif->bt_status) {
			/* BT on */
			if (!priv->bt_ch_announce)
				priv->bt_traffic_load =
					IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
			/*
			 * otherwise, no traffic load information provided
			 * no changes made
			 */
		} else {
			/* BT off */
			priv->bt_traffic_load =
				IWL_BT_COEX_TRAFFIC_LOAD_NONE;
		}
		priv->bt_status = scan_notif->bt_status;
		queue_work(priv->workqueue, &priv->bt_traffic_change_work);
	}
254 255 256 257 258 259 260 261 262 263 264 265 266 267
}

void iwl_setup_rx_scan_handlers(struct iwl_priv *priv)
{
	/* scan handlers */
	priv->rx_handlers[REPLY_SCAN_CMD] = iwl_rx_reply_scan;
	priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl_rx_scan_start_notif;
	priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] =
					iwl_rx_scan_results_notif;
	priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] =
					iwl_rx_scan_complete_notif;
}
EXPORT_SYMBOL(iwl_setup_rx_scan_handlers);

S
Samuel Ortiz 已提交
268 269 270
inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
				     enum ieee80211_band band,
				     u8 n_probes)
271 272
{
	if (band == IEEE80211_BAND_5GHZ)
T
Tomas Winkler 已提交
273 274
		return IWL_ACTIVE_DWELL_TIME_52 +
			IWL_ACTIVE_DWELL_FACTOR_52GHZ * (n_probes + 1);
275
	else
T
Tomas Winkler 已提交
276 277
		return IWL_ACTIVE_DWELL_TIME_24 +
			IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1);
278
}
S
Samuel Ortiz 已提交
279
EXPORT_SYMBOL(iwl_get_active_dwell_time);
280

S
Samuel Ortiz 已提交
281
u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
282 283
			       enum ieee80211_band band,
			       struct ieee80211_vif *vif)
284
{
285
	struct iwl_rxon_context *ctx;
T
Tomas Winkler 已提交
286
	u16 passive = (band == IEEE80211_BAND_2GHZ) ?
287 288 289
	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
	    IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;

290
	if (iwl_is_any_associated(priv)) {
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
		/*
		 * If we're associated, we clamp the maximum passive
		 * dwell time to be 98% of the smallest beacon interval
		 * (minus 2 * channel tune time)
		 */
		for_each_context(priv, ctx) {
			u16 value;

			if (!iwl_is_associated_ctx(ctx))
				continue;
			value = ctx->vif ? ctx->vif->bss_conf.beacon_int : 0;
			if ((value > IWL_PASSIVE_DWELL_BASE) || !value)
				value = IWL_PASSIVE_DWELL_BASE;
			value = (value * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
			passive = min(value, passive);
		}
307 308 309 310
	}

	return passive;
}
S
Samuel Ortiz 已提交
311
EXPORT_SYMBOL(iwl_get_passive_dwell_time);
312

T
Tomas Winkler 已提交
313 314
void iwl_init_scan_params(struct iwl_priv *priv)
{
T
Tomas Winkler 已提交
315
	u8 ant_idx = fls(priv->hw_params.valid_tx_ant) - 1;
T
Tomas Winkler 已提交
316
	if (!priv->scan_tx_ant[IEEE80211_BAND_5GHZ])
T
Tomas Winkler 已提交
317
		priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = ant_idx;
T
Tomas Winkler 已提交
318
	if (!priv->scan_tx_ant[IEEE80211_BAND_2GHZ])
T
Tomas Winkler 已提交
319
		priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx;
T
Tomas Winkler 已提交
320
}
321
EXPORT_SYMBOL(iwl_init_scan_params);
T
Tomas Winkler 已提交
322

J
Johannes Berg 已提交
323 324 325 326
static int __must_check iwl_scan_initiate(struct iwl_priv *priv,
					  struct ieee80211_vif *vif,
					  bool internal,
					  enum nl80211_band band)
327
{
J
Johannes Berg 已提交
328 329
	int ret;

J
Johannes Berg 已提交
330
	lockdep_assert_held(&priv->mutex);
J
Johannes Berg 已提交
331

J
Johannes Berg 已提交
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
	if (WARN_ON(!priv->cfg->ops->utils->request_scan))
		return -EOPNOTSUPP;

	cancel_delayed_work(&priv->scan_check);

	if (!iwl_is_ready(priv)) {
		IWL_WARN(priv, "request scan called when driver not ready.\n");
		return -EIO;
	}

	if (test_bit(STATUS_SCAN_HW, &priv->status)) {
		IWL_DEBUG_INFO(priv,
			"Multiple concurrent scan requests in parallel.\n");
		return -EBUSY;
	}

	if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
		IWL_DEBUG_SCAN(priv, "Aborting scan due to device shutdown\n");
		return -EIO;
	}

	if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
		IWL_DEBUG_HC(priv, "Scan request while abort pending.\n");
		return -EBUSY;
	}

	if (iwl_is_rfkill(priv)) {
		IWL_DEBUG_HC(priv, "Aborting scan due to RF Kill activation\n");
		return -EIO;
	}

	if (!test_bit(STATUS_READY, &priv->status)) {
		IWL_DEBUG_HC(priv, "Scan request while uninitialized.\n");
		return -EBUSY;
	}

	IWL_DEBUG_INFO(priv, "Starting %sscan...\n",
			internal ? "internal short " : "");

371
	set_bit(STATUS_SCANNING, &priv->status);
J
Johannes Berg 已提交
372
	priv->is_internal_short_scan = internal;
373
	priv->scan_start = jiffies;
J
Johannes Berg 已提交
374
	priv->scan_band = band;
375

J
Johannes Berg 已提交
376 377 378 379 380 381
	ret = priv->cfg->ops->utils->request_scan(priv, vif);
	if (ret) {
		clear_bit(STATUS_SCANNING, &priv->status);
		priv->is_internal_short_scan = false;
		return ret;
	}
382

J
Johannes Berg 已提交
383 384
	queue_delayed_work(priv->workqueue, &priv->scan_check,
			   IWL_SCAN_CHECK_WATCHDOG);
385 386 387 388

	return 0;
}

389
int iwl_mac_hw_scan(struct ieee80211_hw *hw,
390 391
		    struct ieee80211_vif *vif,
		    struct cfg80211_scan_request *req)
392 393
{
	struct iwl_priv *priv = hw->priv;
J
Johannes Berg 已提交
394
	int ret;
395 396 397

	IWL_DEBUG_MAC80211(priv, "enter\n");

J
Johannes Berg 已提交
398 399 400
	if (req->n_channels == 0)
		return -EINVAL;

401 402
	mutex_lock(&priv->mutex);

403 404
	if (test_bit(STATUS_SCANNING, &priv->status) &&
	    !priv->is_internal_short_scan) {
R
Reinette Chatre 已提交
405 406 407 408 409
		IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
		ret = -EAGAIN;
		goto out_unlock;
	}

J
Johannes Berg 已提交
410
	/* mac80211 will only ask for one band at a time */
J
Johannes Berg 已提交
411
	priv->scan_request = req;
412
	priv->scan_vif = vif;
413

414 415 416 417 418 419 420
	/*
	 * If an internal scan is in progress, just set
	 * up the scan_request as per above.
	 */
	if (priv->is_internal_short_scan)
		ret = 0;
	else
J
Johannes Berg 已提交
421 422
		ret = iwl_scan_initiate(priv, vif, false,
					req->channels[0]->band);
423 424 425 426 427 428 429 430 431 432

	IWL_DEBUG_MAC80211(priv, "leave\n");

out_unlock:
	mutex_unlock(&priv->mutex);

	return ret;
}
EXPORT_SYMBOL(iwl_mac_hw_scan);

433 434 435 436
/*
 * internal short scan, this function should only been called while associated.
 * It will reset and tune the radio to prevent possible RF related problem
 */
J
Johannes Berg 已提交
437
void iwl_internal_short_hw_scan(struct iwl_priv *priv)
438
{
J
Johannes Berg 已提交
439 440 441
	queue_work(priv->workqueue, &priv->start_internal_scan);
}

442
static void iwl_bg_start_internal_scan(struct work_struct *work)
J
Johannes Berg 已提交
443 444 445 446 447
{
	struct iwl_priv *priv =
		container_of(work, struct iwl_priv, start_internal_scan);

	mutex_lock(&priv->mutex);
448

449 450 451 452 453
	if (priv->is_internal_short_scan == true) {
		IWL_DEBUG_SCAN(priv, "Internal scan already in progress\n");
		goto unlock;
	}

454 455
	if (test_bit(STATUS_SCANNING, &priv->status)) {
		IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
J
Johannes Berg 已提交
456
		goto unlock;
457
	}
J
Johannes Berg 已提交
458

J
Johannes Berg 已提交
459 460
	if (iwl_scan_initiate(priv, NULL, true, priv->band))
		IWL_DEBUG_SCAN(priv, "failed to start internal short scan\n");
J
Johannes Berg 已提交
461 462
 unlock:
	mutex_unlock(&priv->mutex);
463 464
}

465
static void iwl_bg_scan_check(struct work_struct *data)
466 467 468 469 470 471 472 473
{
	struct iwl_priv *priv =
	    container_of(data, struct iwl_priv, scan_check.work);

	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
		return;

	mutex_lock(&priv->mutex);
S
Stanislaw Gruszka 已提交
474 475 476 477
	if (test_bit(STATUS_SCANNING, &priv->status) &&
	    !test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
		IWL_DEBUG_SCAN(priv, "Scan completion watchdog (%dms)\n",
			       jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG));
478 479 480 481 482 483

		if (!test_bit(STATUS_EXIT_PENDING, &priv->status))
			iwl_send_scan_abort(priv);
	}
	mutex_unlock(&priv->mutex);
}
S
Samuel Ortiz 已提交
484

485 486 487
/**
 * iwl_fill_probe_req - fill in all required fields and IE for probe request
 */
T
Tomas Winkler 已提交
488

J
Johannes Berg 已提交
489
u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
490
		       const u8 *ta, const u8 *ies, int ie_len, int left)
491 492 493
{
	int len = 0;
	u8 *pos = NULL;
T
Tomas Winkler 已提交
494

495 496 497 498 499 500 501 502
	/* Make sure there is enough space for the probe request,
	 * two mandatory IEs and the data */
	left -= 24;
	if (left < 0)
		return 0;

	frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
	memcpy(frame->da, iwl_bcast_addr, ETH_ALEN);
503
	memcpy(frame->sa, ta, ETH_ALEN);
504 505 506
	memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN);
	frame->seq_ctrl = 0;

T
Tomas Winkler 已提交
507 508
	len += 24;

509
	/* ...next IE... */
T
Tomas Winkler 已提交
510
	pos = &frame->u.probe_req.variable[0];
511

T
Tomas Winkler 已提交
512
	/* fill in our indirect SSID IE */
513 514 515 516
	left -= 2;
	if (left < 0)
		return 0;
	*pos++ = WLAN_EID_SSID;
517 518 519
	*pos++ = 0;

	len += 2;
520

J
Johannes Berg 已提交
521 522
	if (WARN_ON(left < ie_len))
		return len;
523

524
	if (ies && ie_len) {
525
		memcpy(pos, ies, ie_len);
526 527
		len += ie_len;
	}
T
Tomas Winkler 已提交
528

529 530
	return (u16)len;
}
S
Samuel Ortiz 已提交
531
EXPORT_SYMBOL(iwl_fill_probe_req);
532

533
static void iwl_bg_abort_scan(struct work_struct *work)
534 535 536
{
	struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan);

S
Stanislaw Gruszka 已提交
537
	cancel_delayed_work(&priv->scan_check);
538

S
Stanislaw Gruszka 已提交
539
	mutex_lock(&priv->mutex);
540
	iwl_do_scan_abort(priv);
541 542 543
	mutex_unlock(&priv->mutex);
}

544
static void iwl_bg_scan_completed(struct work_struct *work)
545 546 547
{
	struct iwl_priv *priv =
	    container_of(work, struct iwl_priv, scan_completed);
548
	bool internal = false, aborted;
549
	struct iwl_rxon_context *ctx;
550

551
	IWL_DEBUG_SCAN(priv, "SCAN complete scan\n");
552

553 554
	cancel_delayed_work(&priv->scan_check);

555
	mutex_lock(&priv->mutex);
556 557 558 559 560 561 562 563 564

	aborted = test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->status);
	if (aborted)
		IWL_DEBUG_INFO(priv, "Aborted scan completed.\n");

	IWL_DEBUG_INFO(priv, "Setting scan to off\n");

	clear_bit(STATUS_SCANNING, &priv->status);

565
	if (priv->is_internal_short_scan) {
566 567
		priv->is_internal_short_scan = false;
		IWL_DEBUG_SCAN(priv, "internal short scan completed\n");
568
		internal = true;
569
	} else if (priv->scan_request) {
570 571
		priv->scan_request = NULL;
		priv->scan_vif = NULL;
572
		ieee80211_scan_completed(priv->hw, aborted);
573
	}
574 575 576 577

	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
		goto out;

J
Johannes Berg 已提交
578 579 580 581 582 583 584 585 586 587 588 589 590
	if (internal && priv->scan_request) {
		int err = iwl_scan_initiate(priv, priv->scan_vif, false,
					priv->scan_request->channels[0]->band);

		if (err) {
			IWL_DEBUG_SCAN(priv,
				"failed to initiate pending scan: %d\n", err);
			priv->scan_request = NULL;
			priv->scan_vif = NULL;
			ieee80211_scan_completed(priv->hw, true);
		} else
			goto out;
	}
591 592 593 594

	/* Since setting the TXPOWER may have been deferred while
	 * performing the scan, fire one off */
	iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
595 596 597 598 599

	/*
	 * Since setting the RXON may have been deferred while
	 * performing the scan, fire one off if needed
	 */
600 601
	for_each_context(priv, ctx)
		iwlcore_commit_rxon(priv, ctx);
602

J
Johannes Berg 已提交
603 604 605
	if (priv->cfg->ops->hcmd->set_pan_params)
		priv->cfg->ops->hcmd->set_pan_params(priv);

J
Johannes Berg 已提交
606
 out:
607
	mutex_unlock(&priv->mutex);
608 609
}

610 611
void iwl_setup_scan_deferred_work(struct iwl_priv *priv)
{
612
	INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed);
613
	INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan);
J
Johannes Berg 已提交
614
	INIT_WORK(&priv->start_internal_scan, iwl_bg_start_internal_scan);
615 616 617 618
	INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check);
}
EXPORT_SYMBOL(iwl_setup_scan_deferred_work);