/* The maximum number of channels the firmware can scan per command */
#define MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN 14
-#define MWIFIEX_CHANNELS_PER_SCAN_CMD 4
+#define MWIFIEX_DEF_CHANNELS_PER_SCAN_CMD 4
+#define MWIFIEX_LIMIT_1_CHANNEL_PER_SCAN_CMD 15
+#define MWIFIEX_LIMIT_2_CHANNELS_PER_SCAN_CMD 27
+#define MWIFIEX_LIMIT_3_CHANNELS_PER_SCAN_CMD 35
/* Memory needed to store a max sized Channel List TLV for a firmware scan */
#define CHAN_TLV_MAX_SIZE (sizeof(struct mwifiex_ie_types_header) \
* This routine is used for any scan that is not provided with a
* specific channel list to scan.
*/
-static void
+static int
mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
const struct mwifiex_user_scan_cfg
*user_scan_in,
}
}
+ return chan_idx;
}
/*
u32 tlv_idx;
u32 total_scan_time;
- u32 done_early;
if (!scan_cfg_out || !chan_tlv_out || !scan_chan_list) {
dev_dbg(priv->adapter->dev,
total_scan_time = 0;
chan_tlv_out->header.len = 0;
start_chan = tmp_chan_list;
- done_early = false;
/*
* Construct the Channel TLV for the scan command. Continue to
* - done_early is set (controlling individual scanning of
* 1,6,11)
*/
- while (tlv_idx < max_chan_per_scan &&
- tmp_chan_list->chan_number && !done_early) {
-
+ if (tlv_idx < max_chan_per_scan) {
dev_dbg(priv->adapter->dev,
"info: Scan: Chan(%3d), Radio(%d),"
" Mode(%d, %d), Dur(%d)\n",
total_scan_time +=
le16_to_cpu(tmp_chan_list->max_scan_time);
- done_early = false;
-
- /* Stop the loop if the *current* channel is in the
- 1,6,11 set and we are not filtering on a BSSID
- or SSID. */
- if (!filtered_scan &&
- (tmp_chan_list->chan_number == 1 ||
- tmp_chan_list->chan_number == 6 ||
- tmp_chan_list->chan_number == 11))
- done_early = true;
-
/* Increment the tmp pointer to the next channel to
be scanned */
tmp_chan_list++;
-
- /* Stop the loop if the *next* channel is in the 1,6,11
- set. This will cause it to be the only channel
- scanned on the next interation */
- if (!filtered_scan &&
- (tmp_chan_list->chan_number == 1 ||
- tmp_chan_list->chan_number == 6 ||
- tmp_chan_list->chan_number == 11))
- done_early = true;
}
/* The total scan time should be less than scan command timeout
u32 num_probes;
u32 ssid_len;
u32 chan_idx;
+ u32 chan_num;
u32 scan_type;
u16 scan_dur;
u8 channel;
if (*filtered_scan)
*max_chan_per_scan = MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN;
else
- *max_chan_per_scan = MWIFIEX_CHANNELS_PER_SCAN_CMD;
+ *max_chan_per_scan = MWIFIEX_DEF_CHANNELS_PER_SCAN_CMD;
/* If the input config or adapter has the number of Probes set,
add tlv */
dev_dbg(adapter->dev,
"info: Scan: Scanning current channel only\n");
}
-
+ chan_num = chan_idx;
} else {
dev_dbg(adapter->dev,
"info: Scan: Creating full region channel list\n");
- mwifiex_scan_create_channel_list(priv, user_scan_in,
- scan_chan_list,
- *filtered_scan);
+ chan_num = mwifiex_scan_create_channel_list(priv, user_scan_in,
+ scan_chan_list,
+ *filtered_scan);
+ }
+
+ /*
+ * In associated state we will reduce the number of channels scanned per
+ * scan command to avoid any traffic delay/loss. This number is decided
+ * based on total number of channels to be scanned due to constraints
+ * of command buffers.
+ */
+ if (priv->media_connected) {
+ if (chan_num < MWIFIEX_LIMIT_1_CHANNEL_PER_SCAN_CMD)
+ *max_chan_per_scan = 1;
+ else if (chan_num < MWIFIEX_LIMIT_2_CHANNELS_PER_SCAN_CMD)
+ *max_chan_per_scan = 2;
+ else if (chan_num < MWIFIEX_LIMIT_3_CHANNELS_PER_SCAN_CMD)
+ *max_chan_per_scan = 3;
+ else
+ *max_chan_per_scan = 4;
}
}
* This function parses provided beacon buffer and updates
* respective fields in bss descriptor structure.
*/
-int
-mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
- struct mwifiex_bssdescriptor *bss_entry,
- u8 *ie_buf, u32 ie_len)
+int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
+ struct mwifiex_bssdescriptor *bss_entry)
{
int ret = 0;
u8 element_id;
found_data_rate_ie = false;
rate_size = 0;
- current_ptr = ie_buf;
- bytes_left = ie_len;
- bss_entry->beacon_buf = ie_buf;
- bss_entry->beacon_buf_size = ie_len;
+ current_ptr = bss_entry->beacon_buf;
+ bytes_left = bss_entry->beacon_buf_size;
/* Process variable IE */
while (bytes_left >= 2) {
* order to send the appropriate scan commands to firmware to populate or
* update the internal driver scan table.
*/
-static int mwifiex_scan_networks(struct mwifiex_private *priv,
- const struct mwifiex_user_scan_cfg *user_scan_in)
+int mwifiex_scan_networks(struct mwifiex_private *priv,
+ const struct mwifiex_user_scan_cfg *user_scan_in)
{
- int ret = 0;
+ int ret;
struct mwifiex_adapter *adapter = priv->adapter;
struct cmd_ctrl_node *cmd_node;
union mwifiex_scan_cmd_config_tlv *scan_cfg_out;
unsigned long flags;
if (adapter->scan_processing) {
- dev_dbg(adapter->dev, "cmd: Scan already in process...\n");
- return ret;
+ dev_err(adapter->dev, "cmd: Scan already in process...\n");
+ return -EBUSY;
}
- spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
- adapter->scan_processing = true;
- spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
-
if (priv->scan_block) {
- dev_dbg(adapter->dev,
+ dev_err(adapter->dev,
"cmd: Scan is blocked during association...\n");
- return ret;
+ return -EBUSY;
}
+ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+ adapter->scan_processing = true;
+ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+
scan_cfg_out = kzalloc(sizeof(union mwifiex_scan_cmd_config_tlv),
GFP_KERNEL);
if (!scan_cfg_out) {
dev_err(adapter->dev, "failed to alloc scan_cfg_out\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto done;
}
buf_size = sizeof(struct mwifiex_chan_scan_param_set) *
if (!scan_chan_list) {
dev_err(adapter->dev, "failed to alloc scan_chan_list\n");
kfree(scan_cfg_out);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto done;
}
mwifiex_config_scan(priv, user_scan_in, &scan_cfg_out->config,
adapter->cmd_queued = cmd_node;
mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
true);
+ queue_work(adapter->workqueue, &adapter->main_work);
} else {
spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
flags);
}
- } else {
- spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
- adapter->scan_processing = true;
- spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
}
kfree(scan_cfg_out);
kfree(scan_chan_list);
+done:
+ if (ret) {
+ spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+ adapter->scan_processing = false;
+ spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+ }
return ret;
}
-/*
- * Sends IOCTL request to start a scan with user configurations.
- *
- * This function allocates the IOCTL request buffer, fills it
- * with requisite parameters and calls the IOCTL handler.
- *
- * Upon completion, it also generates a wireless event to notify
- * applications.
- */
-int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv,
- struct mwifiex_user_scan_cfg *scan_req)
-{
- int status;
-
- status = mwifiex_scan_networks(priv, scan_req);
- queue_work(priv->adapter->workqueue, &priv->adapter->main_work);
-
- return status;
-}
-
/*
* This function prepares a scan command to be sent to the firmware.
*
ret = mwifiex_is_network_compatible(priv, bss_desc,
priv->bss_mode);
if (ret)
- dev_err(priv->adapter->dev, "cannot find ssid "
- "%s\n", bss_desc->ssid.ssid);
+ dev_err(priv->adapter->dev,
+ "Incompatible network settings\n");
break;
default:
ret = 0;
return ret;
}
-static int
-mwifiex_update_curr_bss_params(struct mwifiex_private *priv, u8 *bssid,
- s32 rssi, const u8 *ie_buf, size_t ie_len,
- u16 beacon_period, u16 cap_info_bitmap, u8 band)
+static int mwifiex_update_curr_bss_params(struct mwifiex_private *priv,
+ struct cfg80211_bss *bss)
{
struct mwifiex_bssdescriptor *bss_desc;
int ret;
unsigned long flags;
u8 *beacon_ie;
+ size_t beacon_ie_len = bss->len_information_elements;
/* Allocate and fill new bss descriptor */
bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor),
return -ENOMEM;
}
- beacon_ie = kmemdup(ie_buf, ie_len, GFP_KERNEL);
+ beacon_ie = kmemdup(bss->information_elements, beacon_ie_len,
+ GFP_KERNEL);
if (!beacon_ie) {
kfree(bss_desc);
- dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n");
return -ENOMEM;
}
- ret = mwifiex_fill_new_bss_desc(priv, bssid, rssi, beacon_ie,
- ie_len, beacon_period,
- cap_info_bitmap, band, bss_desc);
+ ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc, beacon_ie,
+ beacon_ie_len);
if (ret)
goto done;
if (ret)
goto done;
- /* Update current bss descriptor parameters */
spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags);
- priv->curr_bss_params.bss_descriptor.bcn_wpa_ie = NULL;
- priv->curr_bss_params.bss_descriptor.wpa_offset = 0;
- priv->curr_bss_params.bss_descriptor.bcn_rsn_ie = NULL;
- priv->curr_bss_params.bss_descriptor.rsn_offset = 0;
- priv->curr_bss_params.bss_descriptor.bcn_wapi_ie = NULL;
- priv->curr_bss_params.bss_descriptor.wapi_offset = 0;
- priv->curr_bss_params.bss_descriptor.bcn_ht_cap = NULL;
- priv->curr_bss_params.bss_descriptor.ht_cap_offset =
- 0;
- priv->curr_bss_params.bss_descriptor.bcn_ht_info = NULL;
- priv->curr_bss_params.bss_descriptor.ht_info_offset =
- 0;
- priv->curr_bss_params.bss_descriptor.bcn_bss_co_2040 =
- NULL;
- priv->curr_bss_params.bss_descriptor.
- bss_co_2040_offset = 0;
- priv->curr_bss_params.bss_descriptor.bcn_ext_cap = NULL;
- priv->curr_bss_params.bss_descriptor.ext_cap_offset = 0;
- priv->curr_bss_params.bss_descriptor.beacon_buf = NULL;
- priv->curr_bss_params.bss_descriptor.beacon_buf_size =
- 0;
-
/* Make a copy of current BSSID descriptor */
memcpy(&priv->curr_bss_params.bss_descriptor, bss_desc,
sizeof(priv->curr_bss_params.bss_descriptor));
+
+ /* The contents of beacon_ie will be copied to its own buffer
+ * in mwifiex_save_curr_bcn()
+ */
mwifiex_save_curr_bcn(priv);
spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags);
done:
- kfree(bss_desc);
kfree(beacon_ie);
+ kfree(bss_desc);
return 0;
}
dev_err(adapter->dev, "SCAN_RESP: too many AP returned (%d)\n",
scan_rsp->number_of_sets);
ret = -1;
- goto done;
+ goto check_next_scan;
}
bytes_left = le16_to_cpu(scan_rsp->bss_descript_size);
const u8 *ie_buf;
size_t ie_len;
u16 channel = 0;
- u64 network_tsf = 0;
+ u64 fw_tsf = 0;
u16 beacon_size = 0;
u32 curr_bcn_bytes;
u32 freq;
u16 beacon_period;
u16 cap_info_bitmap;
u8 *current_ptr;
+ u64 timestamp;
struct mwifiex_bcn_param *bcn_param;
+ struct mwifiex_bss_priv *bss_priv;
if (bytes_left >= sizeof(beacon_size)) {
/* Extract & convert beacon size from command buffer */
if (!beacon_size || beacon_size > bytes_left) {
bss_info += bytes_left;
bytes_left = 0;
- return -1;
+ ret = -1;
+ goto check_next_scan;
}
/* Initialize the current working beacon pointer for this BSS
memcpy(bssid, bcn_param->bssid, ETH_ALEN);
- rssi = (s32) (bcn_param->rssi);
- dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%02X\n", rssi);
+ rssi = (s32) bcn_param->rssi;
+ rssi = (-rssi) * 100; /* Convert dBm to mBm */
+ dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%d\n", rssi);
+ timestamp = le64_to_cpu(bcn_param->timestamp);
beacon_period = le16_to_cpu(bcn_param->beacon_period);
cap_info_bitmap = le16_to_cpu(bcn_param->cap_info_bitmap);
dev_err(priv->adapter->dev,
"%s: bytes left < IE length\n",
__func__);
- goto done;
+ goto check_next_scan;
}
if (element_id == WLAN_EID_DS_PARAMS) {
channel = *(u8 *) (current_ptr +
/*
* If the TSF TLV was appended to the scan results, save this
- * entry's TSF value in the networkTSF field.The networkTSF is
- * the firmware's TSF value at the time the beacon or probe
- * response was received.
+ * entry's TSF value in the fw_tsf field. It is the firmware's
+ * TSF value at the time the beacon or probe response was
+ * received.
*/
if (tsf_tlv)
- memcpy(&network_tsf,
- &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE],
- sizeof(network_tsf));
+ memcpy(&fw_tsf, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE],
+ sizeof(fw_tsf));
if (channel) {
struct ieee80211_channel *chan;
chan = ieee80211_get_channel(priv->wdev->wiphy, freq);
if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) {
+ DECLARE_SSID_BUF(ssid_buf);
+
+ wiphy_info(priv->wdev->wiphy,
+ "inform bss: %pM [SSID=%s]\n", bssid,
+ print_ssid(ssid_buf, ie_buf + 2,
+ *(ie_buf + 1)));
+
bss = cfg80211_inform_bss(priv->wdev->wiphy,
- chan, bssid, network_tsf,
+ chan, bssid, timestamp,
cap_info_bitmap, beacon_period,
ie_buf, ie_len, rssi, GFP_KERNEL);
- *(u8 *)bss->priv = band;
- cfg80211_put_bss(bss);
-
+ bss_priv = (struct mwifiex_bss_priv *)bss->priv;
+ bss_priv->band = band;
+ bss_priv->fw_tsf = fw_tsf;
if (priv->media_connected &&
!memcmp(bssid,
priv->curr_bss_params.bss_descriptor
.mac_address, ETH_ALEN))
- mwifiex_update_curr_bss_params
- (priv, bssid, rssi,
- ie_buf, ie_len,
- beacon_period,
- cap_info_bitmap, band);
+ mwifiex_update_curr_bss_params(priv,
+ bss);
+ cfg80211_put_bss(bss);
}
} else {
dev_dbg(adapter->dev, "missing BSS channel IE\n");
}
}
+check_next_scan:
spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
if (list_empty(&adapter->scan_pending_q)) {
spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
}
if (priv->report_scan_result)
priv->report_scan_result = false;
- if (priv->scan_pending_on_block) {
- priv->scan_pending_on_block = false;
- up(&priv->async_sem);
- }
- if (priv->user_scan_cfg) {
- dev_dbg(priv->adapter->dev,
- "info: %s: sending scan results\n", __func__);
+ if (priv->scan_request) {
+ dev_dbg(adapter->dev, "info: notifying scan done\n");
cfg80211_scan_done(priv->scan_request, 0);
priv->scan_request = NULL;
- kfree(priv->user_scan_cfg);
- priv->user_scan_cfg = NULL;
+ } else {
+ priv->scan_aborting = false;
+ dev_dbg(adapter->dev, "info: scan already aborted\n");
}
} else {
- /* Get scan command from scan_pending_q and put to
- cmd_pending_q */
- cmd_node = list_first_entry(&adapter->scan_pending_q,
- struct cmd_ctrl_node, list);
- list_del(&cmd_node->list);
- spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
-
- mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);
+ if (priv->scan_aborting && !priv->scan_request) {
+ spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+ flags);
+ adapter->scan_delay_cnt = MWIFIEX_MAX_SCAN_DELAY_CNT;
+ mod_timer(&priv->scan_delay_timer, jiffies);
+ dev_dbg(priv->adapter->dev,
+ "info: %s: triggerring scan abort\n", __func__);
+ } else if (!mwifiex_wmm_lists_empty(adapter) &&
+ (priv->scan_request && (priv->scan_request->flags &
+ CFG80211_SCAN_FLAG_TX_ABORT))) {
+ spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+ flags);
+ adapter->scan_delay_cnt = 1;
+ mod_timer(&priv->scan_delay_timer, jiffies +
+ msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC));
+ dev_dbg(priv->adapter->dev,
+ "info: %s: deferring scan\n", __func__);
+ } else {
+ /* Get scan command from scan_pending_q and put to
+ cmd_pending_q */
+ cmd_node = list_first_entry(&adapter->scan_pending_q,
+ struct cmd_ctrl_node, list);
+ list_del(&cmd_node->list);
+ spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
+ flags);
+ mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
+ true);
+ }
}
-done:
return ret;
}
struct cfg80211_ssid *req_ssid)
{
struct mwifiex_adapter *adapter = priv->adapter;
- int ret = 0;
+ int ret;
struct mwifiex_user_scan_cfg *scan_cfg;
- if (!req_ssid)
- return -1;
-
if (adapter->scan_processing) {
- dev_dbg(adapter->dev, "cmd: Scan already in process...\n");
- return ret;
+ dev_err(adapter->dev, "cmd: Scan already in process...\n");
+ return -EBUSY;
}
if (priv->scan_block) {
- dev_dbg(adapter->dev,
+ dev_err(adapter->dev,
"cmd: Scan is blocked during association...\n");
- return ret;
+ return -EBUSY;
}
scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL);
__func__);
return -1;
}
- priv->scan_pending_on_block = true;
priv->adapter->scan_wait_q_woken = false;
if (!ret)
ret = mwifiex_wait_queue_complete(priv->adapter);
- if (ret == -1) {
- priv->scan_pending_on_block = false;
- up(&priv->async_sem);
- }
+ up(&priv->async_sem);
return ret;
}