summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/mwifiex
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/mwifiex')
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c31
-rw-r--r--drivers/net/wireless/mwifiex/cfp.c31
-rw-r--r--drivers/net/wireless/mwifiex/debugfs.c2
-rw-r--r--drivers/net/wireless/mwifiex/fw.h3
-rw-r--r--drivers/net/wireless/mwifiex/init.c2
-rw-r--r--drivers/net/wireless/mwifiex/ioctl.h3
-rw-r--r--drivers/net/wireless/mwifiex/join.c50
-rw-r--r--drivers/net/wireless/mwifiex/main.c106
-rw-r--r--drivers/net/wireless/mwifiex/main.h20
-rw-r--r--drivers/net/wireless/mwifiex/pcie.c3
-rw-r--r--drivers/net/wireless/mwifiex/scan.c63
-rw-r--r--drivers/net/wireless/mwifiex/sdio.c3
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmd.c2
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c87
14 files changed, 271 insertions, 135 deletions
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index c7e89188c350..c78ea873a63a 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -1162,6 +1162,17 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
priv->user_scan_cfg->num_ssids = request->n_ssids;
priv->user_scan_cfg->ssid_list = request->ssids;
+ if (request->ie && request->ie_len) {
+ for (i = 0; i < MWIFIEX_MAX_VSIE_NUM; i++) {
+ if (priv->vs_ie[i].mask != MWIFIEX_VSIE_MASK_CLEAR)
+ continue;
+ priv->vs_ie[i].mask = MWIFIEX_VSIE_MASK_SCAN;
+ memcpy(&priv->vs_ie[i].ie, request->ie,
+ request->ie_len);
+ break;
+ }
+ }
+
for (i = 0; i < request->n_channels; i++) {
chan = request->channels[i];
priv->user_scan_cfg->chan_list[i].chan_number = chan->hw_value;
@@ -1179,6 +1190,15 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev,
if (mwifiex_set_user_scan_ioctl(priv, priv->user_scan_cfg))
return -EFAULT;
+ if (request->ie && request->ie_len) {
+ for (i = 0; i < MWIFIEX_MAX_VSIE_NUM; i++) {
+ if (priv->vs_ie[i].mask == MWIFIEX_VSIE_MASK_SCAN) {
+ priv->vs_ie[i].mask = MWIFIEX_VSIE_MASK_CLEAR;
+ memset(&priv->vs_ie[i].ie, 0,
+ MWIFIEX_MAX_VSIE_LEN);
+ }
+ }
+ }
return 0;
}
@@ -1422,6 +1442,7 @@ int mwifiex_register_cfg80211(struct mwifiex_private *priv)
void *wdev_priv;
struct wireless_dev *wdev;
struct ieee80211_sta_ht_cap *ht_info;
+ u8 *country_code;
wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
if (!wdev) {
@@ -1438,6 +1459,7 @@ int mwifiex_register_cfg80211(struct mwifiex_private *priv)
}
wdev->iftype = NL80211_IFTYPE_STATION;
wdev->wiphy->max_scan_ssids = 10;
+ wdev->wiphy->max_scan_ie_len = MWIFIEX_MAX_VSIE_LEN;
wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
@@ -1460,8 +1482,8 @@ int mwifiex_register_cfg80211(struct mwifiex_private *priv)
memcpy(wdev->wiphy->perm_addr, priv->curr_addr, ETH_ALEN);
wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
- /* Reserve space for bss band information */
- wdev->wiphy->bss_priv_size = sizeof(u8);
+ /* Reserve space for mwifiex specific private data for BSS */
+ wdev->wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv);
wdev->wiphy->reg_notifier = mwifiex_reg_notifier;
@@ -1484,6 +1506,11 @@ int mwifiex_register_cfg80211(struct mwifiex_private *priv)
"info: successfully registered wiphy device\n");
}
+ country_code = mwifiex_11d_code_2_region(priv->adapter->region_code);
+ if (country_code && regulatory_hint(wdev->wiphy, country_code))
+ dev_err(priv->adapter->dev,
+ "%s: regulatory_hint failed\n", __func__);
+
priv->wdev = wdev;
return ret;
diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c
index 2fe1c33765b8..560871b0e236 100644
--- a/drivers/net/wireless/mwifiex/cfp.c
+++ b/drivers/net/wireless/mwifiex/cfp.c
@@ -71,6 +71,37 @@ u16 region_code_index[MWIFIEX_MAX_REGION_CODE] = { 0x10, 0x20, 0x30,
static u8 supported_rates_n[N_SUPPORTED_RATES] = { 0x02, 0x04, 0 };
+struct region_code_mapping {
+ u8 code;
+ u8 region[IEEE80211_COUNTRY_STRING_LEN];
+};
+
+static struct region_code_mapping region_code_mapping_t[] = {
+ { 0x10, "US " }, /* US FCC */
+ { 0x20, "CA " }, /* IC Canada */
+ { 0x30, "EU " }, /* ETSI */
+ { 0x31, "ES " }, /* Spain */
+ { 0x32, "FR " }, /* France */
+ { 0x40, "JP " }, /* Japan */
+ { 0x41, "JP " }, /* Japan */
+ { 0x50, "CN " }, /* China */
+};
+
+/* This function converts integer code to region string */
+u8 *mwifiex_11d_code_2_region(u8 code)
+{
+ u8 i;
+ u8 size = sizeof(region_code_mapping_t)/
+ sizeof(struct region_code_mapping);
+
+ /* Look for code in mapping table */
+ for (i = 0; i < size; i++)
+ if (region_code_mapping_t[i].code == code)
+ return region_code_mapping_t[i].region;
+
+ return NULL;
+}
+
/*
* This function maps an index in supported rates table into
* the corresponding data rate.
diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c
index 1a845074c52a..a870b5885c09 100644
--- a/drivers/net/wireless/mwifiex/debugfs.c
+++ b/drivers/net/wireless/mwifiex/debugfs.c
@@ -212,7 +212,7 @@ mwifiex_info_read(struct file *file, char __user *ubuf,
p += sprintf(p, "essid=\"%s\"\n", info.ssid.ssid);
p += sprintf(p, "bssid=\"%pM\"\n", info.bssid);
p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan);
- p += sprintf(p, "region_code = \"%02x\"\n", info.region_code);
+ p += sprintf(p, "country_code = \"%s\"\n", info.country_code);
netdev_for_each_mc_addr(ha, netdev)
p += sprintf(p, "multicast_address[%d]=\"%pM\"\n",
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index bb26114bdb96..6b15449a4cb7 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -104,6 +104,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define TLV_TYPE_RATE_SCOPE (PROPRIETARY_TLV_BASE_ID + 83)
#define TLV_TYPE_POWER_GROUP (PROPRIETARY_TLV_BASE_ID + 84)
#define TLV_TYPE_WAPI_IE (PROPRIETARY_TLV_BASE_ID + 94)
+#define TLV_TYPE_MGMT_IE (PROPRIETARY_TLV_BASE_ID + 105)
#define TLV_TYPE_AUTO_DS_PARAM (PROPRIETARY_TLV_BASE_ID + 113)
#define TLV_TYPE_PS_PARAM (PROPRIETARY_TLV_BASE_ID + 114)
@@ -818,7 +819,7 @@ struct host_cmd_ds_txpwr_cfg {
struct mwifiex_bcn_param {
u8 bssid[ETH_ALEN];
u8 rssi;
- __le32 timestamp[2];
+ __le64 timestamp;
__le16 beacon_period;
__le16 cap_info_bitmap;
} __packed;
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index 54bb4839b57c..0d55c5b542d7 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -131,6 +131,8 @@ static int mwifiex_init_priv(struct mwifiex_private *priv)
priv->wmm_qosinfo = 0;
priv->curr_bcn_buf = NULL;
priv->curr_bcn_size = 0;
+ priv->wps_ie = NULL;
+ priv->wps_ie_len = 0;
priv->scan_block = false;
diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h
index 99c06649f94c..f0f95524e96b 100644
--- a/drivers/net/wireless/mwifiex/ioctl.h
+++ b/drivers/net/wireless/mwifiex/ioctl.h
@@ -96,7 +96,7 @@ struct mwifiex_bss_info {
u32 bss_mode;
struct cfg80211_ssid ssid;
u32 bss_chan;
- u32 region_code;
+ u8 country_code[3];
u32 media_connected;
u32 max_power_level;
u32 min_power_level;
@@ -303,6 +303,7 @@ struct mwifiex_ds_misc_subsc_evt {
#define MWIFIEX_MAX_VSIE_LEN (256)
#define MWIFIEX_MAX_VSIE_NUM (8)
+#define MWIFIEX_VSIE_MASK_CLEAR 0x00
#define MWIFIEX_VSIE_MASK_SCAN 0x01
#define MWIFIEX_VSIE_MASK_ASSOC 0x02
#define MWIFIEX_VSIE_MASK_ADHOC 0x04
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c
index bca8b6d52273..8a390982463e 100644
--- a/drivers/net/wireless/mwifiex/join.c
+++ b/drivers/net/wireless/mwifiex/join.c
@@ -118,15 +118,15 @@ mwifiex_cmd_append_tsf_tlv(struct mwifiex_private *priv, u8 **buffer,
*buffer += sizeof(tsf_tlv.header);
/* TSF at the time when beacon/probe_response was received */
- tsf_val = cpu_to_le64(bss_desc->network_tsf);
+ tsf_val = cpu_to_le64(bss_desc->fw_tsf);
memcpy(*buffer, &tsf_val, sizeof(tsf_val));
*buffer += sizeof(tsf_val);
- memcpy(&tsf_val, bss_desc->time_stamp, sizeof(tsf_val));
+ tsf_val = cpu_to_le64(bss_desc->timestamp);
dev_dbg(priv->adapter->dev,
"info: %s: TSF offset calc: %016llx - %016llx\n",
- __func__, tsf_val, bss_desc->network_tsf);
+ __func__, bss_desc->timestamp, bss_desc->fw_tsf);
memcpy(*buffer, &tsf_val, sizeof(tsf_val));
*buffer += sizeof(tsf_val);
@@ -225,6 +225,48 @@ mwifiex_setup_rates_from_bssdesc(struct mwifiex_private *priv,
}
/*
+ * This function appends a WPS IE. It is called from the network join command
+ * preparation routine.
+ *
+ * If the IE buffer has been setup by the application, this routine appends
+ * the buffer as a WPS TLV type to the request.
+ */
+static int
+mwifiex_cmd_append_wps_ie(struct mwifiex_private *priv, u8 **buffer)
+{
+ int retLen = 0;
+ struct mwifiex_ie_types_header ie_header;
+
+ if (!buffer || !*buffer)
+ return 0;
+
+ /*
+ * If there is a wps ie buffer setup, append it to the return
+ * parameter buffer pointer.
+ */
+ if (priv->wps_ie_len) {
+ dev_dbg(priv->adapter->dev, "cmd: append wps ie %d to %p\n",
+ priv->wps_ie_len, *buffer);
+
+ /* Wrap the generic IE buffer with a pass through TLV type */
+ ie_header.type = cpu_to_le16(TLV_TYPE_MGMT_IE);
+ ie_header.len = cpu_to_le16(priv->wps_ie_len);
+ memcpy(*buffer, &ie_header, sizeof(ie_header));
+ *buffer += sizeof(ie_header);
+ retLen += sizeof(ie_header);
+
+ memcpy(*buffer, priv->wps_ie, priv->wps_ie_len);
+ *buffer += priv->wps_ie_len;
+ retLen += priv->wps_ie_len;
+
+ }
+
+ kfree(priv->wps_ie);
+ priv->wps_ie_len = 0;
+ return retLen;
+}
+
+/*
* This function appends a WAPI IE.
*
* This function is called from the network join command preparation routine.
@@ -480,6 +522,8 @@ int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
if (priv->sec_info.wapi_enabled && priv->wapi_ie_len)
mwifiex_cmd_append_wapi_ie(priv, &pos);
+ if (priv->wps.session_enable && priv->wps_ie_len)
+ mwifiex_cmd_append_wps_ie(priv, &pos);
mwifiex_cmd_append_generic_ie(priv, &pos);
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index 9d1b3ca6334b..245b7329e0c9 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -292,29 +292,28 @@ static void mwifiex_free_adapter(struct mwifiex_adapter *adapter)
}
/*
- * This function initializes the hardware and firmware.
+ * This function gets firmware and initializes it.
*
* The main initialization steps followed are -
* - Download the correct firmware to card
- * - Allocate and initialize the adapter structure
- * - Initialize the private structures
* - Issue the init commands to firmware
*/
-static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter)
+static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
{
- int ret, err;
+ int ret;
+ char fmt[64];
+ struct mwifiex_private *priv;
+ struct mwifiex_adapter *adapter = context;
struct mwifiex_fw_image fw;
- memset(&fw, 0, sizeof(struct mwifiex_fw_image));
-
- err = request_firmware(&adapter->firmware, adapter->fw_name,
- adapter->dev);
- if (err < 0) {
- dev_err(adapter->dev, "request_firmware() returned"
- " error code %#x\n", err);
- ret = -1;
+ if (!firmware) {
+ dev_err(adapter->dev,
+ "Failed to get firmware %s\n", adapter->fw_name);
goto done;
}
+
+ memset(&fw, 0, sizeof(struct mwifiex_fw_image));
+ adapter->firmware = firmware;
fw.fw_buf = (u8 *) adapter->firmware->data;
fw.fw_len = adapter->firmware->size;
@@ -335,17 +334,54 @@ static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter)
/* Wait for mwifiex_init to complete */
wait_event_interruptible(adapter->init_wait_q,
adapter->init_wait_q_woken);
- if (adapter->hw_status != MWIFIEX_HW_STATUS_READY) {
- ret = -1;
+ if (adapter->hw_status != MWIFIEX_HW_STATUS_READY)
goto done;
+
+ priv = adapter->priv[0];
+ if (mwifiex_register_cfg80211(priv) != 0) {
+ dev_err(adapter->dev, "cannot register with cfg80211\n");
+ goto err_init_fw;
+ }
+
+ rtnl_lock();
+ /* Create station interface by default */
+ if (!mwifiex_add_virtual_intf(priv->wdev->wiphy, "mlan%d",
+ NL80211_IFTYPE_STATION, NULL, NULL)) {
+ dev_err(adapter->dev, "cannot create default STA interface\n");
+ goto err_add_intf;
}
- ret = 0;
+ rtnl_unlock();
+
+ mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1);
+ dev_notice(adapter->dev, "driver_version = %s\n", fmt);
+ goto done;
+err_add_intf:
+ mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev);
+ rtnl_unlock();
+err_init_fw:
+ pr_debug("info: %s: unregister device\n", __func__);
+ adapter->if_ops.unregister_dev(adapter);
done:
- if (adapter->firmware)
- release_firmware(adapter->firmware);
- if (ret)
- ret = -1;
+ release_firmware(adapter->firmware);
+ complete(&adapter->fw_load);
+ return;
+}
+
+/*
+ * This function initializes the hardware and gets firmware.
+ */
+static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter)
+{
+ int ret;
+
+ init_completion(&adapter->fw_load);
+ ret = request_firmware_nowait(THIS_MODULE, 1, adapter->fw_name,
+ adapter->dev, GFP_KERNEL, adapter,
+ mwifiex_fw_dpc);
+ if (ret < 0)
+ dev_err(adapter->dev,
+ "request_firmware_nowait() returned error %d\n", ret);
return ret;
}
@@ -650,8 +686,6 @@ mwifiex_add_card(void *card, struct semaphore *sem,
struct mwifiex_if_ops *if_ops, u8 iface_type)
{
struct mwifiex_adapter *adapter;
- char fmt[64];
- struct mwifiex_private *priv;
if (down_interruptible(sem))
goto exit_sem_err;
@@ -692,37 +726,9 @@ mwifiex_add_card(void *card, struct semaphore *sem,
goto err_init_fw;
}
- priv = adapter->priv[0];
-
- if (mwifiex_register_cfg80211(priv) != 0) {
- dev_err(adapter->dev, "cannot register netdevice"
- " with cfg80211\n");
- goto err_init_fw;
- }
-
- rtnl_lock();
- /* Create station interface by default */
- if (!mwifiex_add_virtual_intf(priv->wdev->wiphy, "mlan%d",
- NL80211_IFTYPE_STATION, NULL, NULL)) {
- rtnl_unlock();
- dev_err(adapter->dev, "cannot create default station"
- " interface\n");
- goto err_add_intf;
- }
-
- rtnl_unlock();
-
up(sem);
-
- mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1);
- dev_notice(adapter->dev, "driver_version = %s\n", fmt);
-
return 0;
-err_add_intf:
- rtnl_lock();
- mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev);
- rtnl_unlock();
err_init_fw:
pr_debug("info: %s: unregister device\n", __func__);
adapter->if_ops.unregister_dev(adapter);
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index fcccf6b1373f..a4000f9608d5 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -260,8 +260,8 @@ struct mwifiex_bssdescriptor {
* BAND_A(0X04): 'a' band
*/
u16 bss_band;
- u64 network_tsf;
- u8 time_stamp[8];
+ u64 fw_tsf;
+ u64 timestamp;
union ieee_types_phy_param_set phy_param_set;
union ieee_types_ss_param_set ss_param_set;
u16 cap_info_bitmap;
@@ -407,6 +407,8 @@ struct mwifiex_private {
struct host_cmd_ds_802_11_key_material aes_key;
u8 wapi_ie[256];
u8 wapi_ie_len;
+ u8 *wps_ie;
+ u8 wps_ie_len;
u8 wmm_required;
u8 wmm_enabled;
u8 wmm_qosinfo;
@@ -520,6 +522,11 @@ struct cmd_ctrl_node {
u8 cmd_wait_q_woken;
};
+struct mwifiex_bss_priv {
+ u8 band;
+ u64 fw_tsf;
+};
+
struct mwifiex_if_ops {
int (*init_if) (struct mwifiex_adapter *);
void (*cleanup_if) (struct mwifiex_adapter *);
@@ -653,6 +660,7 @@ struct mwifiex_adapter {
u8 scan_wait_q_woken;
struct cmd_ctrl_node *cmd_queued;
spinlock_t queue_lock; /* lock for tx queues */
+ struct completion fw_load;
};
int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
@@ -950,13 +958,10 @@ int mwifiex_bss_set_channel(struct mwifiex_private *,
int mwifiex_get_bss_info(struct mwifiex_private *,
struct mwifiex_bss_info *);
int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
- u8 *bssid, s32 rssi, u8 *ie_buf,
- size_t ie_len, u16 beacon_period,
- u16 cap_info_bitmap, u8 band,
+ struct cfg80211_bss *bss,
struct mwifiex_bssdescriptor *bss_desc);
int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
- struct mwifiex_bssdescriptor *bss_entry,
- u8 *ie_buf, u32 ie_len);
+ struct mwifiex_bssdescriptor *bss_entry);
int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
struct mwifiex_bssdescriptor *bss_desc);
@@ -965,6 +970,7 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
u32 *flags, struct vif_params *params);
int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev);
+u8 *mwifiex_11d_code_2_region(u8 code);
#ifdef CONFIG_DEBUG_FS
void mwifiex_debugfs_init(void);
diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c
index 5867facd415d..13fbc4eb1595 100644
--- a/drivers/net/wireless/mwifiex/pcie.c
+++ b/drivers/net/wireless/mwifiex/pcie.c
@@ -119,6 +119,9 @@ static void mwifiex_pcie_remove(struct pci_dev *pdev)
if (!adapter || !adapter->priv_num)
return;
+ /* In case driver is removed when asynchronous FW load is in progress */
+ wait_for_completion(&adapter->fw_load);
+
if (user_rmmod) {
#ifdef CONFIG_PM
if (adapter->is_suspended)
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index ef84a1a6742f..74f045715723 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -1048,10 +1048,8 @@ mwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter,
* 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;
@@ -1073,10 +1071,8 @@ mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
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) {
@@ -1447,15 +1443,12 @@ int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
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;
/* Allocate and fill new bss descriptor */
bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor),
@@ -1465,16 +1458,7 @@ mwifiex_update_curr_bss_params(struct mwifiex_private *priv, u8 *bssid,
return -ENOMEM;
}
- beacon_ie = kmemdup(ie_buf, 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);
if (ret)
goto done;
@@ -1514,7 +1498,6 @@ mwifiex_update_curr_bss_params(struct mwifiex_private *priv, u8 *bssid,
done:
kfree(bss_desc);
- kfree(beacon_ie);
return 0;
}
@@ -1620,14 +1603,16 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
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 */
@@ -1671,6 +1656,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
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);
@@ -1710,14 +1696,13 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
/*
* 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;
@@ -1740,21 +1725,19 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) {
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");
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
index f8012e2b7f7c..1aa45c4295bb 100644
--- a/drivers/net/wireless/mwifiex/sdio.c
+++ b/drivers/net/wireless/mwifiex/sdio.c
@@ -123,6 +123,9 @@ mwifiex_sdio_remove(struct sdio_func *func)
if (!adapter || !adapter->priv_num)
return;
+ /* In case driver is removed when asynchronous FW load is in progress */
+ wait_for_completion(&adapter->fw_load);
+
if (user_rmmod) {
if (adapter->is_suspended)
mwifiex_sdio_resume(adapter->dev);
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index e90c34d9c63d..1f7110577b9d 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -988,7 +988,7 @@ mwifiex_cmd_802_11_subsc_evt(struct mwifiex_private *priv,
rssi_tlv->abs_value = subsc_evt_cfg->bcn_h_rssi_cfg.abs_value;
rssi_tlv->evt_freq = subsc_evt_cfg->bcn_h_rssi_cfg.evt_freq;
- dev_dbg(priv->adapter->dev, "Cfg Beacon Low Rssi event, "
+ dev_dbg(priv->adapter->dev, "Cfg Beacon High Rssi event, "
"RSSI:-%d dBm, Freq:%d\n",
subsc_evt_cfg->bcn_h_rssi_cfg.abs_value,
subsc_evt_cfg->bcn_h_rssi_cfg.evt_freq);
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index 8ba58d935328..58970e0f7d13 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -155,20 +155,29 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
* information.
*/
int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
- u8 *bssid, s32 rssi, u8 *ie_buf,
- size_t ie_len, u16 beacon_period,
- u16 cap_info_bitmap, u8 band,
+ struct cfg80211_bss *bss,
struct mwifiex_bssdescriptor *bss_desc)
{
int ret;
+ u8 *beacon_ie;
+ struct mwifiex_bss_priv *bss_priv = (void *)bss->priv;
- memcpy(bss_desc->mac_address, bssid, ETH_ALEN);
- bss_desc->rssi = rssi;
- bss_desc->beacon_buf = ie_buf;
- bss_desc->beacon_buf_size = ie_len;
- bss_desc->beacon_period = beacon_period;
- bss_desc->cap_info_bitmap = cap_info_bitmap;
- bss_desc->bss_band = band;
+ beacon_ie = kmemdup(bss->information_elements, bss->len_beacon_ies,
+ GFP_KERNEL);
+ if (!beacon_ie) {
+ dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n");
+ return -ENOMEM;
+ }
+
+ memcpy(bss_desc->mac_address, bss->bssid, ETH_ALEN);
+ bss_desc->rssi = bss->signal;
+ bss_desc->beacon_buf = beacon_ie;
+ bss_desc->beacon_buf_size = bss->len_beacon_ies;
+ bss_desc->beacon_period = bss->beacon_interval;
+ bss_desc->cap_info_bitmap = bss->capability;
+ bss_desc->bss_band = bss_priv->band;
+ bss_desc->fw_tsf = bss_priv->fw_tsf;
+ bss_desc->timestamp = bss->tsf;
if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) {
dev_dbg(priv->adapter->dev, "info: InterpretIE: AP WEP enabled\n");
bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
@@ -180,9 +189,9 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
else
bss_desc->bss_mode = NL80211_IFTYPE_STATION;
- ret = mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc,
- ie_buf, ie_len);
+ ret = mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc);
+ kfree(beacon_ie);
return ret;
}
@@ -197,7 +206,6 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
int ret;
struct mwifiex_adapter *adapter = priv->adapter;
struct mwifiex_bssdescriptor *bss_desc = NULL;
- u8 *beacon_ie = NULL;
priv->scan_block = false;
@@ -210,19 +218,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
return -ENOMEM;
}
- beacon_ie = kmemdup(bss->information_elements,
- bss->len_beacon_ies, 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, bss->bssid, bss->signal,
- beacon_ie, bss->len_beacon_ies,
- bss->beacon_interval,
- bss->capability,
- *(u8 *)bss->priv, bss_desc);
+ ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc);
if (ret)
goto done;
}
@@ -269,7 +265,6 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
(!mwifiex_ssid_cmp(&priv->curr_bss_params.bss_descriptor.
ssid, &bss_desc->ssid))) {
kfree(bss_desc);
- kfree(beacon_ie);
return 0;
}
@@ -304,7 +299,6 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
done:
kfree(bss_desc);
- kfree(beacon_ie);
return ret;
}
@@ -468,7 +462,8 @@ int mwifiex_get_bss_info(struct mwifiex_private *priv,
info->bss_chan = bss_desc->channel;
- info->region_code = adapter->region_code;
+ memcpy(info->country_code, priv->country_code,
+ IEEE80211_COUNTRY_STRING_LEN);
info->media_connected = priv->media_connected;
@@ -996,6 +991,39 @@ static int mwifiex_set_wapi_ie(struct mwifiex_private *priv,
}
/*
+ * IOCTL request handler to set/reset WPS IE.
+ *
+ * The supplied WPS IE is treated as a opaque buffer. Only the first field
+ * is checked to internally enable WPS. If buffer length is zero, the existing
+ * WPS IE is reset.
+ */
+static int mwifiex_set_wps_ie(struct mwifiex_private *priv,
+ u8 *ie_data_ptr, u16 ie_len)
+{
+ if (ie_len) {
+ priv->wps_ie = kzalloc(MWIFIEX_MAX_VSIE_LEN, GFP_KERNEL);
+ if (!priv->wps_ie)
+ return -ENOMEM;
+ if (ie_len > sizeof(priv->wps_ie)) {
+ dev_dbg(priv->adapter->dev,
+ "info: failed to copy WPS IE, too big\n");
+ kfree(priv->wps_ie);
+ return -1;
+ }
+ memcpy(priv->wps_ie, ie_data_ptr, ie_len);
+ priv->wps_ie_len = ie_len;
+ dev_dbg(priv->adapter->dev, "cmd: Set wps_ie_len=%d IE=%#x\n",
+ priv->wps_ie_len, priv->wps_ie[0]);
+ } else {
+ kfree(priv->wps_ie);
+ priv->wps_ie_len = ie_len;
+ dev_dbg(priv->adapter->dev,
+ "info: Reset wps_ie_len=%d\n", priv->wps_ie_len);
+ }
+ return 0;
+}
+
+/*
* IOCTL request handler to set WAPI key.
*
* This function prepares the correct firmware command and
@@ -1408,6 +1436,7 @@ mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr,
priv->wps.session_enable = true;
dev_dbg(priv->adapter->dev,
"info: WPS Session Enabled.\n");
+ ret = mwifiex_set_wps_ie(priv, ie_data_ptr, ie_len);
}
/* Append the passed data to the end of the