diff options
Diffstat (limited to 'drivers/net/wireless/mwifiex/scan.c')
| -rw-r--r-- | drivers/net/wireless/mwifiex/scan.c | 2560 |
1 files changed, 940 insertions, 1620 deletions
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index 5c22860fb40..45c5b3450cf 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -28,7 +28,7 @@ /* 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 /* 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) \ @@ -125,7 +125,7 @@ mwifiex_is_rsn_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher) ieee_hdr.element_id == WLAN_EID_RSN))) { iebody = (struct ie_body *) (((u8 *) bss_desc->bcn_rsn_ie->data) + - RSN_GTK_OUI_OFFSET); + RSN_GTK_OUI_OFFSET); oui = &mwifiex_rsn_oui[cipher][0]; ret = mwifiex_search_oui_in_ie(iebody, oui); if (ret) @@ -148,8 +148,9 @@ mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher) struct ie_body *iebody; u8 ret = MWIFIEX_OUI_NOT_PRESENT; - if (((bss_desc->bcn_wpa_ie) && ((*(bss_desc->bcn_wpa_ie)). - vend_hdr.element_id == WLAN_EID_WPA))) { + if (((bss_desc->bcn_wpa_ie) && + ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id == + WLAN_EID_VENDOR_SPECIFIC))) { iebody = (struct ie_body *) bss_desc->bcn_wpa_ie->data; oui = &mwifiex_wpa_oui[cipher][0]; ret = mwifiex_search_oui_in_ie(iebody, oui); @@ -163,8 +164,7 @@ mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher) * This function compares two SSIDs and checks if they match. */ s32 -mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1, - struct mwifiex_802_11_ssid *ssid2) +mwifiex_ssid_cmp(struct cfg80211_ssid *ssid1, struct cfg80211_ssid *ssid2) { if (!ssid1 || !ssid2 || (ssid1->ssid_len != ssid2->ssid_len)) return -1; @@ -172,65 +172,12 @@ mwifiex_ssid_cmp(struct mwifiex_802_11_ssid *ssid1, } /* - * Sends IOCTL request to get the best BSS. - * - * This function allocates the IOCTL request buffer, fills it - * with requisite parameters and calls the IOCTL handler. - */ -int mwifiex_find_best_bss(struct mwifiex_private *priv, - struct mwifiex_ssid_bssid *ssid_bssid) -{ - struct mwifiex_ssid_bssid tmp_ssid_bssid; - u8 *mac; - - if (!ssid_bssid) - return -1; - - memcpy(&tmp_ssid_bssid, ssid_bssid, - sizeof(struct mwifiex_ssid_bssid)); - - if (!mwifiex_bss_ioctl_find_bss(priv, &tmp_ssid_bssid)) { - memcpy(ssid_bssid, &tmp_ssid_bssid, - sizeof(struct mwifiex_ssid_bssid)); - mac = (u8 *) &ssid_bssid->bssid; - dev_dbg(priv->adapter->dev, "cmd: found network: ssid=%s," - " %pM\n", ssid_bssid->ssid.ssid, mac); - return 0; - } - - return -1; -} - -/* - * 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; - - priv->adapter->cmd_wait_q.condition = false; - - status = mwifiex_scan_networks(priv, scan_req); - if (!status) - status = mwifiex_wait_queue_complete(priv->adapter); - - return status; -} - -/* * This function checks if wapi is enabled in driver and scanned network is * compatible with it. */ static bool -mwifiex_is_network_compatible_for_wapi(struct mwifiex_private *priv, - struct mwifiex_bssdescriptor *bss_desc) +mwifiex_is_bss_wapi(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) { if (priv->sec_info.wapi_enabled && (bss_desc->bcn_wapi_ie && @@ -246,19 +193,17 @@ mwifiex_is_network_compatible_for_wapi(struct mwifiex_private *priv, * scanned network is compatible with it. */ static bool -mwifiex_is_network_compatible_for_no_sec(struct mwifiex_private *priv, - struct mwifiex_bssdescriptor *bss_desc) +mwifiex_is_bss_no_sec(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) { - if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED - && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled - && ((!bss_desc->bcn_wpa_ie) || + if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled && + !priv->sec_info.wpa2_enabled && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id != - WLAN_EID_WPA)) - && ((!bss_desc->bcn_rsn_ie) || + WLAN_EID_VENDOR_SPECIFIC)) && + ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id != - WLAN_EID_RSN)) - && !priv->sec_info.encryption_mode - && !bss_desc->privacy) { + WLAN_EID_RSN)) && + !priv->sec_info.encryption_mode && !bss_desc->privacy) { return true; } return false; @@ -269,12 +214,11 @@ mwifiex_is_network_compatible_for_no_sec(struct mwifiex_private *priv, * is compatible with it. */ static bool -mwifiex_is_network_compatible_for_static_wep(struct mwifiex_private *priv, - struct mwifiex_bssdescriptor *bss_desc) +mwifiex_is_bss_static_wep(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) { - if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_ENABLED - && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled - && bss_desc->privacy) { + if (priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled && + !priv->sec_info.wpa2_enabled && bss_desc->privacy) { return true; } return false; @@ -285,30 +229,28 @@ mwifiex_is_network_compatible_for_static_wep(struct mwifiex_private *priv, * compatible with it. */ static bool -mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv, - struct mwifiex_bssdescriptor *bss_desc, - int index) +mwifiex_is_bss_wpa(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) { - if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED - && priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled - && ((bss_desc->bcn_wpa_ie) && ((*(bss_desc->bcn_wpa_ie)).vend_hdr. - element_id == WLAN_EID_WPA)) + if (!priv->sec_info.wep_enabled && priv->sec_info.wpa_enabled && + !priv->sec_info.wpa2_enabled && ((bss_desc->bcn_wpa_ie) && + ((*(bss_desc->bcn_wpa_ie)). + vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC)) /* * Privacy bit may NOT be set in some APs like * LinkSys WRT54G && bss_desc->privacy */ ) { - dev_dbg(priv->adapter->dev, "info: %s: WPA: index=%d" + dev_dbg(priv->adapter->dev, "info: %s: WPA:" " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s " - "EncMode=%#x privacy=%#x\n", __func__, index, + "EncMode=%#x privacy=%#x\n", __func__, (bss_desc->bcn_wpa_ie) ? (*(bss_desc->bcn_wpa_ie)). vend_hdr.element_id : 0, (bss_desc->bcn_rsn_ie) ? (*(bss_desc->bcn_rsn_ie)). ieee_hdr.element_id : 0, - (priv->sec_info.wep_status == - MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d", + (priv->sec_info.wep_enabled) ? "e" : "d", (priv->sec_info.wpa_enabled) ? "e" : "d", (priv->sec_info.wpa2_enabled) ? "e" : "d", priv->sec_info.encryption_mode, @@ -323,30 +265,28 @@ mwifiex_is_network_compatible_for_wpa(struct mwifiex_private *priv, * compatible with it. */ static bool -mwifiex_is_network_compatible_for_wpa2(struct mwifiex_private *priv, - struct mwifiex_bssdescriptor *bss_desc, - int index) +mwifiex_is_bss_wpa2(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) { - if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED - && !priv->sec_info.wpa_enabled && priv->sec_info.wpa2_enabled - && ((bss_desc->bcn_rsn_ie) && ((*(bss_desc->bcn_rsn_ie)).ieee_hdr. - element_id == WLAN_EID_RSN)) - /* - * Privacy bit may NOT be set in some APs like - * LinkSys WRT54G && bss_desc->privacy - */ - ) { - dev_dbg(priv->adapter->dev, "info: %s: WPA2: index=%d" + if (!priv->sec_info.wep_enabled && + !priv->sec_info.wpa_enabled && + priv->sec_info.wpa2_enabled && + ((bss_desc->bcn_rsn_ie) && + ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id == WLAN_EID_RSN))) { + /* + * Privacy bit may NOT be set in some APs like + * LinkSys WRT54G && bss_desc->privacy + */ + dev_dbg(priv->adapter->dev, "info: %s: WPA2: " " wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s " - "EncMode=%#x privacy=%#x\n", __func__, index, + "EncMode=%#x privacy=%#x\n", __func__, (bss_desc->bcn_wpa_ie) ? (*(bss_desc->bcn_wpa_ie)). vend_hdr.element_id : 0, (bss_desc->bcn_rsn_ie) ? (*(bss_desc->bcn_rsn_ie)). ieee_hdr.element_id : 0, - (priv->sec_info.wep_status == - MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d", + (priv->sec_info.wep_enabled) ? "e" : "d", (priv->sec_info.wpa_enabled) ? "e" : "d", (priv->sec_info.wpa2_enabled) ? "e" : "d", priv->sec_info.encryption_mode, @@ -361,17 +301,17 @@ mwifiex_is_network_compatible_for_wpa2(struct mwifiex_private *priv, * compatible with it. */ static bool -mwifiex_is_network_compatible_for_adhoc_aes(struct mwifiex_private *priv, - struct mwifiex_bssdescriptor *bss_desc) +mwifiex_is_bss_adhoc_aes(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) { - if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED - && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled - && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr. - element_id != WLAN_EID_WPA)) - && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr. - element_id != WLAN_EID_RSN)) - && !priv->sec_info.encryption_mode - && bss_desc->privacy) { + if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled && + !priv->sec_info.wpa2_enabled && + ((!bss_desc->bcn_wpa_ie) || + ((*(bss_desc->bcn_wpa_ie)). + vend_hdr.element_id != WLAN_EID_VENDOR_SPECIFIC)) && + ((!bss_desc->bcn_rsn_ie) || + ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id != WLAN_EID_RSN)) && + !priv->sec_info.encryption_mode && bss_desc->privacy) { return true; } return false; @@ -382,22 +322,21 @@ mwifiex_is_network_compatible_for_adhoc_aes(struct mwifiex_private *priv, * is compatible with it. */ static bool -mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv, - struct mwifiex_bssdescriptor *bss_desc, - int index) +mwifiex_is_bss_dynamic_wep(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) { - if (priv->sec_info.wep_status == MWIFIEX_802_11_WEP_DISABLED - && !priv->sec_info.wpa_enabled && !priv->sec_info.wpa2_enabled - && ((!bss_desc->bcn_wpa_ie) || ((*(bss_desc->bcn_wpa_ie)).vend_hdr. - element_id != WLAN_EID_WPA)) - && ((!bss_desc->bcn_rsn_ie) || ((*(bss_desc->bcn_rsn_ie)).ieee_hdr. - element_id != WLAN_EID_RSN)) - && priv->sec_info.encryption_mode - && bss_desc->privacy) { + if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled && + !priv->sec_info.wpa2_enabled && + ((!bss_desc->bcn_wpa_ie) || + ((*(bss_desc->bcn_wpa_ie)). + vend_hdr.element_id != WLAN_EID_VENDOR_SPECIFIC)) && + ((!bss_desc->bcn_rsn_ie) || + ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id != WLAN_EID_RSN)) && + priv->sec_info.encryption_mode && bss_desc->privacy) { dev_dbg(priv->adapter->dev, "info: %s: dynamic " - "WEP: index=%d wpa_ie=%#x wpa2_ie=%#x " + "WEP: wpa_ie=%#x wpa2_ie=%#x " "EncMode=%#x privacy=%#x\n", - __func__, index, + __func__, (bss_desc->bcn_wpa_ie) ? (*(bss_desc->bcn_wpa_ie)). vend_hdr.element_id : 0, @@ -430,51 +369,55 @@ mwifiex_is_network_compatible_for_dynamic_wep(struct mwifiex_private *priv, * Compatibility is not matched while roaming, except for mode. */ static s32 -mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode) +mwifiex_is_network_compatible(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc, u32 mode) { struct mwifiex_adapter *adapter = priv->adapter; - struct mwifiex_bssdescriptor *bss_desc; - bss_desc = &adapter->scan_table[index]; bss_desc->disable_11n = false; /* Don't check for compatibility if roaming */ - if (priv->media_connected && (priv->bss_mode == NL80211_IFTYPE_STATION) - && (bss_desc->bss_mode == NL80211_IFTYPE_STATION)) - return index; + if (priv->media_connected && + (priv->bss_mode == NL80211_IFTYPE_STATION) && + (bss_desc->bss_mode == NL80211_IFTYPE_STATION)) + return 0; if (priv->wps.session_enable) { dev_dbg(adapter->dev, "info: return success directly in WPS period\n"); - return index; + return 0; } - if (mwifiex_is_network_compatible_for_wapi(priv, bss_desc)) { + if (bss_desc->chan_sw_ie_present) { + dev_err(adapter->dev, + "Don't connect to AP with WLAN_EID_CHANNEL_SWITCH\n"); + return -1; + } + + if (mwifiex_is_bss_wapi(priv, bss_desc)) { dev_dbg(adapter->dev, "info: return success for WAPI AP\n"); - return index; + return 0; } if (bss_desc->bss_mode == mode) { - if (mwifiex_is_network_compatible_for_no_sec(priv, bss_desc)) { + if (mwifiex_is_bss_no_sec(priv, bss_desc)) { /* No security */ - return index; - } else if (mwifiex_is_network_compatible_for_static_wep(priv, - bss_desc)) { + return 0; + } else if (mwifiex_is_bss_static_wep(priv, bss_desc)) { /* Static WEP enabled */ dev_dbg(adapter->dev, "info: Disable 11n in WEP mode.\n"); bss_desc->disable_11n = true; - return index; - } else if (mwifiex_is_network_compatible_for_wpa(priv, bss_desc, - index)) { + return 0; + } else if (mwifiex_is_bss_wpa(priv, bss_desc)) { /* WPA enabled */ - if (((priv->adapter->config_bands & BAND_GN - || priv->adapter->config_bands & BAND_AN) - && bss_desc->bcn_ht_cap) - && !mwifiex_is_wpa_oui_present(bss_desc, - CIPHER_SUITE_CCMP)) { - - if (mwifiex_is_wpa_oui_present(bss_desc, - CIPHER_SUITE_TKIP)) { + if (((priv->adapter->config_bands & BAND_GN || + priv->adapter->config_bands & BAND_AN) && + bss_desc->bcn_ht_cap) && + !mwifiex_is_wpa_oui_present(bss_desc, + CIPHER_SUITE_CCMP)) { + + if (mwifiex_is_wpa_oui_present + (bss_desc, CIPHER_SUITE_TKIP)) { dev_dbg(adapter->dev, "info: Disable 11n if AES " "is not supported by AP\n"); @@ -483,18 +426,17 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode) return -1; } } - return index; - } else if (mwifiex_is_network_compatible_for_wpa2(priv, - bss_desc, index)) { + return 0; + } else if (mwifiex_is_bss_wpa2(priv, bss_desc)) { /* WPA2 enabled */ - if (((priv->adapter->config_bands & BAND_GN - || priv->adapter->config_bands & BAND_AN) - && bss_desc->bcn_ht_cap) - && !mwifiex_is_rsn_oui_present(bss_desc, - CIPHER_SUITE_CCMP)) { - - if (mwifiex_is_rsn_oui_present(bss_desc, - CIPHER_SUITE_TKIP)) { + if (((priv->adapter->config_bands & BAND_GN || + priv->adapter->config_bands & BAND_AN) && + bss_desc->bcn_ht_cap) && + !mwifiex_is_rsn_oui_present(bss_desc, + CIPHER_SUITE_CCMP)) { + + if (mwifiex_is_rsn_oui_present + (bss_desc, CIPHER_SUITE_TKIP)) { dev_dbg(adapter->dev, "info: Disable 11n if AES " "is not supported by AP\n"); @@ -503,33 +445,27 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode) return -1; } } - return index; - } else if (mwifiex_is_network_compatible_for_adhoc_aes(priv, - bss_desc)) { + return 0; + } else if (mwifiex_is_bss_adhoc_aes(priv, bss_desc)) { /* Ad-hoc AES enabled */ - return index; - } else if (mwifiex_is_network_compatible_for_dynamic_wep(priv, - bss_desc, index)) { + return 0; + } else if (mwifiex_is_bss_dynamic_wep(priv, bss_desc)) { /* Dynamic WEP enabled */ - return index; + return 0; } /* Security doesn't match */ - dev_dbg(adapter->dev, "info: %s: failed: index=%d " - "wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s EncMode" - "=%#x privacy=%#x\n", - __func__, index, - (bss_desc->bcn_wpa_ie) ? - (*(bss_desc->bcn_wpa_ie)).vend_hdr. - element_id : 0, - (bss_desc->bcn_rsn_ie) ? - (*(bss_desc->bcn_rsn_ie)).ieee_hdr. - element_id : 0, - (priv->sec_info.wep_status == - MWIFIEX_802_11_WEP_ENABLED) ? "e" : "d", - (priv->sec_info.wpa_enabled) ? "e" : "d", - (priv->sec_info.wpa2_enabled) ? "e" : "d", - priv->sec_info.encryption_mode, bss_desc->privacy); + dev_dbg(adapter->dev, + "info: %s: failed: wpa_ie=%#x wpa2_ie=%#x WEP=%s " + "WPA=%s WPA2=%s EncMode=%#x privacy=%#x\n", __func__, + (bss_desc->bcn_wpa_ie) ? + (*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id : 0, + (bss_desc->bcn_rsn_ie) ? + (*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id : 0, + (priv->sec_info.wep_enabled) ? "e" : "d", + (priv->sec_info.wpa_enabled) ? "e" : "d", + (priv->sec_info.wpa2_enabled) ? "e" : "d", + priv->sec_info.encryption_mode, bss_desc->privacy); return -1; } @@ -538,72 +474,25 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv, u32 index, u32 mode) } /* - * This function finds the best SSID in the scan list. - * - * It searches the scan table for the best SSID that also matches the current - * adapter network preference (mode, security etc.). - */ -static s32 -mwifiex_find_best_network_in_list(struct mwifiex_private *priv) -{ - struct mwifiex_adapter *adapter = priv->adapter; - u32 mode = priv->bss_mode; - s32 best_net = -1; - s32 best_rssi = 0; - u32 i; - - dev_dbg(adapter->dev, "info: num of BSSIDs = %d\n", - adapter->num_in_scan_table); - - for (i = 0; i < adapter->num_in_scan_table; i++) { - switch (mode) { - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_ADHOC: - if (mwifiex_is_network_compatible(priv, i, mode) >= 0) { - if (SCAN_RSSI(adapter->scan_table[i].rssi) > - best_rssi) { - best_rssi = SCAN_RSSI(adapter-> - scan_table[i].rssi); - best_net = i; - } - } - break; - case NL80211_IFTYPE_UNSPECIFIED: - default: - if (SCAN_RSSI(adapter->scan_table[i].rssi) > - best_rssi) { - best_rssi = SCAN_RSSI(adapter->scan_table[i]. - rssi); - best_net = i; - } - break; - } - } - - return best_net; -} - -/* * This function creates a channel list for the driver to scan, based * on region/band information. * * 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, - struct mwifiex_chan_scan_param_set - *scan_chan_list, - u8 filtered_scan) + const struct mwifiex_user_scan_cfg + *user_scan_in, + struct mwifiex_chan_scan_param_set + *scan_chan_list, + u8 filtered_scan) { enum ieee80211_band band; struct ieee80211_supported_band *sband; struct ieee80211_channel *ch; struct mwifiex_adapter *adapter = priv->adapter; int chan_idx = 0, i; - u8 scan_type; for (band = 0; (band < IEEE80211_NUM_BANDS) ; band++) { @@ -612,24 +501,25 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv, sband = priv->wdev->wiphy->bands[band]; - for (i = 0; (i < sband->n_channels) ; i++, chan_idx++) { + for (i = 0; (i < sband->n_channels) ; i++) { ch = &sband->channels[i]; if (ch->flags & IEEE80211_CHAN_DISABLED) continue; scan_chan_list[chan_idx].radio_type = band; - scan_type = ch->flags & IEEE80211_CHAN_PASSIVE_SCAN; + if (user_scan_in && - user_scan_in->chan_list[0].scan_time) + user_scan_in->chan_list[0].scan_time) scan_chan_list[chan_idx].max_scan_time = cpu_to_le16((u16) user_scan_in-> chan_list[0].scan_time); - else if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE) + else if (ch->flags & IEEE80211_CHAN_NO_IR) scan_chan_list[chan_idx].max_scan_time = cpu_to_le16(adapter->passive_scan_time); else scan_chan_list[chan_idx].max_scan_time = cpu_to_le16(adapter->active_scan_time); - if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE) + + if (ch->flags & IEEE80211_CHAN_NO_IR) scan_chan_list[chan_idx].chan_scan_mode_bitmap |= MWIFIEX_PASSIVE_SCAN; else @@ -643,9 +533,42 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv, scan_chan_list[chan_idx].chan_scan_mode_bitmap |= MWIFIEX_DISABLE_CHAN_FILT; } + chan_idx++; } } + return chan_idx; +} + +/* This function appends rate TLV to scan config command. */ +static int +mwifiex_append_rate_tlv(struct mwifiex_private *priv, + struct mwifiex_scan_cmd_config *scan_cfg_out, + u8 radio) +{ + struct mwifiex_ie_types_rates_param_set *rates_tlv; + u8 rates[MWIFIEX_SUPPORTED_RATES], *tlv_pos; + u32 rates_size; + + memset(rates, 0, sizeof(rates)); + + tlv_pos = (u8 *)scan_cfg_out->tlv_buf + scan_cfg_out->tlv_buf_len; + + if (priv->scan_request) + rates_size = mwifiex_get_rates_from_cfg80211(priv, rates, + radio); + else + rates_size = mwifiex_get_supported_rates(priv, rates); + + dev_dbg(priv->adapter->dev, "info: SCAN_CMD: Rates size = %d\n", + rates_size); + rates_tlv = (struct mwifiex_ie_types_rates_param_set *)tlv_pos; + rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES); + rates_tlv->header.len = cpu_to_le16((u16) rates_size); + memcpy(rates_tlv->rates, rates, rates_size); + scan_cfg_out->tlv_buf_len += sizeof(rates_tlv->header) + rates_size; + + return rates_size; } /* @@ -665,13 +588,16 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv, *chan_tlv_out, struct mwifiex_chan_scan_param_set *scan_chan_list) { + struct mwifiex_adapter *adapter = priv->adapter; int ret = 0; struct mwifiex_chan_scan_param_set *tmp_chan_list; struct mwifiex_chan_scan_param_set *start_chan; - - u32 tlv_idx; + struct cmd_ctrl_node *cmd_node, *tmp_node; + unsigned long flags; + u32 tlv_idx, rates_size, cmd_no; u32 total_scan_time; u32 done_early; + u8 radio_type; if (!scan_cfg_out || !chan_tlv_out || !scan_chan_list) { dev_dbg(priv->adapter->dev, @@ -680,6 +606,9 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv, return -1; } + /* Check csa channel expiry before preparing scan list */ + mwifiex_11h_get_csa_closed_channel(priv); + chan_tlv_out->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); /* Set the temp channel struct pointer to the start of the desired @@ -693,6 +622,7 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv, tlv_idx = 0; total_scan_time = 0; + radio_type = 0; chan_tlv_out->header.len = 0; start_chan = tmp_chan_list; done_early = false; @@ -706,19 +636,25 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv, * - 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) { + while (tlv_idx < max_chan_per_scan && + tmp_chan_list->chan_number && !done_early) { + if (tmp_chan_list->chan_number == priv->csa_chan) { + tmp_chan_list++; + continue; + } + + radio_type = tmp_chan_list->radio_type; dev_dbg(priv->adapter->dev, "info: Scan: Chan(%3d), Radio(%d)," " Mode(%d, %d), Dur(%d)\n", - tmp_chan_list->chan_number, - tmp_chan_list->radio_type, - tmp_chan_list->chan_scan_mode_bitmap - & MWIFIEX_PASSIVE_SCAN, - (tmp_chan_list->chan_scan_mode_bitmap - & MWIFIEX_DISABLE_CHAN_FILT) >> 1, - le16_to_cpu(tmp_chan_list->max_scan_time)); + tmp_chan_list->chan_number, + tmp_chan_list->radio_type, + tmp_chan_list->chan_scan_mode_bitmap + & MWIFIEX_PASSIVE_SCAN, + (tmp_chan_list->chan_scan_mode_bitmap + & MWIFIEX_DISABLE_CHAN_FILT) >> 1, + le16_to_cpu(tmp_chan_list->max_scan_time)); /* Copy the current channel TLV to the command being prepared */ @@ -728,9 +664,8 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv, /* Increment the TLV header length by the size appended */ - chan_tlv_out->header.len = - cpu_to_le16(le16_to_cpu(chan_tlv_out->header.len) + - (sizeof(chan_tlv_out->chan_scan_param))); + le16_add_cpu(&chan_tlv_out->header.len, + sizeof(chan_tlv_out->chan_scan_param)); /* * The tlv buffer length is set to the number of bytes @@ -760,9 +695,10 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv, /* 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)) + 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 @@ -772,9 +708,10 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv, /* 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)) + if (!filtered_scan && + (tmp_chan_list->chan_number == 1 || + tmp_chan_list->chan_number == 6 || + tmp_chan_list->chan_number == 11)) done_early = true; } @@ -788,15 +725,41 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv, break; } + rates_size = mwifiex_append_rate_tlv(priv, scan_cfg_out, + radio_type); + priv->adapter->scan_channels = start_chan; /* Send the scan command to the firmware with the specified cfg */ - ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SCAN, - HostCmd_ACT_GEN_SET, 0, - scan_cfg_out); - if (ret) + if (priv->adapter->ext_scan) + cmd_no = HostCmd_CMD_802_11_SCAN_EXT; + else + cmd_no = HostCmd_CMD_802_11_SCAN; + + ret = mwifiex_send_cmd(priv, cmd_no, HostCmd_ACT_GEN_SET, + 0, scan_cfg_out, false); + + /* rate IE is updated per scan command but same starting + * pointer is used each time so that rate IE from earlier + * scan_cfg_out->buf is overwritten with new one. + */ + scan_cfg_out->tlv_buf_len -= + sizeof(struct mwifiex_ie_types_header) + rates_size; + + if (ret) { + spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); + list_for_each_entry_safe(cmd_node, tmp_node, + &adapter->scan_pending_q, + list) { + list_del(&cmd_node->list); + cmd_node->wait_q_enabled = false; + mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + } + spin_unlock_irqrestore(&adapter->scan_pending_q_lock, + flags); break; + } } if (ret) @@ -826,33 +789,29 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv, * If the number of probes is not set, adapter default setting is used. */ static void -mwifiex_scan_setup_scan_config(struct mwifiex_private *priv, - const struct mwifiex_user_scan_cfg *user_scan_in, - struct mwifiex_scan_cmd_config *scan_cfg_out, - struct mwifiex_ie_types_chan_list_param_set - **chan_list_out, - struct mwifiex_chan_scan_param_set - *scan_chan_list, - u8 *max_chan_per_scan, u8 *filtered_scan, - u8 *scan_current_only) +mwifiex_config_scan(struct mwifiex_private *priv, + const struct mwifiex_user_scan_cfg *user_scan_in, + struct mwifiex_scan_cmd_config *scan_cfg_out, + struct mwifiex_ie_types_chan_list_param_set **chan_list_out, + struct mwifiex_chan_scan_param_set *scan_chan_list, + u8 *max_chan_per_scan, u8 *filtered_scan, + u8 *scan_current_only) { struct mwifiex_adapter *adapter = priv->adapter; struct mwifiex_ie_types_num_probes *num_probes_tlv; struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv; - struct mwifiex_ie_types_rates_param_set *rates_tlv; - const u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; + struct mwifiex_ie_types_bssid_list *bssid_tlv; u8 *tlv_pos; u32 num_probes; u32 ssid_len; u32 chan_idx; + u32 chan_num; u32 scan_type; u16 scan_dur; u8 channel; u8 radio_type; - u32 ssid_idx; + int i; u8 ssid_filter; - u8 rates[MWIFIEX_SUPPORTED_RATES]; - u32 rates_size; struct mwifiex_ie_types_htcap *ht_cap; /* The tlv_buf_len is calculated for each scan command. The TLVs added @@ -904,14 +863,19 @@ mwifiex_scan_setup_scan_config(struct mwifiex_private *priv, user_scan_in->specific_bssid, sizeof(scan_cfg_out->specific_bssid)); - for (ssid_idx = 0; - ((ssid_idx < ARRAY_SIZE(user_scan_in->ssid_list)) - && (*user_scan_in->ssid_list[ssid_idx].ssid - || user_scan_in->ssid_list[ssid_idx].max_len)); - ssid_idx++) { + if (adapter->ext_scan && + !is_zero_ether_addr(scan_cfg_out->specific_bssid)) { + bssid_tlv = + (struct mwifiex_ie_types_bssid_list *)tlv_pos; + bssid_tlv->header.type = cpu_to_le16(TLV_TYPE_BSSID); + bssid_tlv->header.len = cpu_to_le16(ETH_ALEN); + memcpy(bssid_tlv->bssid, user_scan_in->specific_bssid, + ETH_ALEN); + tlv_pos += sizeof(struct mwifiex_ie_types_bssid_list); + } - ssid_len = strlen(user_scan_in->ssid_list[ssid_idx]. - ssid) + 1; + for (i = 0; i < user_scan_in->num_ssids; i++) { + ssid_len = user_scan_in->ssid_list[i].ssid_len; wildcard_ssid_tlv = (struct mwifiex_ie_types_wildcard_ssid_params *) @@ -921,18 +885,27 @@ mwifiex_scan_setup_scan_config(struct mwifiex_private *priv, wildcard_ssid_tlv->header.len = cpu_to_le16( (u16) (ssid_len + sizeof(wildcard_ssid_tlv-> max_ssid_length))); - wildcard_ssid_tlv->max_ssid_length = - user_scan_in->ssid_list[ssid_idx].max_len; + + /* + * max_ssid_length = 0 tells firmware to perform + * specific scan for the SSID filled, whereas + * max_ssid_length = IEEE80211_MAX_SSID_LEN is for + * wildcard scan. + */ + if (ssid_len) + wildcard_ssid_tlv->max_ssid_length = 0; + else + wildcard_ssid_tlv->max_ssid_length = + IEEE80211_MAX_SSID_LEN; memcpy(wildcard_ssid_tlv->ssid, - user_scan_in->ssid_list[ssid_idx].ssid, - ssid_len); + user_scan_in->ssid_list[i].ssid, ssid_len); tlv_pos += (sizeof(wildcard_ssid_tlv->header) + le16_to_cpu(wildcard_ssid_tlv->header.len)); - dev_dbg(adapter->dev, "info: scan: ssid_list[%d]: %s, %d\n", - ssid_idx, wildcard_ssid_tlv->ssid, + dev_dbg(adapter->dev, "info: scan: ssid[%d]: %s, %d\n", + i, wildcard_ssid_tlv->ssid, wildcard_ssid_tlv->max_ssid_length); /* Empty wildcard ssid with a maxlen will match many or @@ -941,7 +914,6 @@ mwifiex_scan_setup_scan_config(struct mwifiex_private *priv, filtered. */ if (!ssid_len && wildcard_ssid_tlv->max_ssid_length) ssid_filter = false; - } /* @@ -950,9 +922,8 @@ mwifiex_scan_setup_scan_config(struct mwifiex_private *priv, * truncate scan results. That is not an issue with an SSID * or BSSID filter applied to the scan results in the firmware. */ - if ((ssid_idx && ssid_filter) - || memcmp(scan_cfg_out->specific_bssid, &zero_mac, - sizeof(zero_mac))) + if ((i && ssid_filter) || + !is_zero_ether_addr(scan_cfg_out->specific_bssid)) *filtered_scan = true; } else { scan_cfg_out->bss_mode = (u8) adapter->scan_mode; @@ -966,14 +937,14 @@ mwifiex_scan_setup_scan_config(struct mwifiex_private *priv, 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 */ if (num_probes) { dev_dbg(adapter->dev, "info: scan: num_probes = %d\n", - num_probes); + num_probes); num_probes_tlv = (struct mwifiex_ie_types_num_probes *) tlv_pos; num_probes_tlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES); @@ -986,22 +957,9 @@ mwifiex_scan_setup_scan_config(struct mwifiex_private *priv, } - /* Append rates tlv */ - memset(rates, 0, sizeof(rates)); - - rates_size = mwifiex_get_supported_rates(priv, rates); - - rates_tlv = (struct mwifiex_ie_types_rates_param_set *) tlv_pos; - rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES); - rates_tlv->header.len = cpu_to_le16((u16) rates_size); - memcpy(rates_tlv->rates, rates, rates_size); - tlv_pos += sizeof(rates_tlv->header) + rates_size; - - dev_dbg(adapter->dev, "info: SCAN_CMD: Rates size = %d\n", rates_size); - - if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info) - && (priv->adapter->config_bands & BAND_GN - || priv->adapter->config_bands & BAND_AN)) { + if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info) && + (priv->adapter->config_bands & BAND_GN || + priv->adapter->config_bands & BAND_AN)) { ht_cap = (struct mwifiex_ie_types_htcap *) tlv_pos; memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap)); ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); @@ -1009,7 +967,7 @@ mwifiex_scan_setup_scan_config(struct mwifiex_private *priv, cpu_to_le16(sizeof(struct ieee80211_ht_cap)); radio_type = mwifiex_band_to_radio_type(priv->adapter->config_bands); - mwifiex_fill_cap_info(priv, radio_type, ht_cap); + mwifiex_fill_cap_info(priv, radio_type, &ht_cap->ht_cap); tlv_pos += sizeof(struct mwifiex_ie_types_htcap); } @@ -1030,8 +988,8 @@ mwifiex_scan_setup_scan_config(struct mwifiex_private *priv, dev_dbg(adapter->dev, "info: Scan: Using supplied channel list\n"); for (chan_idx = 0; - chan_idx < MWIFIEX_USER_SCAN_CHAN_MAX - && user_scan_in->chan_list[chan_idx].chan_number; + chan_idx < MWIFIEX_USER_SCAN_CHAN_MAX && + user_scan_in->chan_list[chan_idx].chan_number; chan_idx++) { channel = user_scan_in->chan_list[chan_idx].chan_number; @@ -1052,6 +1010,11 @@ mwifiex_scan_setup_scan_config(struct mwifiex_private *priv, chan_idx)->chan_scan_mode_bitmap &= ~MWIFIEX_PASSIVE_SCAN; + if (*filtered_scan) + (scan_chan_list + + chan_idx)->chan_scan_mode_bitmap + |= MWIFIEX_DISABLE_CHAN_FILT; + if (user_scan_in->chan_list[chan_idx].scan_time) { scan_dur = (u16) user_scan_in-> chan_list[chan_idx].scan_time; @@ -1071,21 +1034,28 @@ mwifiex_scan_setup_scan_config(struct mwifiex_private *priv, } /* Check if we are only scanning the current channel */ - if ((chan_idx == 1) - && (user_scan_in->chan_list[0].chan_number - == priv->curr_bss_params.bss_descriptor.channel)) { + if ((chan_idx == 1) && + (user_scan_in->chan_list[0].chan_number == + priv->curr_bss_params.bss_descriptor.channel)) { *scan_current_only = true; 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); + "info: Scan: Creating full region channel list\n"); + 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 1 to avoid any traffic delay/loss. + */ + if (priv->media_connected) + *max_chan_per_scan = 1; } /* @@ -1113,7 +1083,7 @@ mwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter, *tlv_data = NULL; dev_dbg(adapter->dev, "info: SCAN_RESP: tlv_buf_size = %d\n", - tlv_buf_size); + tlv_buf_size); while (tlv_buf_left >= sizeof(struct mwifiex_ie_types_header)) { @@ -1130,14 +1100,12 @@ mwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter, case TLV_TYPE_TSFTIMESTAMP: dev_dbg(adapter->dev, "info: SCAN_RESP: TSF " "timestamp TLV, len = %d\n", tlv_len); - *tlv_data = (struct mwifiex_ie_types_data *) - current_tlv; + *tlv_data = current_tlv; break; case TLV_TYPE_CHANNELBANDLIST: dev_dbg(adapter->dev, "info: SCAN_RESP: channel" " band list TLV, len = %d\n", tlv_len); - *tlv_data = (struct mwifiex_ie_types_data *) - current_tlv; + *tlv_data = current_tlv; break; default: dev_err(adapter->dev, @@ -1161,34 +1129,11 @@ mwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter, } /* - * This function interprets a BSS scan response returned from the firmware. - * - * The various fixed fields and IEs are parsed and passed back for a BSS - * probe response or beacon from scan command. Information is recorded as - * needed in the scan table for that entry. - * - * The following IE types are recognized and parsed - - * - SSID - * - Supported rates - * - FH parameters set - * - DS parameters set - * - CF parameters set - * - IBSS parameters set - * - ERP information - * - Extended supported rates - * - Vendor specific (221) - * - RSN IE - * - WAPI IE - * - HT capability - * - HT operation - * - BSS Coexistence 20/40 - * - Extended capability - * - Overlapping BSS scan parameters + * This function parses provided beacon buffer and updates + * respective fields in bss descriptor structure. */ -static int -mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter, - struct mwifiex_bssdescriptor *bss_entry, - u8 **beacon_info, u32 *bytes_left) +int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, + struct mwifiex_bssdescriptor *bss_entry) { int ret = 0; u8 element_id; @@ -1196,135 +1141,42 @@ mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter, struct ieee_types_ds_param_set *ds_param_set; struct ieee_types_cf_param_set *cf_param_set; struct ieee_types_ibss_param_set *ibss_param_set; - __le16 beacon_interval; - __le16 capabilities; u8 *current_ptr; u8 *rate; u8 element_len; u16 total_ie_len; u8 bytes_to_copy; u8 rate_size; - u16 beacon_size; u8 found_data_rate_ie; - u32 bytes_left_for_current_beacon; + u32 bytes_left; struct ieee_types_vendor_specific *vendor_ie; const u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 }; const u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 }; found_data_rate_ie = false; rate_size = 0; - beacon_size = 0; - - if (*bytes_left >= sizeof(beacon_size)) { - /* Extract & convert beacon size from the command buffer */ - memcpy(&beacon_size, *beacon_info, sizeof(beacon_size)); - *bytes_left -= sizeof(beacon_size); - *beacon_info += sizeof(beacon_size); - } - - if (!beacon_size || beacon_size > *bytes_left) { - *beacon_info += *bytes_left; - *bytes_left = 0; - return -1; - } - - /* Initialize the current working beacon pointer for this BSS - iteration */ - current_ptr = *beacon_info; - - /* Advance the return beacon pointer past the current beacon */ - *beacon_info += beacon_size; - *bytes_left -= beacon_size; - - bytes_left_for_current_beacon = beacon_size; - - memcpy(bss_entry->mac_address, current_ptr, ETH_ALEN); - dev_dbg(adapter->dev, "info: InterpretIE: AP MAC Addr: %pM\n", - bss_entry->mac_address); - - current_ptr += ETH_ALEN; - bytes_left_for_current_beacon -= ETH_ALEN; - - if (bytes_left_for_current_beacon < 12) { - dev_err(adapter->dev, "InterpretIE: not enough bytes left\n"); - return -1; - } - - /* - * Next 4 fields are RSSI, time stamp, beacon interval, - * and capability information - */ - - /* RSSI is 1 byte long */ - bss_entry->rssi = (s32) (*current_ptr); - dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%02X\n", *current_ptr); - current_ptr += 1; - bytes_left_for_current_beacon -= 1; - - /* - * The RSSI is not part of the beacon/probe response. After we have - * advanced current_ptr past the RSSI field, save the remaining - * data for use at the application layer - */ - bss_entry->beacon_buf = current_ptr; - bss_entry->beacon_buf_size = bytes_left_for_current_beacon; - - /* Time stamp is 8 bytes long */ - memcpy(bss_entry->time_stamp, current_ptr, 8); - current_ptr += 8; - bytes_left_for_current_beacon -= 8; - - /* Beacon interval is 2 bytes long */ - memcpy(&beacon_interval, current_ptr, 2); - bss_entry->beacon_period = le16_to_cpu(beacon_interval); - current_ptr += 2; - bytes_left_for_current_beacon -= 2; - - /* Capability information is 2 bytes long */ - memcpy(&capabilities, current_ptr, 2); - dev_dbg(adapter->dev, "info: InterpretIE: capabilities=0x%X\n", - capabilities); - bss_entry->cap_info_bitmap = le16_to_cpu(capabilities); - current_ptr += 2; - bytes_left_for_current_beacon -= 2; - - /* Rest of the current buffer are IE's */ - dev_dbg(adapter->dev, "info: InterpretIE: IELength for this AP = %d\n", - bytes_left_for_current_beacon); - - if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) { - dev_dbg(adapter->dev, "info: InterpretIE: AP WEP enabled\n"); - bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; - } else { - bss_entry->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL; - } - - if (bss_entry->cap_info_bitmap & WLAN_CAPABILITY_IBSS) - bss_entry->bss_mode = NL80211_IFTYPE_ADHOC; - else - bss_entry->bss_mode = NL80211_IFTYPE_STATION; - + current_ptr = bss_entry->beacon_buf; + bytes_left = bss_entry->beacon_buf_size; /* Process variable IE */ - while (bytes_left_for_current_beacon >= 2) { + while (bytes_left >= 2) { element_id = *current_ptr; element_len = *(current_ptr + 1); total_ie_len = element_len + sizeof(struct ieee_types_header); - if (bytes_left_for_current_beacon < total_ie_len) { + if (bytes_left < total_ie_len) { dev_err(adapter->dev, "err: InterpretIE: in processing" " IE, bytes left < IE length\n"); - bytes_left_for_current_beacon = 0; - ret = -1; - continue; + return -1; } switch (element_id) { case WLAN_EID_SSID: bss_entry->ssid.ssid_len = element_len; memcpy(bss_entry->ssid.ssid, (current_ptr + 2), element_len); - dev_dbg(adapter->dev, "info: InterpretIE: ssid: %-32s\n", - bss_entry->ssid.ssid); + dev_dbg(adapter->dev, + "info: InterpretIE: ssid: %-32s\n", + bss_entry->ssid.ssid); break; case WLAN_EID_SUPP_RATES: @@ -1376,6 +1228,19 @@ mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter, bss_entry->erp_flags = *(current_ptr + 2); break; + case WLAN_EID_PWR_CONSTRAINT: + bss_entry->local_constraint = *(current_ptr + 2); + bss_entry->sensed_11h = true; + break; + + case WLAN_EID_CHANNEL_SWITCH: + bss_entry->chan_sw_ie_present = true; + case WLAN_EID_PWR_CAPABILITY: + case WLAN_EID_TPC_REPORT: + case WLAN_EID_QUIET: + bss_entry->sensed_11h = true; + break; + case WLAN_EID_EXT_SUPP_RATES: /* * Only process extended supported rate @@ -1412,13 +1277,13 @@ mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter, bss_entry->bcn_wpa_ie = (struct ieee_types_vendor_specific *) current_ptr; - bss_entry->wpa_offset = (u16) (current_ptr - - bss_entry->beacon_buf); + bss_entry->wpa_offset = (u16) + (current_ptr - bss_entry->beacon_buf); } else if (!memcmp(vendor_ie->vend_hdr.oui, wmm_oui, sizeof(wmm_oui))) { if (total_ie_len == - sizeof(struct ieee_types_wmm_parameter) - || total_ie_len == + sizeof(struct ieee_types_wmm_parameter) || + total_ie_len == sizeof(struct ieee_types_wmm_info)) /* * Only accept and copy the WMM IE if @@ -1449,34 +1314,46 @@ mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter, sizeof(struct ieee_types_header) - bss_entry->beacon_buf); break; - case WLAN_EID_HT_INFORMATION: - bss_entry->bcn_ht_info = (struct ieee80211_ht_info *) - (current_ptr + + case WLAN_EID_HT_OPERATION: + bss_entry->bcn_ht_oper = + (struct ieee80211_ht_operation *)(current_ptr + sizeof(struct ieee_types_header)); bss_entry->ht_info_offset = (u16) (current_ptr + sizeof(struct ieee_types_header) - bss_entry->beacon_buf); break; + case WLAN_EID_VHT_CAPABILITY: + bss_entry->disable_11ac = false; + bss_entry->bcn_vht_cap = + (void *)(current_ptr + + sizeof(struct ieee_types_header)); + bss_entry->vht_cap_offset = + (u16)((u8 *)bss_entry->bcn_vht_cap - + bss_entry->beacon_buf); + break; + case WLAN_EID_VHT_OPERATION: + bss_entry->bcn_vht_oper = + (void *)(current_ptr + + sizeof(struct ieee_types_header)); + bss_entry->vht_info_offset = + (u16)((u8 *)bss_entry->bcn_vht_oper - + bss_entry->beacon_buf); + break; case WLAN_EID_BSS_COEX_2040: - bss_entry->bcn_bss_co_2040 = (u8 *) (current_ptr + - sizeof(struct ieee_types_header)); - bss_entry->bss_co_2040_offset = (u16) (current_ptr + - sizeof(struct ieee_types_header) - - bss_entry->beacon_buf); + bss_entry->bcn_bss_co_2040 = current_ptr; + bss_entry->bss_co_2040_offset = + (u16) (current_ptr - bss_entry->beacon_buf); break; case WLAN_EID_EXT_CAPABILITY: - bss_entry->bcn_ext_cap = (u8 *) (current_ptr + - sizeof(struct ieee_types_header)); - bss_entry->ext_cap_offset = (u16) (current_ptr + - sizeof(struct ieee_types_header) - - bss_entry->beacon_buf); + bss_entry->bcn_ext_cap = current_ptr; + bss_entry->ext_cap_offset = + (u16) (current_ptr - bss_entry->beacon_buf); break; - case WLAN_EID_OVERLAP_BSS_SCAN_PARAM: - bss_entry->bcn_obss_scan = - (struct ieee_types_obss_scan_param *) - current_ptr; - bss_entry->overlap_bss_offset = (u16) (current_ptr - - bss_entry->beacon_buf); + case WLAN_EID_OPMODE_NOTIF: + bss_entry->oper_mode = (void *)current_ptr; + bss_entry->oper_mode_offset = + (u16)((u8 *)bss_entry->oper_mode - + bss_entry->beacon_buf); break; default: break; @@ -1485,577 +1362,13 @@ mwifiex_interpret_bss_desc_with_ie(struct mwifiex_adapter *adapter, current_ptr += element_len + 2; /* Need to account for IE ID and IE Len */ - bytes_left_for_current_beacon -= (element_len + 2); + bytes_left -= (element_len + 2); - } /* while (bytes_left_for_current_beacon > 2) */ + } /* while (bytes_left > 2) */ return ret; } /* - * This function adjusts the pointers used in beacon buffers to reflect - * shifts. - * - * The memory allocated for beacon buffers is of fixed sizes where all the - * saved beacons must be stored. New beacons are added in the free portion - * of this memory, space permitting; while duplicate beacon buffers are - * placed at the same start location. However, since duplicate beacon - * buffers may not match the size of the old one, all the following buffers - * in the memory must be shifted to either make space, or to fill up freed - * up space. - * - * This function is used to update the beacon buffer pointers that are past - * an existing beacon buffer that is updated with a new one of different - * size. The pointers are shifted by a fixed amount, either forward or - * backward. - * - * the following pointers in every affected beacon buffers are changed, if - * present - - * - WPA IE pointer - * - RSN IE pointer - * - WAPI IE pointer - * - HT capability IE pointer - * - HT information IE pointer - * - BSS coexistence 20/40 IE pointer - * - Extended capability IE pointer - * - Overlapping BSS scan parameter IE pointer - */ -static void -mwifiex_adjust_beacon_buffer_ptrs(struct mwifiex_private *priv, u8 advance, - u8 *bcn_store, u32 rem_bcn_size, - u32 num_of_ent) -{ - struct mwifiex_adapter *adapter = priv->adapter; - u32 adj_idx; - for (adj_idx = 0; adj_idx < num_of_ent; adj_idx++) { - if (adapter->scan_table[adj_idx].beacon_buf > bcn_store) { - - if (advance) - adapter->scan_table[adj_idx].beacon_buf += - rem_bcn_size; - else - adapter->scan_table[adj_idx].beacon_buf -= - rem_bcn_size; - - if (adapter->scan_table[adj_idx].bcn_wpa_ie) - adapter->scan_table[adj_idx].bcn_wpa_ie = - (struct ieee_types_vendor_specific *) - (adapter->scan_table[adj_idx].beacon_buf + - adapter->scan_table[adj_idx].wpa_offset); - if (adapter->scan_table[adj_idx].bcn_rsn_ie) - adapter->scan_table[adj_idx].bcn_rsn_ie = - (struct ieee_types_generic *) - (adapter->scan_table[adj_idx].beacon_buf + - adapter->scan_table[adj_idx].rsn_offset); - if (adapter->scan_table[adj_idx].bcn_wapi_ie) - adapter->scan_table[adj_idx].bcn_wapi_ie = - (struct ieee_types_generic *) - (adapter->scan_table[adj_idx].beacon_buf + - adapter->scan_table[adj_idx].wapi_offset); - if (adapter->scan_table[adj_idx].bcn_ht_cap) - adapter->scan_table[adj_idx].bcn_ht_cap = - (struct ieee80211_ht_cap *) - (adapter->scan_table[adj_idx].beacon_buf + - adapter->scan_table[adj_idx].ht_cap_offset); - - if (adapter->scan_table[adj_idx].bcn_ht_info) - adapter->scan_table[adj_idx].bcn_ht_info = - (struct ieee80211_ht_info *) - (adapter->scan_table[adj_idx].beacon_buf + - adapter->scan_table[adj_idx].ht_info_offset); - if (adapter->scan_table[adj_idx].bcn_bss_co_2040) - adapter->scan_table[adj_idx].bcn_bss_co_2040 = - (u8 *) - (adapter->scan_table[adj_idx].beacon_buf + - adapter->scan_table[adj_idx].bss_co_2040_offset); - if (adapter->scan_table[adj_idx].bcn_ext_cap) - adapter->scan_table[adj_idx].bcn_ext_cap = - (u8 *) - (adapter->scan_table[adj_idx].beacon_buf + - adapter->scan_table[adj_idx].ext_cap_offset); - if (adapter->scan_table[adj_idx].bcn_obss_scan) - adapter->scan_table[adj_idx].bcn_obss_scan = - (struct ieee_types_obss_scan_param *) - (adapter->scan_table[adj_idx].beacon_buf + - adapter->scan_table[adj_idx].overlap_bss_offset); - } - } -} - -/* - * This function updates the pointers used in beacon buffer for given bss - * descriptor to reflect shifts - * - * Following pointers are updated - * - WPA IE pointer - * - RSN IE pointer - * - WAPI IE pointer - * - HT capability IE pointer - * - HT information IE pointer - * - BSS coexistence 20/40 IE pointer - * - Extended capability IE pointer - * - Overlapping BSS scan parameter IE pointer - */ -static void -mwifiex_update_beacon_buffer_ptrs(struct mwifiex_bssdescriptor *beacon) -{ - if (beacon->bcn_wpa_ie) - beacon->bcn_wpa_ie = (struct ieee_types_vendor_specific *) - (beacon->beacon_buf + beacon->wpa_offset); - if (beacon->bcn_rsn_ie) - beacon->bcn_rsn_ie = (struct ieee_types_generic *) - (beacon->beacon_buf + beacon->rsn_offset); - if (beacon->bcn_wapi_ie) - beacon->bcn_wapi_ie = (struct ieee_types_generic *) - (beacon->beacon_buf + beacon->wapi_offset); - if (beacon->bcn_ht_cap) - beacon->bcn_ht_cap = (struct ieee80211_ht_cap *) - (beacon->beacon_buf + beacon->ht_cap_offset); - if (beacon->bcn_ht_info) - beacon->bcn_ht_info = (struct ieee80211_ht_info *) - (beacon->beacon_buf + beacon->ht_info_offset); - if (beacon->bcn_bss_co_2040) - beacon->bcn_bss_co_2040 = (u8 *) (beacon->beacon_buf + - beacon->bss_co_2040_offset); - if (beacon->bcn_ext_cap) - beacon->bcn_ext_cap = (u8 *) (beacon->beacon_buf + - beacon->ext_cap_offset); - if (beacon->bcn_obss_scan) - beacon->bcn_obss_scan = (struct ieee_types_obss_scan_param *) - (beacon->beacon_buf + beacon->overlap_bss_offset); -} - -/* - * This function stores a beacon or probe response for a BSS returned - * in the scan. - * - * This stores a new scan response or an update for a previous scan response. - * New entries need to verify that they do not exceed the total amount of - * memory allocated for the table. - * - * Replacement entries need to take into consideration the amount of space - * currently allocated for the beacon/probe response and adjust the entry - * as needed. - * - * A small amount of extra pad (SCAN_BEACON_ENTRY_PAD) is generally reserved - * for an entry in case it is a beacon since a probe response for the - * network will by larger per the standard. This helps to reduce the - * amount of memory copying to fit a new probe response into an entry - * already occupied by a network's previously stored beacon. - */ -static void -mwifiex_ret_802_11_scan_store_beacon(struct mwifiex_private *priv, - u32 beacon_idx, u32 num_of_ent, - struct mwifiex_bssdescriptor *new_beacon) -{ - struct mwifiex_adapter *adapter = priv->adapter; - u8 *bcn_store; - u32 new_bcn_size; - u32 old_bcn_size; - u32 bcn_space; - - if (adapter->scan_table[beacon_idx].beacon_buf) { - - new_bcn_size = new_beacon->beacon_buf_size; - old_bcn_size = adapter->scan_table[beacon_idx].beacon_buf_size; - bcn_space = adapter->scan_table[beacon_idx].beacon_buf_size_max; - bcn_store = adapter->scan_table[beacon_idx].beacon_buf; - - /* Set the max to be the same as current entry unless changed - below */ - new_beacon->beacon_buf_size_max = bcn_space; - if (new_bcn_size == old_bcn_size) { - /* - * Beacon is the same size as the previous entry. - * Replace the previous contents with the scan result - */ - memcpy(bcn_store, new_beacon->beacon_buf, - new_beacon->beacon_buf_size); - - } else if (new_bcn_size <= bcn_space) { - /* - * New beacon size will fit in the amount of space - * we have previously allocated for it - */ - - /* Copy the new beacon buffer entry over the old one */ - memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size); - - /* - * If the old beacon size was less than the maximum - * we had alloted for the entry, and the new entry - * is even smaller, reset the max size to the old - * beacon entry and compress the storage space - * (leaving a new pad space of (old_bcn_size - - * new_bcn_size). - */ - if (old_bcn_size < bcn_space - && new_bcn_size <= old_bcn_size) { - /* - * Old Beacon size is smaller than the alloted - * storage size. Shrink the alloted storage - * space. - */ - dev_dbg(adapter->dev, "info: AppControl:" - " smaller duplicate beacon " - "(%d), old = %d, new = %d, space = %d," - "left = %d\n", - beacon_idx, old_bcn_size, new_bcn_size, - bcn_space, - (int)(sizeof(adapter->bcn_buf) - - (adapter->bcn_buf_end - - adapter->bcn_buf))); - - /* - * memmove (since the memory overlaps) the - * data after the beacon we just stored to the - * end of the current beacon. This cleans up - * any unused space the old larger beacon was - * using in the buffer - */ - memmove(bcn_store + old_bcn_size, - bcn_store + bcn_space, - adapter->bcn_buf_end - (bcn_store + - bcn_space)); - - /* - * Decrement the end pointer by the difference - * between the old larger size and the new - * smaller size since we are using less space - * due to the new beacon being smaller - */ - adapter->bcn_buf_end -= - (bcn_space - old_bcn_size); - - /* Set the maximum storage size to the old - beacon size */ - new_beacon->beacon_buf_size_max = old_bcn_size; - - /* Adjust beacon buffer pointers that are past - the current */ - mwifiex_adjust_beacon_buffer_ptrs(priv, 0, - bcn_store, (bcn_space - old_bcn_size), - num_of_ent); - } - } else if (adapter->bcn_buf_end + (new_bcn_size - bcn_space) - < (adapter->bcn_buf + sizeof(adapter->bcn_buf))) { - /* - * Beacon is larger than space previously allocated - * (bcn_space) and there is enough space left in the - * beaconBuffer to store the additional data - */ - dev_dbg(adapter->dev, "info: AppControl:" - " larger duplicate beacon (%d), " - "old = %d, new = %d, space = %d, left = %d\n", - beacon_idx, old_bcn_size, new_bcn_size, - bcn_space, - (int)(sizeof(adapter->bcn_buf) - - (adapter->bcn_buf_end - - adapter->bcn_buf))); - - /* - * memmove (since the memory overlaps) the data - * after the beacon we just stored to the end of - * the current beacon. This moves the data for - * the beacons after this further in memory to - * make space for the new larger beacon we are - * about to copy in. - */ - memmove(bcn_store + new_bcn_size, - bcn_store + bcn_space, - adapter->bcn_buf_end - (bcn_store + bcn_space)); - - /* Copy the new beacon buffer entry over the old one */ - memcpy(bcn_store, new_beacon->beacon_buf, new_bcn_size); - - /* Move the beacon end pointer by the amount of new - beacon data we are adding */ - adapter->bcn_buf_end += (new_bcn_size - bcn_space); - - /* - * This entry is bigger than the alloted max space - * previously reserved. Increase the max space to - * be equal to the new beacon size - */ - new_beacon->beacon_buf_size_max = new_bcn_size; - - /* Adjust beacon buffer pointers that are past the - current */ - mwifiex_adjust_beacon_buffer_ptrs(priv, 1, bcn_store, - (new_bcn_size - bcn_space), - num_of_ent); - } else { - /* - * Beacon is larger than the previously allocated space, - * but there is not enough free space to store the - * additional data. - */ - dev_err(adapter->dev, "AppControl: larger duplicate " - " beacon (%d), old = %d new = %d, space = %d," - " left = %d\n", beacon_idx, old_bcn_size, - new_bcn_size, bcn_space, - (int)(sizeof(adapter->bcn_buf) - - (adapter->bcn_buf_end - adapter->bcn_buf))); - - /* Storage failure, keep old beacon intact */ - new_beacon->beacon_buf_size = old_bcn_size; - if (new_beacon->bcn_wpa_ie) - new_beacon->wpa_offset = - adapter->scan_table[beacon_idx]. - wpa_offset; - if (new_beacon->bcn_rsn_ie) - new_beacon->rsn_offset = - adapter->scan_table[beacon_idx]. - rsn_offset; - if (new_beacon->bcn_wapi_ie) - new_beacon->wapi_offset = - adapter->scan_table[beacon_idx]. - wapi_offset; - if (new_beacon->bcn_ht_cap) - new_beacon->ht_cap_offset = - adapter->scan_table[beacon_idx]. - ht_cap_offset; - if (new_beacon->bcn_ht_info) - new_beacon->ht_info_offset = - adapter->scan_table[beacon_idx]. - ht_info_offset; - if (new_beacon->bcn_bss_co_2040) - new_beacon->bss_co_2040_offset = - adapter->scan_table[beacon_idx]. - bss_co_2040_offset; - if (new_beacon->bcn_ext_cap) - new_beacon->ext_cap_offset = - adapter->scan_table[beacon_idx]. - ext_cap_offset; - if (new_beacon->bcn_obss_scan) - new_beacon->overlap_bss_offset = - adapter->scan_table[beacon_idx]. - overlap_bss_offset; - } - /* Point the new entry to its permanent storage space */ - new_beacon->beacon_buf = bcn_store; - mwifiex_update_beacon_buffer_ptrs(new_beacon); - } else { - /* - * No existing beacon data exists for this entry, check to see - * if we can fit it in the remaining space - */ - if (adapter->bcn_buf_end + new_beacon->beacon_buf_size + - SCAN_BEACON_ENTRY_PAD < (adapter->bcn_buf + - sizeof(adapter->bcn_buf))) { - - /* - * Copy the beacon buffer data from the local entry to - * the adapter dev struct buffer space used to store - * the raw beacon data for each entry in the scan table - */ - memcpy(adapter->bcn_buf_end, new_beacon->beacon_buf, - new_beacon->beacon_buf_size); - - /* Update the beacon ptr to point to the table save - area */ - new_beacon->beacon_buf = adapter->bcn_buf_end; - new_beacon->beacon_buf_size_max = - (new_beacon->beacon_buf_size + - SCAN_BEACON_ENTRY_PAD); - - mwifiex_update_beacon_buffer_ptrs(new_beacon); - - /* Increment the end pointer by the size reserved */ - adapter->bcn_buf_end += new_beacon->beacon_buf_size_max; - - dev_dbg(adapter->dev, "info: AppControl: beacon[%02d]" - " sz=%03d, used = %04d, left = %04d\n", - beacon_idx, - new_beacon->beacon_buf_size, - (int)(adapter->bcn_buf_end - adapter->bcn_buf), - (int)(sizeof(adapter->bcn_buf) - - (adapter->bcn_buf_end - - adapter->bcn_buf))); - } else { - /* No space for new beacon */ - dev_dbg(adapter->dev, "info: AppControl: no space for" - " beacon (%d): %pM sz=%03d, left=%03d\n", - beacon_idx, new_beacon->mac_address, - new_beacon->beacon_buf_size, - (int)(sizeof(adapter->bcn_buf) - - (adapter->bcn_buf_end - - adapter->bcn_buf))); - - /* Storage failure; clear storage records for this - bcn */ - new_beacon->beacon_buf = NULL; - new_beacon->beacon_buf_size = 0; - new_beacon->beacon_buf_size_max = 0; - new_beacon->bcn_wpa_ie = NULL; - new_beacon->wpa_offset = 0; - new_beacon->bcn_rsn_ie = NULL; - new_beacon->rsn_offset = 0; - new_beacon->bcn_wapi_ie = NULL; - new_beacon->wapi_offset = 0; - new_beacon->bcn_ht_cap = NULL; - new_beacon->ht_cap_offset = 0; - new_beacon->bcn_ht_info = NULL; - new_beacon->ht_info_offset = 0; - new_beacon->bcn_bss_co_2040 = NULL; - new_beacon->bss_co_2040_offset = 0; - new_beacon->bcn_ext_cap = NULL; - new_beacon->ext_cap_offset = 0; - new_beacon->bcn_obss_scan = NULL; - new_beacon->overlap_bss_offset = 0; - } - } -} - -/* - * This function restores a beacon buffer of the current BSS descriptor. - */ -static void mwifiex_restore_curr_bcn(struct mwifiex_private *priv) -{ - struct mwifiex_adapter *adapter = priv->adapter; - struct mwifiex_bssdescriptor *curr_bss = - &priv->curr_bss_params.bss_descriptor; - unsigned long flags; - - if (priv->curr_bcn_buf && - ((adapter->bcn_buf_end + priv->curr_bcn_size) < - (adapter->bcn_buf + sizeof(adapter->bcn_buf)))) { - spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags); - - /* restore the current beacon buffer */ - memcpy(adapter->bcn_buf_end, priv->curr_bcn_buf, - priv->curr_bcn_size); - curr_bss->beacon_buf = adapter->bcn_buf_end; - curr_bss->beacon_buf_size = priv->curr_bcn_size; - adapter->bcn_buf_end += priv->curr_bcn_size; - - /* adjust the pointers in the current BSS descriptor */ - if (curr_bss->bcn_wpa_ie) - curr_bss->bcn_wpa_ie = - (struct ieee_types_vendor_specific *) - (curr_bss->beacon_buf + - curr_bss->wpa_offset); - - if (curr_bss->bcn_rsn_ie) - curr_bss->bcn_rsn_ie = (struct ieee_types_generic *) - (curr_bss->beacon_buf + - curr_bss->rsn_offset); - - if (curr_bss->bcn_ht_cap) - curr_bss->bcn_ht_cap = (struct ieee80211_ht_cap *) - (curr_bss->beacon_buf + - curr_bss->ht_cap_offset); - - if (curr_bss->bcn_ht_info) - curr_bss->bcn_ht_info = (struct ieee80211_ht_info *) - (curr_bss->beacon_buf + - curr_bss->ht_info_offset); - - if (curr_bss->bcn_bss_co_2040) - curr_bss->bcn_bss_co_2040 = - (u8 *) (curr_bss->beacon_buf + - curr_bss->bss_co_2040_offset); - - if (curr_bss->bcn_ext_cap) - curr_bss->bcn_ext_cap = (u8 *) (curr_bss->beacon_buf + - curr_bss->ext_cap_offset); - - if (curr_bss->bcn_obss_scan) - curr_bss->bcn_obss_scan = - (struct ieee_types_obss_scan_param *) - (curr_bss->beacon_buf + - curr_bss->overlap_bss_offset); - - spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags); - - dev_dbg(adapter->dev, "info: current beacon restored %d\n", - priv->curr_bcn_size); - } else { - dev_warn(adapter->dev, - "curr_bcn_buf not saved or bcn_buf has no space\n"); - } -} - -/* - * This function post processes the scan table after a new scan command has - * completed. - * - * It inspects each entry of the scan table and tries to find an entry that - * matches with our current associated/joined network from the scan. If - * one is found, the stored copy of the BSS descriptor of our current network - * is updated. - * - * It also debug dumps the current scan table contents after processing is over. - */ -static void -mwifiex_process_scan_results(struct mwifiex_private *priv) -{ - struct mwifiex_adapter *adapter = priv->adapter; - s32 j; - u32 i; - unsigned long flags; - - if (priv->media_connected) { - - j = mwifiex_find_ssid_in_list(priv, &priv->curr_bss_params. - bss_descriptor.ssid, - priv->curr_bss_params. - bss_descriptor.mac_address, - priv->bss_mode); - - if (j >= 0) { - 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. - bcn_obss_scan = NULL; - priv->curr_bss_params.bss_descriptor. - overlap_bss_offset = 0; - priv->curr_bss_params.bss_descriptor.beacon_buf = NULL; - priv->curr_bss_params.bss_descriptor.beacon_buf_size = - 0; - priv->curr_bss_params.bss_descriptor. - beacon_buf_size_max = 0; - - dev_dbg(adapter->dev, "info: Found current ssid/bssid" - " in list @ index #%d\n", j); - /* Make a copy of current BSSID descriptor */ - memcpy(&priv->curr_bss_params.bss_descriptor, - &adapter->scan_table[j], - sizeof(priv->curr_bss_params.bss_descriptor)); - - mwifiex_save_curr_bcn(priv); - spin_unlock_irqrestore(&priv->curr_bcn_buf_lock, flags); - - } else { - mwifiex_restore_curr_bcn(priv); - } - } - - for (i = 0; i < adapter->num_in_scan_table; i++) - dev_dbg(adapter->dev, "info: scan:(%02d) %pM " - "RSSI[%03d], SSID[%s]\n", - i, adapter->scan_table[i].mac_address, - (s32) adapter->scan_table[i].rssi, - adapter->scan_table[i].ssid.ssid); -} - -/* * This function converts radio type scan parameter to a band configuration * to be used in join command. */ @@ -2072,175 +1385,6 @@ mwifiex_radio_type_to_band(u8 radio_type) } /* - * This function deletes a specific indexed entry from the scan table. - * - * This also compacts the remaining entries and adjusts any buffering - * of beacon/probe response data if needed. - */ -static void -mwifiex_scan_delete_table_entry(struct mwifiex_private *priv, s32 table_idx) -{ - struct mwifiex_adapter *adapter = priv->adapter; - u32 del_idx; - u32 beacon_buf_adj; - u8 *beacon_buf; - - /* - * Shift the saved beacon buffer data for the scan table back over the - * entry being removed. Update the end of buffer pointer. Save the - * deleted buffer allocation size for pointer adjustments for entries - * compacted after the deleted index. - */ - beacon_buf_adj = adapter->scan_table[table_idx].beacon_buf_size_max; - - dev_dbg(adapter->dev, "info: Scan: Delete Entry %d, beacon buffer " - "removal = %d bytes\n", table_idx, beacon_buf_adj); - - /* Check if the table entry had storage allocated for its beacon */ - if (beacon_buf_adj) { - beacon_buf = adapter->scan_table[table_idx].beacon_buf; - - /* - * Remove the entry's buffer space, decrement the table end - * pointer by the amount we are removing - */ - adapter->bcn_buf_end -= beacon_buf_adj; - - dev_dbg(adapter->dev, "info: scan: delete entry %d," - " compact data: %p <- %p (sz = %d)\n", - table_idx, beacon_buf, - beacon_buf + beacon_buf_adj, - (int)(adapter->bcn_buf_end - beacon_buf)); - - /* - * Compact data storage. Copy all data after the deleted - * entry's end address (beacon_buf + beacon_buf_adj) back - * to the original start address (beacon_buf). - * - * Scan table entries affected by the move will have their - * entry pointer adjusted below. - * - * Use memmove since the dest/src memory regions overlap. - */ - memmove(beacon_buf, beacon_buf + beacon_buf_adj, - adapter->bcn_buf_end - beacon_buf); - } - - dev_dbg(adapter->dev, - "info: Scan: Delete Entry %d, num_in_scan_table = %d\n", - table_idx, adapter->num_in_scan_table); - - /* Shift all of the entries after the table_idx back by one, compacting - the table and removing the requested entry */ - for (del_idx = table_idx; (del_idx + 1) < adapter->num_in_scan_table; - del_idx++) { - /* Copy the next entry over this one */ - memcpy(adapter->scan_table + del_idx, - adapter->scan_table + del_idx + 1, - sizeof(struct mwifiex_bssdescriptor)); - - /* - * Adjust this entry's pointer to its beacon buffer based on - * the removed/compacted entry from the deleted index. Don't - * decrement if the buffer pointer is NULL (no data stored for - * this entry). - */ - if (adapter->scan_table[del_idx].beacon_buf) { - adapter->scan_table[del_idx].beacon_buf -= - beacon_buf_adj; - if (adapter->scan_table[del_idx].bcn_wpa_ie) - adapter->scan_table[del_idx].bcn_wpa_ie = - (struct ieee_types_vendor_specific *) - (adapter->scan_table[del_idx]. - beacon_buf + - adapter->scan_table[del_idx]. - wpa_offset); - if (adapter->scan_table[del_idx].bcn_rsn_ie) - adapter->scan_table[del_idx].bcn_rsn_ie = - (struct ieee_types_generic *) - (adapter->scan_table[del_idx]. - beacon_buf + - adapter->scan_table[del_idx]. - rsn_offset); - if (adapter->scan_table[del_idx].bcn_wapi_ie) - adapter->scan_table[del_idx].bcn_wapi_ie = - (struct ieee_types_generic *) - (adapter->scan_table[del_idx].beacon_buf - + adapter->scan_table[del_idx]. - wapi_offset); - if (adapter->scan_table[del_idx].bcn_ht_cap) - adapter->scan_table[del_idx].bcn_ht_cap = - (struct ieee80211_ht_cap *) - (adapter->scan_table[del_idx].beacon_buf - + adapter->scan_table[del_idx]. - ht_cap_offset); - - if (adapter->scan_table[del_idx].bcn_ht_info) - adapter->scan_table[del_idx].bcn_ht_info = - (struct ieee80211_ht_info *) - (adapter->scan_table[del_idx].beacon_buf - + adapter->scan_table[del_idx]. - ht_info_offset); - if (adapter->scan_table[del_idx].bcn_bss_co_2040) - adapter->scan_table[del_idx].bcn_bss_co_2040 = - (u8 *) - (adapter->scan_table[del_idx].beacon_buf - + adapter->scan_table[del_idx]. - bss_co_2040_offset); - if (adapter->scan_table[del_idx].bcn_ext_cap) - adapter->scan_table[del_idx].bcn_ext_cap = - (u8 *) - (adapter->scan_table[del_idx].beacon_buf - + adapter->scan_table[del_idx]. - ext_cap_offset); - if (adapter->scan_table[del_idx].bcn_obss_scan) - adapter->scan_table[del_idx]. - bcn_obss_scan = - (struct ieee_types_obss_scan_param *) - (adapter->scan_table[del_idx].beacon_buf - + adapter->scan_table[del_idx]. - overlap_bss_offset); - } - } - - /* The last entry is invalid now that it has been deleted or moved - back */ - memset(adapter->scan_table + adapter->num_in_scan_table - 1, - 0x00, sizeof(struct mwifiex_bssdescriptor)); - - adapter->num_in_scan_table--; -} - -/* - * This function deletes all occurrences of a given SSID from the scan table. - * - * This iterates through the scan table and deletes all entries that match - * the given SSID. It also compacts the remaining scan table entries. - */ -static int -mwifiex_scan_delete_ssid_table_entry(struct mwifiex_private *priv, - struct mwifiex_802_11_ssid *del_ssid) -{ - s32 table_idx = -1; - - dev_dbg(priv->adapter->dev, "info: scan: delete ssid entry: %-32s\n", - del_ssid->ssid); - - /* If the requested SSID is found in the table, delete it. Then keep - searching the table for multiple entires for the SSID until no - more are found */ - while ((table_idx = mwifiex_find_ssid_in_list(priv, del_ssid, NULL, - NL80211_IFTYPE_UNSPECIFIED)) >= 0) { - dev_dbg(priv->adapter->dev, - "info: Scan: Delete SSID Entry: Found Idx = %d\n", - table_idx); - mwifiex_scan_delete_table_entry(priv, table_idx); - } - - return table_idx == -1 ? -1 : 0; -} - -/* * This is an internal function used to start a scan based on an input * configuration. * @@ -2251,67 +1395,51 @@ mwifiex_scan_delete_ssid_table_entry(struct mwifiex_private *priv, 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; struct mwifiex_ie_types_chan_list_param_set *chan_list_out; - u32 buf_size; struct mwifiex_chan_scan_param_set *scan_chan_list; - u8 keep_previous_scan; u8 filtered_scan; u8 scan_current_chan_only; u8 max_chan_per_scan; 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); + 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) * - MWIFIEX_USER_SCAN_CHAN_MAX; - scan_chan_list = kzalloc(buf_size, GFP_KERNEL); + scan_chan_list = kcalloc(MWIFIEX_USER_SCAN_CHAN_MAX, + sizeof(struct mwifiex_chan_scan_param_set), + GFP_KERNEL); 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; } - keep_previous_scan = false; - - mwifiex_scan_setup_scan_config(priv, user_scan_in, - &scan_cfg_out->config, &chan_list_out, - scan_chan_list, &max_chan_per_scan, - &filtered_scan, &scan_current_chan_only); - - if (user_scan_in) - keep_previous_scan = user_scan_in->keep_previous_scan; - - - if (!keep_previous_scan) { - memset(adapter->scan_table, 0x00, - sizeof(struct mwifiex_bssdescriptor) * IW_MAX_AP); - adapter->num_in_scan_table = 0; - adapter->bcn_buf_end = adapter->bcn_buf; - } + mwifiex_config_scan(priv, user_scan_in, &scan_cfg_out->config, + &chan_list_out, scan_chan_list, &max_chan_per_scan, + &filtered_scan, &scan_current_chan_only); ret = mwifiex_scan_channel_list(priv, max_chan_per_scan, filtered_scan, &scan_cfg_out->config, chan_list_out, @@ -2322,24 +1450,33 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); if (!list_empty(&adapter->scan_pending_q)) { cmd_node = list_first_entry(&adapter->scan_pending_q, - struct cmd_ctrl_node, list); + struct cmd_ctrl_node, list); list_del(&cmd_node->list); spin_unlock_irqrestore(&adapter->scan_pending_q_lock, - flags); + flags); mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); + queue_work(adapter->workqueue, &adapter->main_work); + + /* Perform internal scan synchronously */ + if (!priv->scan_request) { + dev_dbg(adapter->dev, "wait internal scan\n"); + mwifiex_wait_queue_complete(adapter, cmd_node); + } } 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; } @@ -2357,12 +1494,10 @@ int mwifiex_scan_networks(struct mwifiex_private *priv, * - Setting command ID, and proper size * - Ensuring correct endian-ness */ -int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd, void *data_buf) +int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd, + struct mwifiex_scan_cmd_config *scan_cfg) { struct host_cmd_ds_802_11_scan *scan_cmd = &cmd->params.scan; - struct mwifiex_scan_cmd_config *scan_cfg; - - scan_cfg = (struct mwifiex_scan_cmd_config *) data_buf; /* Set fixed field variables in scan command */ scan_cmd->bss_mode = scan_cfg->bss_mode; @@ -2381,6 +1516,305 @@ int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd, void *data_buf) } /* + * This function checks compatibility of requested network with current + * driver settings. + */ +int mwifiex_check_network_compatibility(struct mwifiex_private *priv, + struct mwifiex_bssdescriptor *bss_desc) +{ + int ret = -1; + + if (!bss_desc) + return -1; + + if ((mwifiex_get_cfp(priv, (u8) bss_desc->bss_band, + (u16) bss_desc->channel, 0))) { + switch (priv->bss_mode) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + ret = mwifiex_is_network_compatible(priv, bss_desc, + priv->bss_mode); + if (ret) + 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, + struct cfg80211_bss *bss) +{ + struct mwifiex_bssdescriptor *bss_desc; + int ret; + unsigned long flags; + + /* Allocate and fill new bss descriptor */ + bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor), GFP_KERNEL); + if (!bss_desc) + return -ENOMEM; + + ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc); + if (ret) + goto done; + + ret = mwifiex_check_network_compatibility(priv, bss_desc); + if (ret) + goto done; + + spin_lock_irqsave(&priv->curr_bcn_buf_lock, flags); + /* 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: + /* beacon_ie buffer was allocated in function + * mwifiex_fill_new_bss_desc(). Free it now. + */ + kfree(bss_desc->beacon_buf); + kfree(bss_desc); + return 0; +} + +static int +mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info, + u32 *bytes_left, u64 fw_tsf, u8 *radio_type, + bool ext_scan, s32 rssi_val) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_chan_freq_power *cfp; + struct cfg80211_bss *bss; + u8 bssid[ETH_ALEN]; + s32 rssi; + const u8 *ie_buf; + size_t ie_len; + u16 channel = 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_fixed_bcn_param *bcn_param; + struct mwifiex_bss_priv *bss_priv; + + if (*bytes_left >= sizeof(beacon_size)) { + /* Extract & convert beacon size from command buffer */ + memcpy(&beacon_size, *bss_info, sizeof(beacon_size)); + *bytes_left -= sizeof(beacon_size); + *bss_info += sizeof(beacon_size); + } + + if (!beacon_size || beacon_size > *bytes_left) { + *bss_info += *bytes_left; + *bytes_left = 0; + return -EFAULT; + } + + /* Initialize the current working beacon pointer for this BSS + * iteration + */ + current_ptr = *bss_info; + + /* Advance the return beacon pointer past the current beacon */ + *bss_info += beacon_size; + *bytes_left -= beacon_size; + + curr_bcn_bytes = beacon_size; + + /* First 5 fields are bssid, RSSI(for legacy scan only), + * time stamp, beacon interval, and capability information + */ + if (curr_bcn_bytes < ETH_ALEN + sizeof(u8) + + sizeof(struct mwifiex_fixed_bcn_param)) { + dev_err(adapter->dev, "InterpretIE: not enough bytes left\n"); + return -EFAULT; + } + + memcpy(bssid, current_ptr, ETH_ALEN); + current_ptr += ETH_ALEN; + curr_bcn_bytes -= ETH_ALEN; + + if (!ext_scan) { + rssi = (s32) *current_ptr; + rssi = (-rssi) * 100; /* Convert dBm to mBm */ + current_ptr += sizeof(u8); + curr_bcn_bytes -= sizeof(u8); + dev_dbg(adapter->dev, "info: InterpretIE: RSSI=%d\n", rssi); + } else { + rssi = rssi_val; + } + + bcn_param = (struct mwifiex_fixed_bcn_param *)current_ptr; + current_ptr += sizeof(*bcn_param); + curr_bcn_bytes -= sizeof(*bcn_param); + + 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_dbg(adapter->dev, "info: InterpretIE: capabilities=0x%X\n", + cap_info_bitmap); + + /* Rest of the current buffer are IE's */ + ie_buf = current_ptr; + ie_len = curr_bcn_bytes; + dev_dbg(adapter->dev, "info: InterpretIE: IELength for this AP = %d\n", + curr_bcn_bytes); + + while (curr_bcn_bytes >= sizeof(struct ieee_types_header)) { + u8 element_id, element_len; + + element_id = *current_ptr; + element_len = *(current_ptr + 1); + if (curr_bcn_bytes < element_len + + sizeof(struct ieee_types_header)) { + dev_err(adapter->dev, + "%s: bytes left < IE length\n", __func__); + return -EFAULT; + } + if (element_id == WLAN_EID_DS_PARAMS) { + channel = *(current_ptr + + sizeof(struct ieee_types_header)); + break; + } + + current_ptr += element_len + sizeof(struct ieee_types_header); + curr_bcn_bytes -= element_len + + sizeof(struct ieee_types_header); + } + + if (channel) { + struct ieee80211_channel *chan; + u8 band; + + /* Skip entry if on csa closed channel */ + if (channel == priv->csa_chan) { + dev_dbg(adapter->dev, + "Dropping entry on csa closed channel\n"); + return 0; + } + + band = BAND_G; + if (radio_type) + band = mwifiex_radio_type_to_band(*radio_type & + (BIT(0) | BIT(1))); + + cfp = mwifiex_get_cfp(priv, band, channel, 0); + + freq = cfp ? cfp->freq : 0; + + chan = ieee80211_get_channel(priv->wdev->wiphy, freq); + + if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) { + bss = cfg80211_inform_bss(priv->wdev->wiphy, + chan, bssid, timestamp, + cap_info_bitmap, beacon_period, + ie_buf, ie_len, rssi, GFP_KERNEL); + 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, bss); + cfg80211_put_bss(priv->wdev->wiphy, bss); + } + } else { + dev_dbg(adapter->dev, "missing BSS channel IE\n"); + } + + return 0; +} + +static void mwifiex_complete_scan(struct mwifiex_private *priv) +{ + struct mwifiex_adapter *adapter = priv->adapter; + + if (adapter->curr_cmd->wait_q_enabled) { + adapter->cmd_wait_q.status = 0; + if (!priv->scan_request) { + dev_dbg(adapter->dev, "complete internal scan\n"); + mwifiex_complete_cmd(adapter, adapter->curr_cmd); + } + } +} + +static void mwifiex_check_next_scan_command(struct mwifiex_private *priv) +{ + struct mwifiex_adapter *adapter = priv->adapter; + struct cmd_ctrl_node *cmd_node; + unsigned long flags; + + 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); + spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); + adapter->scan_processing = false; + spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); + + if (!adapter->ext_scan) + mwifiex_complete_scan(priv); + + if (priv->report_scan_result) + priv->report_scan_result = false; + + if (priv->scan_request) { + dev_dbg(adapter->dev, "info: notifying scan done\n"); + cfg80211_scan_done(priv->scan_request, 0); + priv->scan_request = NULL; + } else { + priv->scan_aborting = false; + dev_dbg(adapter->dev, "info: scan already aborted\n"); + } + } else { + if ((priv->scan_aborting && !priv->scan_request) || + priv->scan_block) { + 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 & + NL80211_SCAN_FLAG_LOW_PRIORITY))) { + 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); + } + } + + return; +} + +/* * This function handles the command response of scan. * * The response buffer for the scan command has the following @@ -2404,52 +1838,48 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, { int ret = 0; struct mwifiex_adapter *adapter = priv->adapter; - struct cmd_ctrl_node *cmd_node; struct host_cmd_ds_802_11_scan_rsp *scan_rsp; - struct mwifiex_bssdescriptor *bss_new_entry = NULL; struct mwifiex_ie_types_data *tlv_data; struct mwifiex_ie_types_tsf_timestamp *tsf_tlv; u8 *bss_info; u32 scan_resp_size; u32 bytes_left; - u32 num_in_table; - u32 bss_idx; u32 idx; u32 tlv_buf_size; - long long tsf_val; - struct mwifiex_chan_freq_power *cfp; struct mwifiex_ie_types_chan_band_list_param_set *chan_band_tlv; struct chan_band_param_set *chan_band; - u8 band; u8 is_bgscan_resp; - unsigned long flags; + __le64 fw_tsf = 0; + u8 *radio_type; is_bgscan_resp = (le16_to_cpu(resp->command) - == HostCmd_CMD_802_11_BG_SCAN_QUERY); + == HostCmd_CMD_802_11_BG_SCAN_QUERY); if (is_bgscan_resp) scan_rsp = &resp->params.bg_scan_query_resp.scan_resp; else scan_rsp = &resp->params.scan_resp; - if (scan_rsp->number_of_sets > IW_MAX_AP) { + if (scan_rsp->number_of_sets > MWIFIEX_MAX_AP) { dev_err(adapter->dev, "SCAN_RESP: too many AP returned (%d)\n", - scan_rsp->number_of_sets); + scan_rsp->number_of_sets); ret = -1; - goto done; + goto check_next_scan; } + /* Check csa channel expiry before parsing scan response */ + mwifiex_11h_get_csa_closed_channel(priv); + bytes_left = le16_to_cpu(scan_rsp->bss_descript_size); dev_dbg(adapter->dev, "info: SCAN_RESP: bss_descript_size %d\n", - bytes_left); + bytes_left); scan_resp_size = le16_to_cpu(resp->size); dev_dbg(adapter->dev, "info: SCAN_RESP: returned %d APs before parsing\n", - scan_rsp->number_of_sets); + scan_rsp->number_of_sets); - num_in_table = adapter->num_in_scan_table; bss_info = scan_rsp->bss_desc_and_tlv_buffer; /* @@ -2481,164 +1911,198 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, (struct mwifiex_ie_types_data **) &chan_band_tlv); - /* - * Process each scan response returned (scan_rsp->number_of_sets). - * Save the information in the bss_new_entry and then insert into the - * driver scan table either as an update to an existing entry - * or as an addition at the end of the table - */ - bss_new_entry = kzalloc(sizeof(struct mwifiex_bssdescriptor), - GFP_KERNEL); - if (!bss_new_entry) { - dev_err(adapter->dev, " failed to alloc bss_new_entry\n"); - return -ENOMEM; - } - for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) { - /* Zero out the bss_new_entry we are about to store info in */ - memset(bss_new_entry, 0x00, - sizeof(struct mwifiex_bssdescriptor)); - - if (mwifiex_interpret_bss_desc_with_ie(adapter, bss_new_entry, - &bss_info, - &bytes_left)) { - /* Error parsing/interpreting scan response, skipped */ - dev_err(adapter->dev, "SCAN_RESP: " - "mwifiex_interpret_bss_desc_with_ie " - "returned ERROR\n"); - continue; - } - - /* Process the data fields and IEs returned for this BSS */ - dev_dbg(adapter->dev, "info: SCAN_RESP: BSSID = %pM\n", - bss_new_entry->mac_address); - - /* Search the scan table for the same bssid */ - for (bss_idx = 0; bss_idx < num_in_table; bss_idx++) { - if (memcmp(bss_new_entry->mac_address, - adapter->scan_table[bss_idx].mac_address, - sizeof(bss_new_entry->mac_address))) { - continue; - } - /* - * If the SSID matches as well, it is a - * duplicate of this entry. Keep the bss_idx - * set to this entry so we replace the old - * contents in the table - */ - if ((bss_new_entry->ssid.ssid_len - == adapter->scan_table[bss_idx]. ssid.ssid_len) - && (!memcmp(bss_new_entry->ssid.ssid, - adapter->scan_table[bss_idx].ssid.ssid, - bss_new_entry->ssid.ssid_len))) { - dev_dbg(adapter->dev, "info: SCAN_RESP:" - " duplicate of index: %d\n", bss_idx); - break; - } - } - /* - * If the bss_idx is equal to the number of entries in - * the table, the new entry was not a duplicate; append - * it to the scan table - */ - if (bss_idx == num_in_table) { - /* Range check the bss_idx, keep it limited to - the last entry */ - if (bss_idx == IW_MAX_AP) - bss_idx--; - else - num_in_table++; - } - - /* - * Save the beacon/probe response returned for later application - * retrieval. Duplicate beacon/probe responses are updated if - * possible - */ - mwifiex_ret_802_11_scan_store_beacon(priv, bss_idx, - num_in_table, bss_new_entry); /* * 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(&tsf_val, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE] - , sizeof(tsf_val)); - memcpy(&bss_new_entry->network_tsf, &tsf_val, - sizeof(bss_new_entry->network_tsf)); - } - band = BAND_G; + if (tsf_tlv) + memcpy(&fw_tsf, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE], + sizeof(fw_tsf)); + if (chan_band_tlv) { chan_band = &chan_band_tlv->chan_band_param[idx]; - band = mwifiex_radio_type_to_band(chan_band->radio_type - & (BIT(0) | BIT(1))); + radio_type = &chan_band->radio_type; + } else { + radio_type = NULL; } - /* Save the band designation for this entry for use in join */ - bss_new_entry->bss_band = band; - cfp = mwifiex_get_cfp_by_band_and_channel_from_cfg80211(priv, - (u8) bss_new_entry->bss_band, - (u16)bss_new_entry->channel); + ret = mwifiex_parse_single_response_buf(priv, &bss_info, + &bytes_left, + le64_to_cpu(fw_tsf), + radio_type, false, 0); + if (ret) + goto check_next_scan; + } - if (cfp) - bss_new_entry->freq = cfp->freq; - else - bss_new_entry->freq = 0; +check_next_scan: + mwifiex_check_next_scan_command(priv); + return ret; +} - /* Copy the locally created bss_new_entry to the scan table */ - memcpy(&adapter->scan_table[bss_idx], bss_new_entry, - sizeof(adapter->scan_table[bss_idx])); +/* + * This function prepares an extended scan command to be sent to the firmware + * + * This uses the scan command configuration sent to the command processing + * module in command preparation stage to configure a extended scan command + * structure to send to firmware. + */ +int mwifiex_cmd_802_11_scan_ext(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + void *data_buf) +{ + struct host_cmd_ds_802_11_scan_ext *ext_scan = &cmd->params.ext_scan; + struct mwifiex_scan_cmd_config *scan_cfg = data_buf; + + memcpy(ext_scan->tlv_buffer, scan_cfg->tlv_buf, scan_cfg->tlv_buf_len); + + cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SCAN_EXT); + + /* Size is equal to the sizeof(fixed portions) + the TLV len + header */ + cmd->size = cpu_to_le16((u16)(sizeof(ext_scan->reserved) + + scan_cfg->tlv_buf_len + S_DS_GEN)); + + return 0; +} + +/* This function handles the command response of extended scan */ +int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv) +{ + dev_dbg(priv->adapter->dev, "info: EXT scan returns successfully\n"); + + mwifiex_complete_scan(priv); + return 0; +} + +/* This function This function handles the event extended scan report. It + * parses extended scan results and informs to cfg80211 stack. + */ +int mwifiex_handle_event_ext_scan_report(struct mwifiex_private *priv, + void *buf) +{ + int ret = 0; + struct mwifiex_adapter *adapter = priv->adapter; + u8 *bss_info; + u32 bytes_left, bytes_left_for_tlv, idx; + u16 type, len; + struct mwifiex_ie_types_data *tlv; + struct mwifiex_ie_types_bss_scan_rsp *scan_rsp_tlv; + struct mwifiex_ie_types_bss_scan_info *scan_info_tlv; + u8 *radio_type; + u64 fw_tsf = 0; + s32 rssi = 0; + struct mwifiex_event_scan_result *event_scan = buf; + u8 num_of_set = event_scan->num_of_set; + u8 *scan_resp = buf + sizeof(struct mwifiex_event_scan_result); + u16 scan_resp_size = le16_to_cpu(event_scan->buf_size); + + if (num_of_set > MWIFIEX_MAX_AP) { + dev_err(adapter->dev, + "EXT_SCAN: Invalid number of AP returned (%d)!!\n", + num_of_set); + ret = -1; + goto check_next_scan; } + bytes_left = scan_resp_size; dev_dbg(adapter->dev, - "info: SCAN_RESP: Scanned %2d APs, %d valid, %d total\n", - scan_rsp->number_of_sets, - num_in_table - adapter->num_in_scan_table, num_in_table); + "EXT_SCAN: size %d, returned %d APs...", + scan_resp_size, num_of_set); - /* Update the total number of BSSIDs in the scan table */ - adapter->num_in_scan_table = num_in_table; + tlv = (struct mwifiex_ie_types_data *)scan_resp; - 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); - spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags); - adapter->scan_processing = false; - spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags); - /* - * Process the resulting scan table: - * - Remove any bad ssids - * - Update our current BSS information from scan data + for (idx = 0; idx < num_of_set && bytes_left; idx++) { + type = le16_to_cpu(tlv->header.type); + len = le16_to_cpu(tlv->header.len); + if (bytes_left < sizeof(struct mwifiex_ie_types_header) + len) { + dev_err(adapter->dev, "EXT_SCAN: Error bytes left < TLV length\n"); + break; + } + scan_rsp_tlv = NULL; + scan_info_tlv = NULL; + bytes_left_for_tlv = bytes_left; + + /* BSS response TLV with beacon or probe response buffer + * at the initial position of each descriptor */ - mwifiex_process_scan_results(priv); + if (type != TLV_TYPE_BSS_SCAN_RSP) + break; - /* Need to indicate IOCTL complete */ - if (adapter->curr_cmd->wait_q_enabled) { - adapter->cmd_wait_q.status = 0; - mwifiex_complete_cmd(adapter); - } - 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); + bss_info = (u8 *)tlv; + scan_rsp_tlv = (struct mwifiex_ie_types_bss_scan_rsp *)tlv; + tlv = (struct mwifiex_ie_types_data *)(tlv->data + len); + bytes_left_for_tlv -= + (len + sizeof(struct mwifiex_ie_types_header)); + + while (bytes_left_for_tlv >= + sizeof(struct mwifiex_ie_types_header) && + le16_to_cpu(tlv->header.type) != TLV_TYPE_BSS_SCAN_RSP) { + type = le16_to_cpu(tlv->header.type); + len = le16_to_cpu(tlv->header.len); + if (bytes_left_for_tlv < + sizeof(struct mwifiex_ie_types_header) + len) { + dev_err(adapter->dev, + "EXT_SCAN: Error in processing TLV, bytes left < TLV length\n"); + scan_rsp_tlv = NULL; + bytes_left_for_tlv = 0; + continue; + } + switch (type) { + case TLV_TYPE_BSS_SCAN_INFO: + scan_info_tlv = + (struct mwifiex_ie_types_bss_scan_info *)tlv; + if (len != + sizeof(struct mwifiex_ie_types_bss_scan_info) - + sizeof(struct mwifiex_ie_types_header)) { + bytes_left_for_tlv = 0; + continue; + } + break; + default: + break; + } + tlv = (struct mwifiex_ie_types_data *)(tlv->data + len); + bytes_left -= + (len + sizeof(struct mwifiex_ie_types_header)); + bytes_left_for_tlv -= + (len + sizeof(struct mwifiex_ie_types_header)); } - } 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); + if (!scan_rsp_tlv) + break; + + /* Advance pointer to the beacon buffer length and + * update the bytes count so that the function + * wlan_interpret_bss_desc_with_ie() can handle the + * scan buffer withut any change + */ + bss_info += sizeof(u16); + bytes_left -= sizeof(u16); - mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); + if (scan_info_tlv) { + rssi = (s32)(s16)(le16_to_cpu(scan_info_tlv->rssi)); + rssi *= 100; /* Convert dBm to mBm */ + dev_dbg(adapter->dev, + "info: InterpretIE: RSSI=%d\n", rssi); + fw_tsf = le64_to_cpu(scan_info_tlv->tsf); + radio_type = &scan_info_tlv->radio_type; + } else { + radio_type = NULL; + } + ret = mwifiex_parse_single_response_buf(priv, &bss_info, + &bytes_left, fw_tsf, + radio_type, true, rssi); + if (ret) + goto check_next_scan; } -done: - kfree((u8 *) bss_new_entry); +check_next_scan: + if (!event_scan->more_event) + mwifiex_check_next_scan_command(priv); + return ret; } @@ -2665,141 +2129,6 @@ int mwifiex_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd) } /* - * This function finds a SSID in the scan table. - * - * A BSSID may optionally be provided to qualify the SSID. - * For non-Auto mode, further check is made to make sure the - * BSS found in the scan table is compatible with the current - * settings of the driver. - */ -s32 -mwifiex_find_ssid_in_list(struct mwifiex_private *priv, - struct mwifiex_802_11_ssid *ssid, u8 *bssid, - u32 mode) -{ - struct mwifiex_adapter *adapter = priv->adapter; - s32 net = -1, j; - u8 best_rssi = 0; - u32 i; - - dev_dbg(adapter->dev, "info: num of entries in table = %d\n", - adapter->num_in_scan_table); - - /* - * Loop through the table until the maximum is reached or until a match - * is found based on the bssid field comparison - */ - for (i = 0; - i < adapter->num_in_scan_table && (!bssid || (bssid && net < 0)); - i++) { - if (!mwifiex_ssid_cmp(&adapter->scan_table[i].ssid, ssid) && - (!bssid - || !memcmp(adapter->scan_table[i].mac_address, bssid, - ETH_ALEN)) - && - (mwifiex_get_cfp_by_band_and_channel_from_cfg80211 - (priv, (u8) adapter->scan_table[i].bss_band, - (u16) adapter->scan_table[i].channel))) { - switch (mode) { - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_ADHOC: - j = mwifiex_is_network_compatible(priv, i, - mode); - - if (j >= 0) { - if (SCAN_RSSI - (adapter->scan_table[i].rssi) > - best_rssi) { - best_rssi = SCAN_RSSI(adapter-> - scan_table - [i].rssi); - net = i; - } - } else { - if (net == -1) - net = j; - } - break; - case NL80211_IFTYPE_UNSPECIFIED: - default: - /* - * Do not check compatibility if the mode - * requested is Auto/Unknown. Allows generic - * find to work without verifying against the - * Adapter security settings - */ - if (SCAN_RSSI(adapter->scan_table[i].rssi) > - best_rssi) { - best_rssi = SCAN_RSSI(adapter-> - scan_table[i].rssi); - net = i; - } - break; - } - } - } - - return net; -} - -/* - * This function finds a specific compatible BSSID in the scan list. - * - * This function loops through the scan table looking for a compatible - * match. If a BSSID matches, but the BSS is found to be not compatible - * the function ignores it and continues to search through the rest of - * the entries in case there is an AP with multiple SSIDs assigned to - * the same BSSID. - */ -s32 -mwifiex_find_bssid_in_list(struct mwifiex_private *priv, u8 *bssid, - u32 mode) -{ - struct mwifiex_adapter *adapter = priv->adapter; - s32 net = -1; - u32 i; - - if (!bssid) - return -1; - - dev_dbg(adapter->dev, "info: FindBSSID: Num of BSSIDs = %d\n", - adapter->num_in_scan_table); - - /* - * Look through the scan table for a compatible match. The ret return - * variable will be equal to the index in the scan table (greater - * than zero) if the network is compatible. The loop will continue - * past a matched bssid that is not compatible in case there is an - * AP with multiple SSIDs assigned to the same BSSID - */ - for (i = 0; net < 0 && i < adapter->num_in_scan_table; i++) { - if (!memcmp - (adapter->scan_table[i].mac_address, bssid, ETH_ALEN) - && mwifiex_get_cfp_by_band_and_channel_from_cfg80211 - (priv, - (u8) adapter-> - scan_table[i]. - bss_band, - (u16) adapter-> - scan_table[i]. - channel)) { - switch (mode) { - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_ADHOC: - net = mwifiex_is_network_compatible(priv, i, - mode); - break; - default: - net = i; - break; - } - } - } - - return net; -} - -/* * This function inserts scan command node to the scan pending queue. */ void @@ -2810,83 +2139,40 @@ mwifiex_queue_scan_cmd(struct mwifiex_private *priv, unsigned long flags; cmd_node->wait_q_enabled = true; + cmd_node->condition = &adapter->scan_wait_q_woken; spin_lock_irqsave(&adapter->scan_pending_q_lock, flags); list_add_tail(&cmd_node->list, &adapter->scan_pending_q); spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); } /* - * This function finds an AP with specific ssid in the scan list. - */ -int mwifiex_find_best_network(struct mwifiex_private *priv, - struct mwifiex_ssid_bssid *req_ssid_bssid) -{ - struct mwifiex_adapter *adapter = priv->adapter; - struct mwifiex_bssdescriptor *req_bss; - s32 i; - - memset(req_ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid)); - - i = mwifiex_find_best_network_in_list(priv); - - if (i >= 0) { - req_bss = &adapter->scan_table[i]; - memcpy(&req_ssid_bssid->ssid, &req_bss->ssid, - sizeof(struct mwifiex_802_11_ssid)); - memcpy((u8 *) &req_ssid_bssid->bssid, - (u8 *) &req_bss->mac_address, ETH_ALEN); - - /* Make sure we are in the right mode */ - if (priv->bss_mode == NL80211_IFTYPE_UNSPECIFIED) - priv->bss_mode = req_bss->bss_mode; - } - - if (!req_ssid_bssid->ssid.ssid_len) - return -1; - - dev_dbg(adapter->dev, "info: Best network found = [%s], " - "[%pM]\n", req_ssid_bssid->ssid.ssid, - req_ssid_bssid->bssid); - - return 0; -} - -/* * This function sends a scan command for all available channels to the * firmware, filtered on a specific SSID. */ static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv, - struct mwifiex_802_11_ssid *req_ssid) + 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; } - mwifiex_scan_delete_ssid_table_entry(priv, req_ssid); - scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL); - if (!scan_cfg) { - dev_err(adapter->dev, "failed to alloc scan_cfg\n"); + if (!scan_cfg) return -ENOMEM; - } - memcpy(scan_cfg->ssid_list[0].ssid, req_ssid->ssid, - req_ssid->ssid_len); - scan_cfg->keep_previous_scan = true; + scan_cfg->ssid_list = req_ssid; + scan_cfg->num_ssids = 1; ret = mwifiex_scan_networks(priv, scan_cfg); @@ -2904,18 +2190,17 @@ static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv, * scan, depending upon whether an SSID is provided or not. */ int mwifiex_request_scan(struct mwifiex_private *priv, - struct mwifiex_802_11_ssid *req_ssid) + struct cfg80211_ssid *req_ssid) { int ret; if (down_interruptible(&priv->async_sem)) { dev_err(priv->adapter->dev, "%s: acquire semaphore\n", - __func__); + __func__); return -1; } - priv->scan_pending_on_block = true; - priv->adapter->cmd_wait_q.condition = false; + priv->adapter->scan_wait_q_woken = false; if (req_ssid && req_ssid->ssid_len != 0) /* Specific SSID scan */ @@ -2924,13 +2209,7 @@ int mwifiex_request_scan(struct mwifiex_private *priv, /* Normal scan */ ret = mwifiex_scan_networks(priv, NULL); - 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; } @@ -2995,23 +2274,64 @@ mwifiex_save_curr_bcn(struct mwifiex_private *priv) /* allocate beacon buffer at 1st time; or if it's size has changed */ if (!priv->curr_bcn_buf || - priv->curr_bcn_size != curr_bss->beacon_buf_size) { + priv->curr_bcn_size != curr_bss->beacon_buf_size) { priv->curr_bcn_size = curr_bss->beacon_buf_size; kfree(priv->curr_bcn_buf); - priv->curr_bcn_buf = kzalloc(curr_bss->beacon_buf_size, - GFP_KERNEL); - if (!priv->curr_bcn_buf) { - dev_err(priv->adapter->dev, - "failed to alloc curr_bcn_buf\n"); + priv->curr_bcn_buf = kmalloc(curr_bss->beacon_buf_size, + GFP_ATOMIC); + if (!priv->curr_bcn_buf) return; - } } memcpy(priv->curr_bcn_buf, curr_bss->beacon_buf, - curr_bss->beacon_buf_size); + curr_bss->beacon_buf_size); dev_dbg(priv->adapter->dev, "info: current beacon saved %d\n", priv->curr_bcn_size); + + curr_bss->beacon_buf = priv->curr_bcn_buf; + + /* adjust the pointers in the current BSS descriptor */ + if (curr_bss->bcn_wpa_ie) + curr_bss->bcn_wpa_ie = + (struct ieee_types_vendor_specific *) + (curr_bss->beacon_buf + + curr_bss->wpa_offset); + + if (curr_bss->bcn_rsn_ie) + curr_bss->bcn_rsn_ie = (struct ieee_types_generic *) + (curr_bss->beacon_buf + + curr_bss->rsn_offset); + + if (curr_bss->bcn_ht_cap) + curr_bss->bcn_ht_cap = (struct ieee80211_ht_cap *) + (curr_bss->beacon_buf + + curr_bss->ht_cap_offset); + + if (curr_bss->bcn_ht_oper) + curr_bss->bcn_ht_oper = (struct ieee80211_ht_operation *) + (curr_bss->beacon_buf + + curr_bss->ht_info_offset); + + if (curr_bss->bcn_vht_cap) + curr_bss->bcn_vht_cap = (void *)(curr_bss->beacon_buf + + curr_bss->vht_cap_offset); + + if (curr_bss->bcn_vht_oper) + curr_bss->bcn_vht_oper = (void *)(curr_bss->beacon_buf + + curr_bss->vht_info_offset); + + if (curr_bss->bcn_bss_co_2040) + curr_bss->bcn_bss_co_2040 = + (curr_bss->beacon_buf + curr_bss->bss_co_2040_offset); + + if (curr_bss->bcn_ext_cap) + curr_bss->bcn_ext_cap = curr_bss->beacon_buf + + curr_bss->ext_cap_offset; + + if (curr_bss->oper_mode) + curr_bss->oper_mode = (void *)(curr_bss->beacon_buf + + curr_bss->oper_mode_offset); } /* |
