diff options
Diffstat (limited to 'drivers/net/wireless/mwifiex/sta_ioctl.c')
-rw-r--r-- | drivers/net/wireless/mwifiex/sta_ioctl.c | 295 |
1 files changed, 128 insertions, 167 deletions
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index c34ff8c4f4f..ea4a29b7e33 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -55,7 +55,9 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) { bool cancel_flag = false; int status = adapter->cmd_wait_q.status; + struct cmd_ctrl_node *cmd_queued = adapter->cmd_queued; + adapter->cmd_queued = NULL; dev_dbg(adapter->dev, "cmd pending\n"); atomic_inc(&adapter->cmd_pending); @@ -64,8 +66,8 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) /* Wait for completion */ wait_event_interruptible(adapter->cmd_wait_q.wait, - adapter->cmd_wait_q.condition); - if (!adapter->cmd_wait_q.condition) + *(cmd_queued->condition)); + if (!*(cmd_queued->condition)) cancel_flag = true; if (cancel_flag) { @@ -142,90 +144,146 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv, } /* + * This function fills bss descriptor structure using provided + * 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 mwifiex_bssdescriptor *bss_desc) +{ + int ret; + + 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; + 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; + } else { + bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL; + } + if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_IBSS) + bss_desc->bss_mode = NL80211_IFTYPE_ADHOC; + else + bss_desc->bss_mode = NL80211_IFTYPE_STATION; + + ret = mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc, + ie_buf, ie_len); + + return ret; +} + +/* * In Ad-Hoc mode, the IBSS is created if not found in scan list. * In both Ad-Hoc and infra mode, an deauthentication is performed * first. */ -int mwifiex_bss_start(struct mwifiex_private *priv, - struct mwifiex_ssid_bssid *ssid_bssid) +int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, + struct mwifiex_802_11_ssid *req_ssid) { int ret; struct mwifiex_adapter *adapter = priv->adapter; - s32 i = -1; + struct mwifiex_bssdescriptor *bss_desc = NULL; + u8 *beacon_ie = NULL; priv->scan_block = false; - if (!ssid_bssid) - return -1; + + if (bss) { + /* Allocate and fill new bss descriptor */ + bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor), + GFP_KERNEL); + if (!bss_desc) { + dev_err(priv->adapter->dev, " failed to alloc bss_desc\n"); + 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); + if (ret) + goto done; + } if (priv->bss_mode == NL80211_IFTYPE_STATION) { /* Infra mode */ ret = mwifiex_deauthenticate(priv, NULL); if (ret) - return ret; + goto done; - /* Search for the requested SSID in the scan table */ - if (ssid_bssid->ssid.ssid_len) - i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid, - NULL, NL80211_IFTYPE_STATION); - else - i = mwifiex_find_bssid_in_list(priv, - (u8 *) &ssid_bssid->bssid, - NL80211_IFTYPE_STATION); - if (i < 0) - return -1; + ret = mwifiex_check_network_compatibility(priv, bss_desc); + if (ret) + goto done; - dev_dbg(adapter->dev, - "info: SSID found in scan list ... associating...\n"); + dev_dbg(adapter->dev, "info: SSID found in scan list ... " + "associating...\n"); + + if (!netif_queue_stopped(priv->netdev)) + netif_stop_queue(priv->netdev); /* Clear any past association response stored for * application retrieval */ priv->assoc_rsp_size = 0; - ret = mwifiex_associate(priv, &adapter->scan_table[i]); - if (ret) - return ret; + ret = mwifiex_associate(priv, bss_desc); + if (bss) + cfg80211_put_bss(bss); } else { /* Adhoc mode */ /* If the requested SSID matches current SSID, return */ - if (ssid_bssid->ssid.ssid_len && + if (bss_desc && bss_desc->ssid.ssid_len && (!mwifiex_ssid_cmp (&priv->curr_bss_params.bss_descriptor.ssid, - &ssid_bssid->ssid))) + &bss_desc->ssid))) { + kfree(bss_desc); + kfree(beacon_ie); return 0; + } /* Exit Adhoc mode first */ dev_dbg(adapter->dev, "info: Sending Adhoc Stop\n"); ret = mwifiex_deauthenticate(priv, NULL); if (ret) - return ret; + goto done; priv->adhoc_is_link_sensed = false; - /* Search for the requested network in the scan table */ - if (ssid_bssid->ssid.ssid_len) - i = mwifiex_find_ssid_in_list(priv, - &ssid_bssid->ssid, NULL, - NL80211_IFTYPE_ADHOC); - else - i = mwifiex_find_bssid_in_list(priv, - (u8 *)&ssid_bssid->bssid, - NL80211_IFTYPE_ADHOC); + ret = mwifiex_check_network_compatibility(priv, bss_desc); + + if (!netif_queue_stopped(priv->netdev)) + netif_stop_queue(priv->netdev); - if (i >= 0) { + if (!ret) { dev_dbg(adapter->dev, "info: network found in scan" " list. Joining...\n"); - ret = mwifiex_adhoc_join(priv, &adapter->scan_table[i]); - if (ret) - return ret; + ret = mwifiex_adhoc_join(priv, bss_desc); + if (bss) + cfg80211_put_bss(bss); } else { dev_dbg(adapter->dev, "info: Network not found in " "the list, creating adhoc with ssid = %s\n", - ssid_bssid->ssid.ssid); - ret = mwifiex_adhoc_start(priv, &ssid_bssid->ssid); - if (ret) - return ret; + req_ssid->ssid); + ret = mwifiex_adhoc_start(priv, req_ssid); } } +done: + kfree(bss_desc); + kfree(beacon_ie); return ret; } @@ -235,8 +293,8 @@ int mwifiex_bss_start(struct mwifiex_private *priv, * This function prepares the correct firmware command and * issues it. */ -int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action, - int cmd_type, struct mwifiex_ds_hs_cfg *hs_cfg) +static int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action, + int cmd_type, struct mwifiex_ds_hs_cfg *hs_cfg) { struct mwifiex_adapter *adapter = priv->adapter; @@ -376,7 +434,6 @@ int mwifiex_get_bss_info(struct mwifiex_private *priv, { struct mwifiex_adapter *adapter = priv->adapter; struct mwifiex_bssdescriptor *bss_desc; - s32 tbl_idx; if (!info) return -1; @@ -394,17 +451,6 @@ int mwifiex_get_bss_info(struct mwifiex_private *priv, info->region_code = adapter->region_code; - /* Scan table index if connected */ - info->scan_table_idx = 0; - if (priv->media_connected) { - tbl_idx = - mwifiex_find_ssid_in_list(priv, &bss_desc->ssid, - bss_desc->mac_address, - priv->bss_mode); - if (tbl_idx >= 0) - info->scan_table_idx = tbl_idx; - } - info->media_connected = priv->media_connected; info->max_power_level = priv->max_tx_power_level; @@ -586,50 +632,6 @@ static int mwifiex_bss_ioctl_ibss_channel(struct mwifiex_private *priv, } /* - * IOCTL request handler to find a particular BSS. - * - * The BSS can be searched with either a BSSID or a SSID. If none of - * these are provided, just the best BSS (best RSSI) is returned. - */ -int mwifiex_bss_ioctl_find_bss(struct mwifiex_private *priv, - struct mwifiex_ssid_bssid *ssid_bssid) -{ - struct mwifiex_adapter *adapter = priv->adapter; - struct mwifiex_bssdescriptor *bss_desc; - u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; - u8 mac[ETH_ALEN]; - int i = 0; - - if (memcmp(ssid_bssid->bssid, zero_mac, sizeof(zero_mac))) { - i = mwifiex_find_bssid_in_list(priv, - (u8 *) ssid_bssid->bssid, - priv->bss_mode); - if (i < 0) { - memcpy(mac, ssid_bssid->bssid, sizeof(mac)); - dev_err(adapter->dev, "cannot find bssid %pM\n", mac); - return -1; - } - bss_desc = &adapter->scan_table[i]; - memcpy(&ssid_bssid->ssid, &bss_desc->ssid, - sizeof(struct mwifiex_802_11_ssid)); - } else if (ssid_bssid->ssid.ssid_len) { - i = mwifiex_find_ssid_in_list(priv, &ssid_bssid->ssid, NULL, - priv->bss_mode); - if (i < 0) { - dev_err(adapter->dev, "cannot find ssid %s\n", - ssid_bssid->ssid.ssid); - return -1; - } - bss_desc = &adapter->scan_table[i]; - memcpy(ssid_bssid->bssid, bss_desc->mac_address, ETH_ALEN); - } else { - return mwifiex_find_best_network(priv, ssid_bssid); - } - - return 0; -} - -/* * IOCTL request handler to change Ad-Hoc channel. * * This function allocates the IOCTL request buffer, fills it @@ -653,6 +655,9 @@ mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel) struct mwifiex_bss_info bss_info; struct mwifiex_ssid_bssid ssid_bssid; u16 curr_chan = 0; + struct cfg80211_bss *bss = NULL; + struct ieee80211_channel *chan; + enum ieee80211_band band; memset(&bss_info, 0, sizeof(bss_info)); @@ -688,12 +693,20 @@ mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel) ret = -1; goto done; } - /* Start/Join Adhoc network */ - memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); - memcpy(&ssid_bssid.ssid, &bss_info.ssid, - sizeof(struct mwifiex_802_11_ssid)); - ret = mwifiex_bss_start(priv, &ssid_bssid); + band = mwifiex_band_to_radio_type(priv->curr_bss_params.band); + chan = __ieee80211_get_channel(priv->wdev->wiphy, + ieee80211_channel_to_frequency(channel, band)); + + /* Find the BSS we want using available scan results */ + bss = cfg80211_get_bss(priv->wdev->wiphy, chan, bss_info.bssid, + bss_info.ssid.ssid, bss_info.ssid.ssid_len, + WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); + if (!bss) + wiphy_warn(priv->wdev->wiphy, "assoc: bss %pM not in scan results\n", + bss_info.bssid); + + ret = mwifiex_bss_start(priv, bss, &bss_info.ssid); done: return ret; } @@ -709,51 +722,9 @@ done: static int mwifiex_rate_ioctl_get_rate_value(struct mwifiex_private *priv, struct mwifiex_rate_cfg *rate_cfg) { - struct mwifiex_adapter *adapter = priv->adapter; - rate_cfg->is_rate_auto = priv->is_data_rate_auto; - if (!priv->media_connected) { - switch (adapter->config_bands) { - case BAND_B: - /* Return the lowest supported rate for B band */ - rate_cfg->rate = supported_rates_b[0] & 0x7f; - break; - case BAND_G: - case BAND_G | BAND_GN: - /* Return the lowest supported rate for G band */ - rate_cfg->rate = supported_rates_g[0] & 0x7f; - break; - case BAND_B | BAND_G: - case BAND_A | BAND_B | BAND_G: - case BAND_A | BAND_B: - case BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN: - case BAND_B | BAND_G | BAND_GN: - /* Return the lowest supported rate for BG band */ - rate_cfg->rate = supported_rates_bg[0] & 0x7f; - break; - case BAND_A: - case BAND_A | BAND_G: - case BAND_A | BAND_G | BAND_AN | BAND_GN: - case BAND_A | BAND_AN: - /* Return the lowest supported rate for A band */ - rate_cfg->rate = supported_rates_a[0] & 0x7f; - break; - case BAND_GN: - /* Return the lowest supported rate for N band */ - rate_cfg->rate = supported_rates_n[0] & 0x7f; - break; - default: - dev_warn(adapter->dev, "invalid band %#x\n", - adapter->config_bands); - break; - } - } else { - return mwifiex_send_cmd_sync(priv, - HostCmd_CMD_802_11_TX_RATE_QUERY, - HostCmd_ACT_GEN_GET, 0, NULL); - } - - return 0; + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_TX_RATE_QUERY, + HostCmd_ACT_GEN_GET, 0, NULL); } /* @@ -794,7 +765,7 @@ static int mwifiex_rate_ioctl_set_rate_value(struct mwifiex_private *priv, if ((rate[i] & 0x7f) == (rate_cfg->rate & 0x7f)) break; } - if (!rate[i] || (i == MWIFIEX_SUPPORTED_RATES)) { + if ((i == MWIFIEX_SUPPORTED_RATES) || !rate[i]) { dev_err(adapter->dev, "fixed data rate %#x is out " "of range\n", rate_cfg->rate); return -1; @@ -860,10 +831,10 @@ int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, ret = mwifiex_rate_ioctl_cfg(priv, rate); if (!ret) { - if (rate && rate->is_rate_auto) + if (rate->is_rate_auto) rate->rate = mwifiex_index_to_data_rate(priv->tx_rate, priv->tx_htinfo); - else if (rate) + else rate->rate = priv->data_rate; } else { ret = -1; @@ -1280,9 +1251,9 @@ int mwifiex_get_signal_info(struct mwifiex_private *priv, if (!status) { if (signal->selector & BCN_RSSI_AVG_MASK) - priv->w_stats.qual.level = signal->bcn_rssi_avg; + priv->qual_level = signal->bcn_rssi_avg; if (signal->selector & BCN_NF_AVG_MASK) - priv->w_stats.qual.noise = signal->bcn_nf_avg; + priv->qual_noise = signal->bcn_nf_avg; } return status; @@ -1341,18 +1312,8 @@ int mwifiex_get_stats_info(struct mwifiex_private *priv, struct mwifiex_ds_get_stats *log) { - int ret; - - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_GET_LOG, + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_GET_LOG, HostCmd_ACT_GEN_GET, 0, log); - - if (!ret) { - priv->w_stats.discard.fragment = log->fcs_error; - priv->w_stats.discard.retries = log->retry; - priv->w_stats.discard.misc = log->ack_failure; - } - - return ret; } /* @@ -1594,7 +1555,7 @@ mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len) { struct mwifiex_ds_misc_gen_ie gen_ie; - if (ie_len > IW_CUSTOM_MAX) + if (ie_len > IEEE_MAX_IE_SIZE) return -EFAULT; gen_ie.type = MWIFIEX_IE_TYPE_GEN_IE; |