aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-03-10 23:13:26 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-03-11 14:15:55 -0500
commit266af4c745952e9bebf687dd68af58df553cb59d (patch)
treeb3bbe8ac763395a4dfcfdd2b46948c9963dbfa46
parent808118cb41dfe12a1ac0e35515ac4d91b170bdf9 (diff)
iwlagn: support off-channel TX
Add support to iwlagn for off-channel TX. The microcode API for this is a bit strange in that it uses a hacked-up scan command, so the scan code needs to change quite a bit to accomodate that and be able to send it out. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-lib.c135
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c87
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h8
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c41
6 files changed, 238 insertions, 51 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index 25fccf9a3001..2003c1d4295f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -1115,6 +1115,18 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
1115 return added; 1115 return added;
1116} 1116}
1117 1117
1118static int iwl_fill_offch_tx(struct iwl_priv *priv, void *data, size_t maxlen)
1119{
1120 struct sk_buff *skb = priv->_agn.offchan_tx_skb;
1121
1122 if (skb->len < maxlen)
1123 maxlen = skb->len;
1124
1125 memcpy(data, skb->data, maxlen);
1126
1127 return maxlen;
1128}
1129
1118int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) 1130int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
1119{ 1131{
1120 struct iwl_host_cmd cmd = { 1132 struct iwl_host_cmd cmd = {
@@ -1157,17 +1169,25 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
1157 scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH; 1169 scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
1158 scan->quiet_time = IWL_ACTIVE_QUIET_TIME; 1170 scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
1159 1171
1160 if (iwl_is_any_associated(priv)) { 1172 if (priv->scan_type != IWL_SCAN_OFFCH_TX &&
1173 iwl_is_any_associated(priv)) {
1161 u16 interval = 0; 1174 u16 interval = 0;
1162 u32 extra; 1175 u32 extra;
1163 u32 suspend_time = 100; 1176 u32 suspend_time = 100;
1164 u32 scan_suspend_time = 100; 1177 u32 scan_suspend_time = 100;
1165 1178
1166 IWL_DEBUG_INFO(priv, "Scanning while associated...\n"); 1179 IWL_DEBUG_INFO(priv, "Scanning while associated...\n");
1167 if (priv->is_internal_short_scan) 1180 switch (priv->scan_type) {
1181 case IWL_SCAN_OFFCH_TX:
1182 WARN_ON(1);
1183 break;
1184 case IWL_SCAN_RADIO_RESET:
1168 interval = 0; 1185 interval = 0;
1169 else 1186 break;
1187 case IWL_SCAN_NORMAL:
1170 interval = vif->bss_conf.beacon_int; 1188 interval = vif->bss_conf.beacon_int;
1189 break;
1190 }
1171 1191
1172 scan->suspend_time = 0; 1192 scan->suspend_time = 0;
1173 scan->max_out_time = cpu_to_le32(200 * 1024); 1193 scan->max_out_time = cpu_to_le32(200 * 1024);
@@ -1180,29 +1200,41 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
1180 scan->suspend_time = cpu_to_le32(scan_suspend_time); 1200 scan->suspend_time = cpu_to_le32(scan_suspend_time);
1181 IWL_DEBUG_SCAN(priv, "suspend_time 0x%X beacon interval %d\n", 1201 IWL_DEBUG_SCAN(priv, "suspend_time 0x%X beacon interval %d\n",
1182 scan_suspend_time, interval); 1202 scan_suspend_time, interval);
1203 } else if (priv->scan_type == IWL_SCAN_OFFCH_TX) {
1204 scan->suspend_time = 0;
1205 scan->max_out_time =
1206 cpu_to_le32(1024 * priv->_agn.offchan_tx_timeout);
1183 } 1207 }
1184 1208
1185 if (priv->is_internal_short_scan) { 1209 switch (priv->scan_type) {
1210 case IWL_SCAN_RADIO_RESET:
1186 IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n"); 1211 IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n");
1187 } else if (priv->scan_request->n_ssids) { 1212 break;
1188 int i, p = 0; 1213 case IWL_SCAN_NORMAL:
1189 IWL_DEBUG_SCAN(priv, "Kicking off active scan\n"); 1214 if (priv->scan_request->n_ssids) {
1190 for (i = 0; i < priv->scan_request->n_ssids; i++) { 1215 int i, p = 0;
1191 /* always does wildcard anyway */ 1216 IWL_DEBUG_SCAN(priv, "Kicking off active scan\n");
1192 if (!priv->scan_request->ssids[i].ssid_len) 1217 for (i = 0; i < priv->scan_request->n_ssids; i++) {
1193 continue; 1218 /* always does wildcard anyway */
1194 scan->direct_scan[p].id = WLAN_EID_SSID; 1219 if (!priv->scan_request->ssids[i].ssid_len)
1195 scan->direct_scan[p].len = 1220 continue;
1196 priv->scan_request->ssids[i].ssid_len; 1221 scan->direct_scan[p].id = WLAN_EID_SSID;
1197 memcpy(scan->direct_scan[p].ssid, 1222 scan->direct_scan[p].len =
1198 priv->scan_request->ssids[i].ssid, 1223 priv->scan_request->ssids[i].ssid_len;
1199 priv->scan_request->ssids[i].ssid_len); 1224 memcpy(scan->direct_scan[p].ssid,
1200 n_probes++; 1225 priv->scan_request->ssids[i].ssid,
1201 p++; 1226 priv->scan_request->ssids[i].ssid_len);
1202 } 1227 n_probes++;
1203 is_active = true; 1228 p++;
1204 } else 1229 }
1205 IWL_DEBUG_SCAN(priv, "Start passive scan.\n"); 1230 is_active = true;
1231 } else
1232 IWL_DEBUG_SCAN(priv, "Start passive scan.\n");
1233 break;
1234 case IWL_SCAN_OFFCH_TX:
1235 IWL_DEBUG_SCAN(priv, "Start offchannel TX scan.\n");
1236 break;
1237 }
1206 1238
1207 scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK; 1239 scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
1208 scan->tx_cmd.sta_id = ctx->bcast_sta_id; 1240 scan->tx_cmd.sta_id = ctx->bcast_sta_id;
@@ -1300,38 +1332,77 @@ int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
1300 rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS; 1332 rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS;
1301 rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS; 1333 rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS;
1302 scan->rx_chain = cpu_to_le16(rx_chain); 1334 scan->rx_chain = cpu_to_le16(rx_chain);
1303 if (!priv->is_internal_short_scan) { 1335 switch (priv->scan_type) {
1336 case IWL_SCAN_NORMAL:
1304 cmd_len = iwl_fill_probe_req(priv, 1337 cmd_len = iwl_fill_probe_req(priv,
1305 (struct ieee80211_mgmt *)scan->data, 1338 (struct ieee80211_mgmt *)scan->data,
1306 vif->addr, 1339 vif->addr,
1307 priv->scan_request->ie, 1340 priv->scan_request->ie,
1308 priv->scan_request->ie_len, 1341 priv->scan_request->ie_len,
1309 IWL_MAX_SCAN_SIZE - sizeof(*scan)); 1342 IWL_MAX_SCAN_SIZE - sizeof(*scan));
1310 } else { 1343 break;
1344 case IWL_SCAN_RADIO_RESET:
1311 /* use bcast addr, will not be transmitted but must be valid */ 1345 /* use bcast addr, will not be transmitted but must be valid */
1312 cmd_len = iwl_fill_probe_req(priv, 1346 cmd_len = iwl_fill_probe_req(priv,
1313 (struct ieee80211_mgmt *)scan->data, 1347 (struct ieee80211_mgmt *)scan->data,
1314 iwl_bcast_addr, NULL, 0, 1348 iwl_bcast_addr, NULL, 0,
1315 IWL_MAX_SCAN_SIZE - sizeof(*scan)); 1349 IWL_MAX_SCAN_SIZE - sizeof(*scan));
1316 1350 break;
1351 case IWL_SCAN_OFFCH_TX:
1352 cmd_len = iwl_fill_offch_tx(priv, scan->data,
1353 IWL_MAX_SCAN_SIZE
1354 - sizeof(*scan)
1355 - sizeof(struct iwl_scan_channel));
1356 scan->scan_flags |= IWL_SCAN_FLAGS_ACTION_FRAME_TX;
1357 break;
1358 default:
1359 BUG();
1317 } 1360 }
1318 scan->tx_cmd.len = cpu_to_le16(cmd_len); 1361 scan->tx_cmd.len = cpu_to_le16(cmd_len);
1319 1362
1320 scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK | 1363 scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
1321 RXON_FILTER_BCON_AWARE_MSK); 1364 RXON_FILTER_BCON_AWARE_MSK);
1322 1365
1323 if (priv->is_internal_short_scan) { 1366 switch (priv->scan_type) {
1367 case IWL_SCAN_RADIO_RESET:
1324 scan->channel_count = 1368 scan->channel_count =
1325 iwl_get_single_channel_for_scan(priv, vif, band, 1369 iwl_get_single_channel_for_scan(priv, vif, band,
1326 (void *)&scan->data[le16_to_cpu( 1370 (void *)&scan->data[cmd_len]);
1327 scan->tx_cmd.len)]); 1371 break;
1328 } else { 1372 case IWL_SCAN_NORMAL:
1329 scan->channel_count = 1373 scan->channel_count =
1330 iwl_get_channels_for_scan(priv, vif, band, 1374 iwl_get_channels_for_scan(priv, vif, band,
1331 is_active, n_probes, 1375 is_active, n_probes,
1332 (void *)&scan->data[le16_to_cpu( 1376 (void *)&scan->data[cmd_len]);
1333 scan->tx_cmd.len)]); 1377 break;
1378 case IWL_SCAN_OFFCH_TX: {
1379 struct iwl_scan_channel *scan_ch;
1380
1381 scan->channel_count = 1;
1382
1383 scan_ch = (void *)&scan->data[cmd_len];
1384 scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
1385 scan_ch->channel =
1386 cpu_to_le16(priv->_agn.offchan_tx_chan->hw_value);
1387 scan_ch->active_dwell =
1388 cpu_to_le16(priv->_agn.offchan_tx_timeout);
1389 scan_ch->passive_dwell = 0;
1390
1391 /* Set txpower levels to defaults */
1392 scan_ch->dsp_atten = 110;
1393
1394 /* NOTE: if we were doing 6Mb OFDM for scans we'd use
1395 * power level:
1396 * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
1397 */
1398 if (priv->_agn.offchan_tx_chan->band == IEEE80211_BAND_5GHZ)
1399 scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
1400 else
1401 scan_ch->tx_gain = ((1 << 5) | (5 << 3));
1402 }
1403 break;
1334 } 1404 }
1405
1335 if (scan->channel_count == 0) { 1406 if (scan->channel_count == 0) {
1336 IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count); 1407 IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count);
1337 return -EIO; 1408 return -EIO;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 19bb567d1c52..b57fbbf3fb64 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -2937,6 +2937,91 @@ static void iwl_bg_rx_replenish(struct work_struct *data)
2937 mutex_unlock(&priv->mutex); 2937 mutex_unlock(&priv->mutex);
2938} 2938}
2939 2939
2940static int iwl_mac_offchannel_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
2941 struct ieee80211_channel *chan,
2942 enum nl80211_channel_type channel_type,
2943 unsigned int wait)
2944{
2945 struct iwl_priv *priv = hw->priv;
2946 int ret;
2947
2948 /* Not supported if we don't have PAN */
2949 if (!(priv->valid_contexts & BIT(IWL_RXON_CTX_PAN))) {
2950 ret = -EOPNOTSUPP;
2951 goto free;
2952 }
2953
2954 /* Not supported on pre-P2P firmware */
2955 if (!(priv->contexts[IWL_RXON_CTX_PAN].interface_modes &
2956 BIT(NL80211_IFTYPE_P2P_CLIENT))) {
2957 ret = -EOPNOTSUPP;
2958 goto free;
2959 }
2960
2961 mutex_lock(&priv->mutex);
2962
2963 if (!priv->contexts[IWL_RXON_CTX_PAN].is_active) {
2964 /*
2965 * If the PAN context is free, use the normal
2966 * way of doing remain-on-channel offload + TX.
2967 */
2968 ret = 1;
2969 goto out;
2970 }
2971
2972 /* TODO: queue up if scanning? */
2973 if (test_bit(STATUS_SCANNING, &priv->status) ||
2974 priv->_agn.offchan_tx_skb) {
2975 ret = -EBUSY;
2976 goto out;
2977 }
2978
2979 /*
2980 * max_scan_ie_len doesn't include the blank SSID or the header,
2981 * so need to add that again here.
2982 */
2983 if (skb->len > hw->wiphy->max_scan_ie_len + 24 + 2) {
2984 ret = -ENOBUFS;
2985 goto out;
2986 }
2987
2988 priv->_agn.offchan_tx_skb = skb;
2989 priv->_agn.offchan_tx_timeout = wait;
2990 priv->_agn.offchan_tx_chan = chan;
2991
2992 ret = iwl_scan_initiate(priv, priv->contexts[IWL_RXON_CTX_PAN].vif,
2993 IWL_SCAN_OFFCH_TX, chan->band);
2994 if (ret)
2995 priv->_agn.offchan_tx_skb = NULL;
2996 out:
2997 mutex_unlock(&priv->mutex);
2998 free:
2999 if (ret < 0)
3000 kfree_skb(skb);
3001
3002 return ret;
3003}
3004
3005static int iwl_mac_offchannel_tx_cancel_wait(struct ieee80211_hw *hw)
3006{
3007 struct iwl_priv *priv = hw->priv;
3008 int ret;
3009
3010 mutex_lock(&priv->mutex);
3011
3012 if (!priv->_agn.offchan_tx_skb)
3013 return -EINVAL;
3014
3015 priv->_agn.offchan_tx_skb = NULL;
3016
3017 ret = iwl_scan_cancel_timeout(priv, 200);
3018 if (ret)
3019 ret = -EIO;
3020 mutex_unlock(&priv->mutex);
3021
3022 return ret;
3023}
3024
2940/***************************************************************************** 3025/*****************************************************************************
2941 * 3026 *
2942 * mac80211 entry point functions 3027 * mac80211 entry point functions
@@ -3815,6 +3900,8 @@ struct ieee80211_ops iwlagn_hw_ops = {
3815 .tx_last_beacon = iwl_mac_tx_last_beacon, 3900 .tx_last_beacon = iwl_mac_tx_last_beacon,
3816 .remain_on_channel = iwl_mac_remain_on_channel, 3901 .remain_on_channel = iwl_mac_remain_on_channel,
3817 .cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel, 3902 .cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel,
3903 .offchannel_tx = iwl_mac_offchannel_tx,
3904 .offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait,
3818}; 3905};
3819 3906
3820static void iwl_hw_detect(struct iwl_priv *priv) 3907static void iwl_hw_detect(struct iwl_priv *priv)
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index 03cfb74da2bc..ca42ffa63ed7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -2964,9 +2964,15 @@ struct iwl3945_scan_cmd {
2964 u8 data[0]; 2964 u8 data[0];
2965} __packed; 2965} __packed;
2966 2966
2967enum iwl_scan_flags {
2968 /* BIT(0) currently unused */
2969 IWL_SCAN_FLAGS_ACTION_FRAME_TX = BIT(1),
2970 /* bits 2-7 reserved */
2971};
2972
2967struct iwl_scan_cmd { 2973struct iwl_scan_cmd {
2968 __le16 len; 2974 __le16 len;
2969 u8 reserved0; 2975 u8 scan_flags; /* scan flags: see enum iwl_scan_flags */
2970 u8 channel_count; /* # channels in channel list */ 2976 u8 channel_count; /* # channels in channel list */
2971 __le16 quiet_time; /* dwell only this # millisecs on quiet channel 2977 __le16 quiet_time; /* dwell only this # millisecs on quiet channel
2972 * (only for active scan) */ 2978 * (only for active scan) */
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index af47750f8985..b316d833d9a2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -63,6 +63,8 @@
63#ifndef __iwl_core_h__ 63#ifndef __iwl_core_h__
64#define __iwl_core_h__ 64#define __iwl_core_h__
65 65
66#include "iwl-dev.h"
67
66/************************ 68/************************
67 * forward declarations * 69 * forward declarations *
68 ************************/ 70 ************************/
@@ -551,6 +553,10 @@ u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
551 struct ieee80211_vif *vif); 553 struct ieee80211_vif *vif);
552void iwl_setup_scan_deferred_work(struct iwl_priv *priv); 554void iwl_setup_scan_deferred_work(struct iwl_priv *priv);
553void iwl_cancel_scan_deferred_work(struct iwl_priv *priv); 555void iwl_cancel_scan_deferred_work(struct iwl_priv *priv);
556int __must_check iwl_scan_initiate(struct iwl_priv *priv,
557 struct ieee80211_vif *vif,
558 enum iwl_scan_type scan_type,
559 enum ieee80211_band band);
554 560
555/* For faster active scanning, scan will move to the next channel if fewer than 561/* For faster active scanning, scan will move to the next channel if fewer than
556 * PLCP_QUIET_THRESH packets are heard on this channel within 562 * PLCP_QUIET_THRESH packets are heard on this channel within
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 6a41deba6863..68b953f2bdc7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -1230,6 +1230,12 @@ struct iwl_rxon_context {
1230 } ht; 1230 } ht;
1231}; 1231};
1232 1232
1233enum iwl_scan_type {
1234 IWL_SCAN_NORMAL,
1235 IWL_SCAN_RADIO_RESET,
1236 IWL_SCAN_OFFCH_TX,
1237};
1238
1233struct iwl_priv { 1239struct iwl_priv {
1234 1240
1235 /* ieee device used by generic ieee processing code */ 1241 /* ieee device used by generic ieee processing code */
@@ -1290,7 +1296,7 @@ struct iwl_priv {
1290 enum ieee80211_band scan_band; 1296 enum ieee80211_band scan_band;
1291 struct cfg80211_scan_request *scan_request; 1297 struct cfg80211_scan_request *scan_request;
1292 struct ieee80211_vif *scan_vif; 1298 struct ieee80211_vif *scan_vif;
1293 bool is_internal_short_scan; 1299 enum iwl_scan_type scan_type;
1294 u8 scan_tx_ant[IEEE80211_NUM_BANDS]; 1300 u8 scan_tx_ant[IEEE80211_NUM_BANDS];
1295 u8 mgmt_tx_ant; 1301 u8 mgmt_tx_ant;
1296 1302
@@ -1504,6 +1510,10 @@ struct iwl_priv {
1504 struct delayed_work hw_roc_work; 1510 struct delayed_work hw_roc_work;
1505 enum nl80211_channel_type hw_roc_chantype; 1511 enum nl80211_channel_type hw_roc_chantype;
1506 int hw_roc_duration; 1512 int hw_roc_duration;
1513
1514 struct sk_buff *offchan_tx_skb;
1515 int offchan_tx_timeout;
1516 struct ieee80211_channel *offchan_tx_chan;
1507 } _agn; 1517 } _agn;
1508#endif 1518#endif
1509 }; 1519 };
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index faa6d34cb658..3a4d9e6b0421 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -101,7 +101,7 @@ static void iwl_complete_scan(struct iwl_priv *priv, bool aborted)
101 ieee80211_scan_completed(priv->hw, aborted); 101 ieee80211_scan_completed(priv->hw, aborted);
102 } 102 }
103 103
104 priv->is_internal_short_scan = false; 104 priv->scan_type = IWL_SCAN_NORMAL;
105 priv->scan_vif = NULL; 105 priv->scan_vif = NULL;
106 priv->scan_request = NULL; 106 priv->scan_request = NULL;
107} 107}
@@ -339,10 +339,10 @@ void iwl_init_scan_params(struct iwl_priv *priv)
339 priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx; 339 priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx;
340} 340}
341 341
342static int __must_check iwl_scan_initiate(struct iwl_priv *priv, 342int __must_check iwl_scan_initiate(struct iwl_priv *priv,
343 struct ieee80211_vif *vif, 343 struct ieee80211_vif *vif,
344 bool internal, 344 enum iwl_scan_type scan_type,
345 enum ieee80211_band band) 345 enum ieee80211_band band)
346{ 346{
347 int ret; 347 int ret;
348 348
@@ -370,17 +370,19 @@ static int __must_check iwl_scan_initiate(struct iwl_priv *priv,
370 } 370 }
371 371
372 IWL_DEBUG_SCAN(priv, "Starting %sscan...\n", 372 IWL_DEBUG_SCAN(priv, "Starting %sscan...\n",
373 internal ? "internal short " : ""); 373 scan_type == IWL_SCAN_NORMAL ? "" :
374 scan_type == IWL_SCAN_OFFCH_TX ? "offchan TX " :
375 "internal short ");
374 376
375 set_bit(STATUS_SCANNING, &priv->status); 377 set_bit(STATUS_SCANNING, &priv->status);
376 priv->is_internal_short_scan = internal; 378 priv->scan_type = scan_type;
377 priv->scan_start = jiffies; 379 priv->scan_start = jiffies;
378 priv->scan_band = band; 380 priv->scan_band = band;
379 381
380 ret = priv->cfg->ops->utils->request_scan(priv, vif); 382 ret = priv->cfg->ops->utils->request_scan(priv, vif);
381 if (ret) { 383 if (ret) {
382 clear_bit(STATUS_SCANNING, &priv->status); 384 clear_bit(STATUS_SCANNING, &priv->status);
383 priv->is_internal_short_scan = false; 385 priv->scan_type = IWL_SCAN_NORMAL;
384 return ret; 386 return ret;
385 } 387 }
386 388
@@ -405,7 +407,7 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
405 mutex_lock(&priv->mutex); 407 mutex_lock(&priv->mutex);
406 408
407 if (test_bit(STATUS_SCANNING, &priv->status) && 409 if (test_bit(STATUS_SCANNING, &priv->status) &&
408 !priv->is_internal_short_scan) { 410 priv->scan_type != IWL_SCAN_NORMAL) {
409 IWL_DEBUG_SCAN(priv, "Scan already in progress.\n"); 411 IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
410 ret = -EAGAIN; 412 ret = -EAGAIN;
411 goto out_unlock; 413 goto out_unlock;
@@ -419,11 +421,11 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
419 * If an internal scan is in progress, just set 421 * If an internal scan is in progress, just set
420 * up the scan_request as per above. 422 * up the scan_request as per above.
421 */ 423 */
422 if (priv->is_internal_short_scan) { 424 if (priv->scan_type != IWL_SCAN_NORMAL) {
423 IWL_DEBUG_SCAN(priv, "SCAN request during internal scan\n"); 425 IWL_DEBUG_SCAN(priv, "SCAN request during internal scan\n");
424 ret = 0; 426 ret = 0;
425 } else 427 } else
426 ret = iwl_scan_initiate(priv, vif, false, 428 ret = iwl_scan_initiate(priv, vif, IWL_SCAN_NORMAL,
427 req->channels[0]->band); 429 req->channels[0]->band);
428 430
429 IWL_DEBUG_MAC80211(priv, "leave\n"); 431 IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -452,7 +454,7 @@ static void iwl_bg_start_internal_scan(struct work_struct *work)
452 454
453 mutex_lock(&priv->mutex); 455 mutex_lock(&priv->mutex);
454 456
455 if (priv->is_internal_short_scan == true) { 457 if (priv->scan_type == IWL_SCAN_RADIO_RESET) {
456 IWL_DEBUG_SCAN(priv, "Internal scan already in progress\n"); 458 IWL_DEBUG_SCAN(priv, "Internal scan already in progress\n");
457 goto unlock; 459 goto unlock;
458 } 460 }
@@ -462,7 +464,7 @@ static void iwl_bg_start_internal_scan(struct work_struct *work)
462 goto unlock; 464 goto unlock;
463 } 465 }
464 466
465 if (iwl_scan_initiate(priv, NULL, true, priv->band)) 467 if (iwl_scan_initiate(priv, NULL, IWL_SCAN_RADIO_RESET, priv->band))
466 IWL_DEBUG_SCAN(priv, "failed to start internal short scan\n"); 468 IWL_DEBUG_SCAN(priv, "failed to start internal short scan\n");
467 unlock: 469 unlock:
468 mutex_unlock(&priv->mutex); 470 mutex_unlock(&priv->mutex);
@@ -549,8 +551,7 @@ static void iwl_bg_scan_completed(struct work_struct *work)
549 container_of(work, struct iwl_priv, scan_completed); 551 container_of(work, struct iwl_priv, scan_completed);
550 bool aborted; 552 bool aborted;
551 553
552 IWL_DEBUG_SCAN(priv, "Completed %sscan.\n", 554 IWL_DEBUG_SCAN(priv, "Completed scan.\n");
553 priv->is_internal_short_scan ? "internal short " : "");
554 555
555 cancel_delayed_work(&priv->scan_check); 556 cancel_delayed_work(&priv->scan_check);
556 557
@@ -565,7 +566,13 @@ static void iwl_bg_scan_completed(struct work_struct *work)
565 goto out_settings; 566 goto out_settings;
566 } 567 }
567 568
568 if (priv->is_internal_short_scan && !aborted) { 569 if (priv->scan_type == IWL_SCAN_OFFCH_TX && priv->_agn.offchan_tx_skb) {
570 ieee80211_tx_status_irqsafe(priv->hw,
571 priv->_agn.offchan_tx_skb);
572 priv->_agn.offchan_tx_skb = NULL;
573 }
574
575 if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) {
569 int err; 576 int err;
570 577
571 /* Check if mac80211 requested scan during our internal scan */ 578 /* Check if mac80211 requested scan during our internal scan */
@@ -573,7 +580,7 @@ static void iwl_bg_scan_completed(struct work_struct *work)
573 goto out_complete; 580 goto out_complete;
574 581
575 /* If so request a new scan */ 582 /* If so request a new scan */
576 err = iwl_scan_initiate(priv, priv->scan_vif, false, 583 err = iwl_scan_initiate(priv, priv->scan_vif, IWL_SCAN_NORMAL,
577 priv->scan_request->channels[0]->band); 584 priv->scan_request->channels[0]->band);
578 if (err) { 585 if (err) {
579 IWL_DEBUG_SCAN(priv, 586 IWL_DEBUG_SCAN(priv,