iwl-scan.c revision 1b63ba8a86c85524a8d7e5953b314ce71ebcb9c9
12a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/****************************************************************************** 22a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * 32a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * GPL LICENSE SUMMARY 42a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * 52a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * Copyright(c) 2008 Intel Corporation. All rights reserved. 62a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * 72a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * This program is free software; you can redistribute it and/or modify 82a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * it under the terms of version 2 of the GNU General Public License as 92a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * published by the Free Software Foundation. 102a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * 112a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * This program is distributed in the hope that it will be useful, but 122a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * WITHOUT ANY WARRANTY; without even the implied warranty of 132a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 142a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * General Public License for more details. 152a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * 162a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * You should have received a copy of the GNU General Public License 172a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * along with this program; if not, write to the Free Software 182a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, 192a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * USA 202a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * 212a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * The full GNU General Public License is included in this distribution 222a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * in the file called LICENSE.GPL. 232a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * 242a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * Contact Information: 252a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * Tomas Winkler <tomas.winkler@intel.com> 262a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 272a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler *****************************************************************************/ 282a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#include <net/mac80211.h> 292a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#include <linux/etherdevice.h> 302a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 312a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#include "iwl-eeprom.h" 322a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#include "iwl-dev.h" 332a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#include "iwl-core.h" 342a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#include "iwl-sta.h" 352a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#include "iwl-io.h" 362a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#include "iwl-helpers.h" 372a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 382a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after 392a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * sending probe req. This should be set long enough to hear probe responses 402a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * from more than one AP. */ 412a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#define IWL_ACTIVE_DWELL_TIME_24 (20) /* all times in msec */ 422a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#define IWL_ACTIVE_DWELL_TIME_52 (10) 432a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 442a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/* For faster active scanning, scan will move to the next channel if fewer than 452a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * PLCP_QUIET_THRESH packets are heard on this channel within 462a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * ACTIVE_QUIET_TIME after sending probe request. This shortens the dwell 472a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * time if it's a quiet channel (nothing responded to our probe, and there's 482a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * no other traffic). 492a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * Disable "quiet" feature by setting PLCP_QUIET_THRESH to 0. */ 502a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#define IWL_PLCP_QUIET_THRESH __constant_cpu_to_le16(1) /* packets */ 512a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#define IWL_ACTIVE_QUIET_TIME __constant_cpu_to_le16(5) /* msec */ 522a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 532a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/* For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel. 542a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * Must be set longer than active dwell time. 552a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * For the most reliable scan, set > AP beacon interval (typically 100msec). */ 562a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#define IWL_PASSIVE_DWELL_TIME_24 (20) /* all times in msec */ 572a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#define IWL_PASSIVE_DWELL_TIME_52 (10) 582a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#define IWL_PASSIVE_DWELL_BASE (100) 592a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#define IWL_CHANNEL_TUNE_TIME 5 602a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 61f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winklerstatic int scan_tx_ant[3] = { 62f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler RATE_MCS_ANT_A_MSK, RATE_MCS_ANT_B_MSK, RATE_MCS_ANT_C_MSK 63f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler}; 642a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 652a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic int iwl_is_empty_essid(const char *essid, int essid_len) 662a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 672a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler /* Single white space is for Linksys APs */ 682a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (essid_len == 1 && essid[0] == ' ') 692a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return 1; 702a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 712a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler /* Otherwise, if the entire essid is 0, we assume it is hidden */ 722a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler while (essid_len) { 732a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler essid_len--; 742a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (essid[essid_len] != '\0') 752a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return 0; 762a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 772a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 782a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return 1; 792a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 802a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 812a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 822a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 832a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerconst char *iwl_escape_essid(const char *essid, u8 essid_len) 842a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 852a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; 862a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler const char *s = essid; 872a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler char *d = escaped; 882a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 892a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (iwl_is_empty_essid(essid, essid_len)) { 902a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler memcpy(escaped, "<hidden>", sizeof("<hidden>")); 912a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return escaped; 922a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 932a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 942a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE); 952a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler while (essid_len--) { 962a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (*s == '\0') { 972a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler *d++ = '\\'; 982a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler *d++ = '0'; 992a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler s++; 1002a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } else 1012a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler *d++ = *s++; 1022a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 1032a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler *d = '\0'; 1042a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return escaped; 1052a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 1062a421b91d6fe89e27ded7544a25449c0b050098fTomas WinklerEXPORT_SYMBOL(iwl_escape_essid); 1072a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 1082a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/** 1092a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * iwl_scan_cancel - Cancel any currently executing HW scan 1102a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * 1112a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * NOTE: priv->mutex is not required before calling this function 1122a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler */ 1132a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerint iwl_scan_cancel(struct iwl_priv *priv) 1142a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 1152a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (!test_bit(STATUS_SCAN_HW, &priv->status)) { 1162a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler clear_bit(STATUS_SCANNING, &priv->status); 1172a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return 0; 1182a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 1192a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 1202a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (test_bit(STATUS_SCANNING, &priv->status)) { 1212a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (!test_bit(STATUS_SCAN_ABORTING, &priv->status)) { 1222a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_DEBUG_SCAN("Queuing scan abort.\n"); 1232a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler set_bit(STATUS_SCAN_ABORTING, &priv->status); 1242a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler queue_work(priv->workqueue, &priv->abort_scan); 1252a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 1262a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } else 1272a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_DEBUG_SCAN("Scan abort already in progress.\n"); 1282a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 1292a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return test_bit(STATUS_SCANNING, &priv->status); 1302a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 1312a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 1322a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return 0; 1332a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 1342a421b91d6fe89e27ded7544a25449c0b050098fTomas WinklerEXPORT_SYMBOL(iwl_scan_cancel); 1352a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/** 1362a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * iwl_scan_cancel_timeout - Cancel any currently executing HW scan 1372a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * @ms: amount of time to wait (in milliseconds) for scan to abort 1382a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * 1392a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * NOTE: priv->mutex must be held before calling this function 1402a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler */ 1412a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerint iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms) 1422a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 1432a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler unsigned long now = jiffies; 1442a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler int ret; 1452a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 1462a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler ret = iwl_scan_cancel(priv); 1472a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (ret && ms) { 1482a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler mutex_unlock(&priv->mutex); 1492a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler while (!time_after(jiffies, now + msecs_to_jiffies(ms)) && 1502a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler test_bit(STATUS_SCANNING, &priv->status)) 1512a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler msleep(1); 1522a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler mutex_lock(&priv->mutex); 1532a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 1542a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return test_bit(STATUS_SCANNING, &priv->status); 1552a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 1562a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 1572a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return ret; 1582a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 1592a421b91d6fe89e27ded7544a25449c0b050098fTomas WinklerEXPORT_SYMBOL(iwl_scan_cancel_timeout); 1602a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 1612a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic int iwl_send_scan_abort(struct iwl_priv *priv) 1622a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 1632a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler int ret = 0; 1642a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler struct iwl_rx_packet *res; 1652a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler struct iwl_host_cmd cmd = { 1662a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler .id = REPLY_SCAN_ABORT_CMD, 1672a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler .meta.flags = CMD_WANT_SKB, 1682a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler }; 1692a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 1702a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler /* If there isn't a scan actively going on in the hardware 1712a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * then we are in between scan bands and not actually 1722a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * actively scanning, so don't send the abort command */ 1732a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (!test_bit(STATUS_SCAN_HW, &priv->status)) { 1742a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler clear_bit(STATUS_SCAN_ABORTING, &priv->status); 1752a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return 0; 1762a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 1772a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 1782a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler ret = iwl_send_cmd_sync(priv, &cmd); 1792a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (ret) { 1802a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler clear_bit(STATUS_SCAN_ABORTING, &priv->status); 1812a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return ret; 1822a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 1832a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 1842a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; 1852a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (res->u.status != CAN_ABORT_STATUS) { 1862a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler /* The scan abort will return 1 for success or 1872a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * 2 for "failure". A failure condition can be 1882a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * due to simply not being in an active scan which 1892a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * can occur if we send the scan abort before we 1902a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * the microcode has notified us that a scan is 1912a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * completed. */ 1922a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_DEBUG_INFO("SCAN_ABORT returned %d.\n", res->u.status); 1932a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler clear_bit(STATUS_SCAN_ABORTING, &priv->status); 1942a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler clear_bit(STATUS_SCAN_HW, &priv->status); 1952a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 1962a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 1972a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler dev_kfree_skb_any(cmd.meta.u.skb); 1982a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 1992a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return ret; 2002a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 2012a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 2022a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 2032a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/* Service response to REPLY_SCAN_CMD (0x80) */ 2042a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic void iwl_rx_reply_scan(struct iwl_priv *priv, 2052a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler struct iwl_rx_mem_buffer *rxb) 2062a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 2072a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#ifdef CONFIG_IWLWIFI_DEBUG 2082a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; 2092a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler struct iwl_scanreq_notification *notif = 2102a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler (struct iwl_scanreq_notification *)pkt->u.raw; 2112a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 2122a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_DEBUG_RX("Scan request status = 0x%x\n", notif->status); 2132a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#endif 2142a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 2152a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 2162a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/* Service SCAN_START_NOTIFICATION (0x82) */ 2172a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic void iwl_rx_scan_start_notif(struct iwl_priv *priv, 2182a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler struct iwl_rx_mem_buffer *rxb) 2192a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 2202a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; 2212a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler struct iwl_scanstart_notification *notif = 2222a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler (struct iwl_scanstart_notification *)pkt->u.raw; 2232a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler priv->scan_start_tsf = le32_to_cpu(notif->tsf_low); 2242a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_DEBUG_SCAN("Scan start: " 2252a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler "%d [802.11%s] " 2262a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n", 2272a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler notif->channel, 2282a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler notif->band ? "bg" : "a", 2292a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler notif->tsf_high, 2302a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler notif->tsf_low, notif->status, notif->beacon_timer); 2312a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 2322a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 2332a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/* Service SCAN_RESULTS_NOTIFICATION (0x83) */ 2342a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic void iwl_rx_scan_results_notif(struct iwl_priv *priv, 2352a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler struct iwl_rx_mem_buffer *rxb) 2362a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 2372a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#ifdef CONFIG_IWLWIFI_DEBUG 2382a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; 2392a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler struct iwl_scanresults_notification *notif = 2402a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler (struct iwl_scanresults_notification *)pkt->u.raw; 2412a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 2422a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_DEBUG_SCAN("Scan ch.res: " 2432a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler "%d [802.11%s] " 2442a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler "(TSF: 0x%08X:%08X) - %d " 2452a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler "elapsed=%lu usec (%dms since last)\n", 2462a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler notif->channel, 2472a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler notif->band ? "bg" : "a", 2482a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler le32_to_cpu(notif->tsf_high), 2492a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler le32_to_cpu(notif->tsf_low), 2502a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler le32_to_cpu(notif->statistics[0]), 2512a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf, 2522a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler jiffies_to_msecs(elapsed_jiffies 2532a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler (priv->last_scan_jiffies, jiffies))); 2542a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#endif 2552a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 2562a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler priv->last_scan_jiffies = jiffies; 2572a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler priv->next_scan_jiffies = 0; 2582a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 2592a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 2602a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */ 2612a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic void iwl_rx_scan_complete_notif(struct iwl_priv *priv, 2622a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler struct iwl_rx_mem_buffer *rxb) 2632a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 2642a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; 2652a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw; 2662a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 2672a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_DEBUG_SCAN("Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n", 2682a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan_notif->scanned_channels, 2692a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan_notif->tsf_low, 2702a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan_notif->tsf_high, scan_notif->status); 2712a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 2722a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler /* The HW is no longer scanning */ 2732a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler clear_bit(STATUS_SCAN_HW, &priv->status); 2742a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 2752a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler /* The scan completion notification came in, so kill that timer... */ 2762a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler cancel_delayed_work(&priv->scan_check); 2772a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 2782a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_DEBUG_INFO("Scan pass on %sGHz took %dms\n", 2791b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) ? 2801b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller "2.4" : "5.2", 2812a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler jiffies_to_msecs(elapsed_jiffies 2822a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler (priv->scan_pass_start, jiffies))); 2832a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 2841b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller /* Remove this scanned band from the list of pending 2851b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller * bands to scan, band G precedes A in order of scanning 2861b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller * as seen in iwl_bg_request_scan */ 2871b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) 2881b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller priv->scan_bands &= ~BIT(IEEE80211_BAND_2GHZ); 2891b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) 2901b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller priv->scan_bands &= ~BIT(IEEE80211_BAND_5GHZ); 2912a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 2922a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler /* If a request to abort was given, or the scan did not succeed 2932a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * then we reset the scan state machine and terminate, 2942a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * re-queuing another scan if one has been requested */ 2952a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { 2962a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_DEBUG_INFO("Aborted scan completed.\n"); 2972a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler clear_bit(STATUS_SCAN_ABORTING, &priv->status); 2982a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } else { 2992a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler /* If there are more bands on this scan pass reschedule */ 3001b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller if (priv->scan_bands) 3012a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler goto reschedule; 3022a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 3032a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 3042a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler priv->last_scan_jiffies = jiffies; 3052a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler priv->next_scan_jiffies = 0; 3062a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_DEBUG_INFO("Setting scan to off\n"); 3072a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 3082a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler clear_bit(STATUS_SCANNING, &priv->status); 3092a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 3102a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_DEBUG_INFO("Scan took %dms\n", 3112a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler jiffies_to_msecs(elapsed_jiffies(priv->scan_start, jiffies))); 3122a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 3132a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler queue_work(priv->workqueue, &priv->scan_completed); 3142a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 3152a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return; 3162a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 3172a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerreschedule: 3182a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler priv->scan_pass_start = jiffies; 3192a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler queue_work(priv->workqueue, &priv->request_scan); 3202a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 3212a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 3222a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklervoid iwl_setup_rx_scan_handlers(struct iwl_priv *priv) 3232a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 3242a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler /* scan handlers */ 3252a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler priv->rx_handlers[REPLY_SCAN_CMD] = iwl_rx_reply_scan; 3262a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl_rx_scan_start_notif; 3272a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] = 3282a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler iwl_rx_scan_results_notif; 3292a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] = 3302a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler iwl_rx_scan_complete_notif; 3312a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 3322a421b91d6fe89e27ded7544a25449c0b050098fTomas WinklerEXPORT_SYMBOL(iwl_setup_rx_scan_handlers); 3332a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 3342a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv, 3352a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler enum ieee80211_band band) 3362a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 3372a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (band == IEEE80211_BAND_5GHZ) 3382a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return IWL_ACTIVE_DWELL_TIME_52; 3392a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler else 3402a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return IWL_ACTIVE_DWELL_TIME_24; 3412a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 3422a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 3432a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, 3442a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler enum ieee80211_band band) 3452a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 3462a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler u16 active = iwl_get_active_dwell_time(priv, band); 3472a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler u16 passive = (band != IEEE80211_BAND_5GHZ) ? 3482a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 : 3492a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52; 3502a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 3512a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (iwl_is_associated(priv)) { 3522a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler /* If we're associated, we clamp the maximum passive 3532a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * dwell time to be 98% of the beacon interval (minus 3542a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * 2 * channel tune time) */ 3552a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler passive = priv->beacon_int; 3562a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if ((passive > IWL_PASSIVE_DWELL_BASE) || !passive) 3572a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler passive = IWL_PASSIVE_DWELL_BASE; 3582a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler passive = (passive * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2; 3592a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 3602a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 3612a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (passive <= active) 3622a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler passive = active + 1; 3632a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 3642a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return passive; 3652a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 3662a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 3672a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic int iwl_get_channels_for_scan(struct iwl_priv *priv, 3682a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler enum ieee80211_band band, 3692a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler u8 is_active, u8 direct_mask, 3702a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler struct iwl_scan_channel *scan_ch) 3712a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 3722a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler const struct ieee80211_channel *channels = NULL; 3732a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler const struct ieee80211_supported_band *sband; 3742a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler const struct iwl_channel_info *ch_info; 3752a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler u16 passive_dwell = 0; 3762a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler u16 active_dwell = 0; 3772a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler int added, i; 3782a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 3792a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler sband = iwl_get_hw_mode(priv, band); 3802a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (!sband) 3812a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return 0; 3822a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 3832a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler channels = sband->channels; 3842a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 3852a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler active_dwell = iwl_get_active_dwell_time(priv, band); 3862a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler passive_dwell = iwl_get_passive_dwell_time(priv, band); 3872a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 3882a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler for (i = 0, added = 0; i < sband->n_channels; i++) { 3892a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (channels[i].flags & IEEE80211_CHAN_DISABLED) 3902a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler continue; 3912a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 3922a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan_ch->channel = 3932a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler ieee80211_frequency_to_channel(channels[i].center_freq); 3942a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 395f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler ch_info = iwl_get_channel_info(priv, band, scan_ch->channel); 3962a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (!is_channel_valid(ch_info)) { 3971b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller IWL_DEBUG_SCAN("Channel %d is INVALID for this band.\n", 3982a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan_ch->channel); 3992a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler continue; 4002a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 4012a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 4022a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (!is_active || is_channel_passive(ch_info) || 4032a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) 404f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler scan_ch->type = 0; 4052a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler else 406f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler scan_ch->type = 1; 4072a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 4082a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (scan_ch->type & 1) 4092a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan_ch->type |= (direct_mask << 1); 4102a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 4112a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan_ch->active_dwell = cpu_to_le16(active_dwell); 4122a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan_ch->passive_dwell = cpu_to_le16(passive_dwell); 4132a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 4142a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler /* Set txpower levels to defaults */ 415f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler scan_ch->dsp_atten = 110; 4162a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 4172a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (band == IEEE80211_BAND_5GHZ) 418f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3; 4192a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler else { 420f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler scan_ch->tx_gain = ((1 << 5) | (5 << 3)); 4212a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler /* NOTE: if we were doing 6Mb OFDM for scans we'd use 4222a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * power level: 423f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3; 4242a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler */ 4252a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 4262a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 4272a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_DEBUG_SCAN("Scanning %d [%s %d]\n", 4282a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan_ch->channel, 4292a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler (scan_ch->type & 1) ? "ACTIVE" : "PASSIVE", 4302a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler (scan_ch->type & 1) ? 4312a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler active_dwell : passive_dwell); 4322a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 4332a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan_ch++; 4342a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler added++; 4352a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 4362a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 4372a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_DEBUG_SCAN("total channels to scan %d \n", added); 4382a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return added; 4392a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 4402a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 441f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winklervoid iwl_init_scan_params(struct iwl_priv *priv) 442f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler{ 443f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler if (!priv->scan_tx_ant[IEEE80211_BAND_5GHZ]) 444f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = RATE_MCS_ANT_INIT_IND; 445f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler if (!priv->scan_tx_ant[IEEE80211_BAND_2GHZ]) 446f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = RATE_MCS_ANT_INIT_IND; 447f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler} 448f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler 4492a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerint iwl_scan_initiate(struct iwl_priv *priv) 4502a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 4512a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (priv->iw_mode == IEEE80211_IF_TYPE_AP) { 4522a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_ERROR("APs don't scan.\n"); 4532a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return 0; 4542a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 4552a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 4562a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (!iwl_is_ready_rf(priv)) { 4572a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_DEBUG_SCAN("Aborting scan due to not ready.\n"); 4582a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return -EIO; 4592a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 4602a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 4612a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (test_bit(STATUS_SCANNING, &priv->status)) { 4622a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_DEBUG_SCAN("Scan already in progress.\n"); 4632a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return -EAGAIN; 4642a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 4652a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 4662a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { 4672a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_DEBUG_SCAN("Scan request while abort pending. " 4682a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler "Queuing.\n"); 4692a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return -EAGAIN; 4702a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 4712a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 4722a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_DEBUG_INFO("Starting scan...\n"); 4731b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller if (priv->cfg->sku & IWL_SKU_G) 4741b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ); 4751b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller if (priv->cfg->sku & IWL_SKU_A) 4761b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ); 4772a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler set_bit(STATUS_SCANNING, &priv->status); 4782a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler priv->scan_start = jiffies; 4792a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler priv->scan_pass_start = priv->scan_start; 4802a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 4812a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler queue_work(priv->workqueue, &priv->request_scan); 4822a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 4832a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return 0; 4842a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 4852a421b91d6fe89e27ded7544a25449c0b050098fTomas WinklerEXPORT_SYMBOL(iwl_scan_initiate); 4862a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 4872a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler#define IWL_SCAN_CHECK_WATCHDOG (7 * HZ) 4882a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 4892a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic void iwl_bg_scan_check(struct work_struct *data) 4902a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 4912a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler struct iwl_priv *priv = 4922a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler container_of(data, struct iwl_priv, scan_check.work); 4932a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 4942a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (test_bit(STATUS_EXIT_PENDING, &priv->status)) 4952a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return; 4962a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 4972a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler mutex_lock(&priv->mutex); 4982a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (test_bit(STATUS_SCANNING, &priv->status) || 4992a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler test_bit(STATUS_SCAN_ABORTING, &priv->status)) { 5002a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_DEBUG(IWL_DL_SCAN, "Scan completion watchdog resetting " 5012a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler "adapter (%dms)\n", 5022a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler jiffies_to_msecs(IWL_SCAN_CHECK_WATCHDOG)); 5032a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 5042a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) 5052a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler iwl_send_scan_abort(priv); 5062a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 5072a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler mutex_unlock(&priv->mutex); 5082a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 5092a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/** 5102a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * iwl_supported_rate_to_ie - fill in the supported rate in IE field 5112a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * 5122a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * return : set the bit for each supported rate insert in ie 5132a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler */ 5142a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic u16 iwl_supported_rate_to_ie(u8 *ie, u16 supported_rate, 5152a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler u16 basic_rate, int *left) 5162a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 5172a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler u16 ret_rates = 0, bit; 5182a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler int i; 5192a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler u8 *cnt = ie; 5202a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler u8 *rates = ie + 1; 5212a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 5222a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler for (bit = 1, i = 0; i < IWL_RATE_COUNT; i++, bit <<= 1) { 5232a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (bit & supported_rate) { 5242a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler ret_rates |= bit; 5252a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler rates[*cnt] = iwl_rates[i].ieee | 5262a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler ((bit & basic_rate) ? 0x80 : 0x00); 5272a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler (*cnt)++; 5282a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler (*left)--; 5292a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if ((*left <= 0) || 5302a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler (*cnt >= IWL_SUPPORTED_RATES_IE_LEN)) 5312a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler break; 5322a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 5332a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 5342a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 5352a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return ret_rates; 5362a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 5372a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 5382a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 5392a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband, 540f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler u8 *pos, int *left) 5412a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 5422a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler struct ieee80211_ht_cap *ht_cap; 5432a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 5442a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (!sband || !sband->ht_info.ht_supported) 5452a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return; 5462a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 5472a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (*left < sizeof(struct ieee80211_ht_cap)) 5482a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return; 5492a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 5502a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler *pos++ = sizeof(struct ieee80211_ht_cap); 5512a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler ht_cap = (struct ieee80211_ht_cap *) pos; 5522a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 5532a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler ht_cap->cap_info = cpu_to_le16(sband->ht_info.cap); 5542a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler memcpy(ht_cap->supp_mcs_set, sband->ht_info.supp_mcs_set, 16); 5552a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler ht_cap->ampdu_params_info = 5562a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler (sband->ht_info.ampdu_factor & IEEE80211_HT_CAP_AMPDU_FACTOR) | 5572a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler ((sband->ht_info.ampdu_density << 2) & 5582a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IEEE80211_HT_CAP_AMPDU_DENSITY); 5592a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler *left -= sizeof(struct ieee80211_ht_cap); 5602a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 5612a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 5622a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler/** 5632a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * iwl_fill_probe_req - fill in all required fields and IE for probe request 5642a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler */ 565f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler 5662a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic u16 iwl_fill_probe_req(struct iwl_priv *priv, 5672a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler enum ieee80211_band band, 5682a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler struct ieee80211_mgmt *frame, 569f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler int left) 5702a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 5712a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler int len = 0; 5722a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler u8 *pos = NULL; 5732a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler u16 active_rates, ret_rates, cck_rates, active_rate_basic; 5742a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler const struct ieee80211_supported_band *sband = 5752a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler iwl_get_hw_mode(priv, band); 5762a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 577f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler 5782a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler /* Make sure there is enough space for the probe request, 5792a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * two mandatory IEs and the data */ 5802a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler left -= 24; 5812a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (left < 0) 5822a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return 0; 5832a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 5842a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); 5852a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler memcpy(frame->da, iwl_bcast_addr, ETH_ALEN); 5862a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler memcpy(frame->sa, priv->mac_addr, ETH_ALEN); 5872a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN); 5882a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler frame->seq_ctrl = 0; 5892a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 590f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler len += 24; 591f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler 5922a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler /* ...next IE... */ 593f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler pos = &frame->u.probe_req.variable[0]; 5942a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 595f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler /* fill in our indirect SSID IE */ 5962a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler left -= 2; 5972a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (left < 0) 5982a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return 0; 5992a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler *pos++ = WLAN_EID_SSID; 6002a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler *pos++ = 0; 6012a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 602f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler len += 2; 6032a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 6042a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler /* fill in supported rate */ 6052a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler left -= 2; 6062a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (left < 0) 6072a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return 0; 6082a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 6092a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler *pos++ = WLAN_EID_SUPP_RATES; 6102a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler *pos = 0; 6112a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 6122a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler /* exclude 60M rate */ 6132a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler active_rates = priv->rates_mask; 6142a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler active_rates &= ~IWL_RATE_60M_MASK; 6152a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 6162a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler active_rate_basic = active_rates & IWL_BASIC_RATES_MASK; 6172a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 6182a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler cck_rates = IWL_CCK_RATES_MASK & active_rates; 6192a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler ret_rates = iwl_supported_rate_to_ie(pos, cck_rates, 620f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler active_rate_basic, &left); 6212a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler active_rates &= ~ret_rates; 6222a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 6232a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler ret_rates = iwl_supported_rate_to_ie(pos, active_rates, 624f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler active_rate_basic, &left); 6252a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler active_rates &= ~ret_rates; 6262a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 6272a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler len += 2 + *pos; 6282a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler pos += (*pos) + 1; 629f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler 6302a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (active_rates == 0) 6312a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler goto fill_end; 6322a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 6332a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler /* fill in supported extended rate */ 6342a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler /* ...next IE... */ 6352a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler left -= 2; 6362a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (left < 0) 6372a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return 0; 6382a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler /* ... fill it in... */ 6392a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler *pos++ = WLAN_EID_EXT_SUPP_RATES; 6402a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler *pos = 0; 641f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler iwl_supported_rate_to_ie(pos, active_rates, active_rate_basic, &left); 642f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler if (*pos > 0) { 6432a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler len += 2 + *pos; 644f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler pos += (*pos) + 1; 645f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler } else { 646f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler pos--; 647f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler } 6482a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 6492a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler fill_end: 650f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler 6512a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler left -= 2; 6522a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (left < 0) 6532a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return 0; 6542a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 6552a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler *pos++ = WLAN_EID_HT_CAPABILITY; 6562a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler *pos = 0; 6572a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler iwl_ht_cap_to_ie(sband, pos, &left); 6582a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (*pos > 0) 6592a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler len += 2 + *pos; 660f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler 6612a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return (u16)len; 6622a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 6632a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 664f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winklerstatic u32 iwl_scan_tx_ant(struct iwl_priv *priv, enum ieee80211_band band) 665f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler{ 666f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler int i, ind; 667f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler 668f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler ind = priv->scan_tx_ant[band]; 669f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler for (i = 0; i < priv->hw_params.tx_chains_num; i++) { 670f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler ind = (ind+1) >= priv->hw_params.tx_chains_num ? 0 : ind+1; 671f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler if (priv->hw_params.valid_tx_ant & (1 << ind)) { 672f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler priv->scan_tx_ant[band] = ind; 673f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler break; 674f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler } 675f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler } 676f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler 677f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler return scan_tx_ant[ind]; 678f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler} 679f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler 680f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler 6812a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic void iwl_bg_request_scan(struct work_struct *data) 6822a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 6832a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler struct iwl_priv *priv = 6842a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler container_of(data, struct iwl_priv, request_scan); 6852a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler struct iwl_host_cmd cmd = { 6862a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler .id = REPLY_SCAN_CMD, 6872a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler .len = sizeof(struct iwl_scan_cmd), 6882a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler .meta.flags = CMD_SIZE_HUGE, 6892a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler }; 6902a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler struct iwl_scan_cmd *scan; 6912a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler struct ieee80211_conf *conf = NULL; 692f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler int ret = 0; 693f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler u32 tx_ant; 6942a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler u16 cmd_len; 6952a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler enum ieee80211_band band; 6962a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler u8 direct_mask; 697f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler u8 rx_chain = 0x7; /* bitmap: ABC chains */ 6982a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 6992a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler conf = ieee80211_get_hw_conf(priv->hw); 7002a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 7012a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler mutex_lock(&priv->mutex); 7022a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 7032a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (!iwl_is_ready(priv)) { 7042a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_WARNING("request scan called when driver not ready.\n"); 7052a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler goto done; 7062a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 7072a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 7082a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler /* Make sure the scan wasn't cancelled before this queued work 7092a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * was given the chance to run... */ 7102a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (!test_bit(STATUS_SCANNING, &priv->status)) 7112a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler goto done; 7122a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 7132a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler /* This should never be called or scheduled if there is currently 7142a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * a scan active in the hardware. */ 7152a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (test_bit(STATUS_SCAN_HW, &priv->status)) { 7162a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_DEBUG_INFO("Multiple concurrent scan requests in parallel. " 7172a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler "Ignoring second request.\n"); 7182a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler ret = -EIO; 7192a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler goto done; 7202a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 7212a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 7222a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { 7232a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_DEBUG_SCAN("Aborting scan due to device shutdown\n"); 7242a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler goto done; 7252a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 7262a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 7272a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { 7282a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_DEBUG_HC("Scan request while abort pending. Queuing.\n"); 7292a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler goto done; 7302a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 7312a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 7322a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (iwl_is_rfkill(priv)) { 7332a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_DEBUG_HC("Aborting scan due to RF Kill activation\n"); 7342a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler goto done; 7352a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 7362a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 7372a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (!test_bit(STATUS_READY, &priv->status)) { 7382a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_DEBUG_HC("Scan request while uninitialized. Queuing.\n"); 7392a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler goto done; 7402a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 7412a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 7422a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (!priv->scan_bands) { 7432a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_DEBUG_HC("Aborting scan due to no requested bands\n"); 7442a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler goto done; 7452a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 7462a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 7472a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (!priv->scan) { 7482a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler priv->scan = kmalloc(sizeof(struct iwl_scan_cmd) + 7492a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_MAX_SCAN_SIZE, GFP_KERNEL); 7502a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (!priv->scan) { 7512a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler ret = -ENOMEM; 7522a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler goto done; 7532a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 7542a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 7552a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan = priv->scan; 7562a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE); 7572a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 7582a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH; 7592a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan->quiet_time = IWL_ACTIVE_QUIET_TIME; 7602a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 7612a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (iwl_is_associated(priv)) { 7622a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler u16 interval = 0; 7632a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler u32 extra; 7642a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler u32 suspend_time = 100; 7652a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler u32 scan_suspend_time = 100; 7662a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler unsigned long flags; 7672a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 7682a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_DEBUG_INFO("Scanning while associated...\n"); 7692a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 7702a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler spin_lock_irqsave(&priv->lock, flags); 7712a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler interval = priv->beacon_int; 7722a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler spin_unlock_irqrestore(&priv->lock, flags); 7732a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 7742a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan->suspend_time = 0; 7752a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan->max_out_time = cpu_to_le32(200 * 1024); 7762a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (!interval) 7772a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler interval = suspend_time; 7782a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 7792a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler extra = (suspend_time / interval) << 22; 7802a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan_suspend_time = (extra | 7812a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler ((suspend_time % interval) * 1024)); 7822a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan->suspend_time = cpu_to_le32(scan_suspend_time); 7832a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_DEBUG_SCAN("suspend_time 0x%X beacon interval %d\n", 7842a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan_suspend_time, interval); 7852a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 7862a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 7872a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler /* We should add the ability for user to lock to PASSIVE ONLY */ 7882a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (priv->one_direct_scan) { 789f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler IWL_DEBUG_SCAN("Start direct scan for '%s'\n", 790f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler iwl_escape_essid(priv->direct_ssid, 791f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler priv->direct_ssid_len)); 7922a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan->direct_scan[0].id = WLAN_EID_SSID; 7932a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan->direct_scan[0].len = priv->direct_ssid_len; 7942a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler memcpy(scan->direct_scan[0].ssid, 7952a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler priv->direct_ssid, priv->direct_ssid_len); 7962a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler direct_mask = 1; 7972a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } else if (!iwl_is_associated(priv) && priv->essid_len) { 798f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler IWL_DEBUG_SCAN("Start direct scan for '%s' (not associated)\n", 799f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler iwl_escape_essid(priv->essid, priv->essid_len)); 8002a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan->direct_scan[0].id = WLAN_EID_SSID; 8012a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan->direct_scan[0].len = priv->essid_len; 8022a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len); 8032a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler direct_mask = 1; 8042a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } else { 805f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler IWL_DEBUG_SCAN("Start indirect scan.\n"); 8062a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler direct_mask = 0; 8072a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 8082a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 8092a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; 8102a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan->tx_cmd.sta_id = priv->hw_params.bcast_sta_id; 8112a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; 8122a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 8132a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 8141b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) { 815f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler band = IEEE80211_BAND_2GHZ; 8162a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; 817f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler tx_ant = iwl_scan_tx_ant(priv, band); 818f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler if (priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) 819f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler scan->tx_cmd.rate_n_flags = 820f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler iwl_hw_set_rate_n_flags(IWL_RATE_6M_PLCP, 821f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler tx_ant); 822f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler else 823f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler scan->tx_cmd.rate_n_flags = 824e7d326ac437e9e9425dcd79382f4e5f6ca31fb16Tomas Winkler iwl_hw_set_rate_n_flags(IWL_RATE_1M_PLCP, 825f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler tx_ant | 826e7d326ac437e9e9425dcd79382f4e5f6ca31fb16Tomas Winkler RATE_MCS_CCK_MSK); 8272a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan->good_CRC_th = 0; 8281b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller } else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) { 829f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler band = IEEE80211_BAND_5GHZ; 830f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler tx_ant = iwl_scan_tx_ant(priv, band); 8312a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan->tx_cmd.rate_n_flags = 832e7d326ac437e9e9425dcd79382f4e5f6ca31fb16Tomas Winkler iwl_hw_set_rate_n_flags(IWL_RATE_6M_PLCP, 833f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler tx_ant); 8342a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan->good_CRC_th = IWL_GOOD_CRC_TH; 8352a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 836f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler /* Force use of chains B and C (0x6) for scan Rx for 4965 837f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler * Avoid A (0x1) because of its off-channel reception on A-band. 838f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler * MIMO is not used here, but value is required */ 839f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_4965) 840f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler rx_chain = 0x6; 8411b63ba8a86c85524a8d7e5953b314ce71ebcb9c9David S. Miller } else { 8422a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_WARNING("Invalid scan band count\n"); 8432a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler goto done; 8442a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler } 8452a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 846f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler scan->rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK | 847f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) | 848f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler (rx_chain << RXON_RX_CHAIN_FORCE_SEL_POS) | 849f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler (0x7 << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS)); 850f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler 8512a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler cmd_len = iwl_fill_probe_req(priv, band, 852f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler (struct ieee80211_mgmt *)scan->data, 853f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler IWL_MAX_SCAN_SIZE - sizeof(*scan)); 8542a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 8552a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan->tx_cmd.len = cpu_to_le16(cmd_len); 8562a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 8572a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) 8582a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan->filter_flags = RXON_FILTER_PROMISC_MSK; 8592a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 860f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK | 861f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler RXON_FILTER_BCON_AWARE_MSK); 862f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler 8632a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (direct_mask) 8642a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan->channel_count = 865f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler iwl_get_channels_for_scan(priv, band, 1, /* active */ 866f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler direct_mask, 8672a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); 8682a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler else 8692a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan->channel_count = 870f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler iwl_get_channels_for_scan(priv, band, 0, /* passive */ 871f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler direct_mask, 8722a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); 873f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler if (scan->channel_count == 0) { 874f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler IWL_DEBUG_SCAN("channel count %d\n", scan->channel_count); 875f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler goto done; 876f53696de6722a4aac00b76e25a5321c01e88a55fTomas Winkler } 8772a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 8782a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler cmd.len += le16_to_cpu(scan->tx_cmd.len) + 8792a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan->channel_count * sizeof(struct iwl_scan_channel); 8802a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler cmd.data = scan; 8812a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler scan->len = cpu_to_le16(cmd.len); 8822a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 8832a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler set_bit(STATUS_SCAN_HW, &priv->status); 8842a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler ret = iwl_send_cmd_sync(priv, &cmd); 8852a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (ret) 8862a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler goto done; 8872a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 8882a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler queue_delayed_work(priv->workqueue, &priv->scan_check, 8892a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler IWL_SCAN_CHECK_WATCHDOG); 8902a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 8912a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler mutex_unlock(&priv->mutex); 8922a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return; 8932a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 8942a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler done: 8952a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler /* inform mac80211 scan aborted */ 8962a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler queue_work(priv->workqueue, &priv->scan_completed); 8972a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler mutex_unlock(&priv->mutex); 8982a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 8992a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 9002a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklerstatic void iwl_bg_abort_scan(struct work_struct *work) 9012a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 9022a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan); 9032a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 9042a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler if (!iwl_is_ready(priv)) 9052a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler return; 9062a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 9072a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler mutex_lock(&priv->mutex); 9082a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 9092a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler set_bit(STATUS_SCAN_ABORTING, &priv->status); 9102a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler iwl_send_scan_abort(priv); 9112a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 9122a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler mutex_unlock(&priv->mutex); 9132a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 9142a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 9152a421b91d6fe89e27ded7544a25449c0b050098fTomas Winklervoid iwl_setup_scan_deferred_work(struct iwl_priv *priv) 9162a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler{ 9172a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler /* FIXME: move here when resolved PENDING 9182a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler * INIT_WORK(&priv->scan_completed, iwl_bg_scan_completed); */ 9192a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler INIT_WORK(&priv->request_scan, iwl_bg_request_scan); 9202a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler INIT_WORK(&priv->abort_scan, iwl_bg_abort_scan); 9212a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check); 9222a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler} 9232a421b91d6fe89e27ded7544a25449c0b050098fTomas WinklerEXPORT_SYMBOL(iwl_setup_scan_deferred_work); 9242a421b91d6fe89e27ded7544a25449c0b050098fTomas Winkler 925