linux/drivers/net/wireless/marvell/mwifiex/scan.c
<<
>>
Prefs
   1/*
   2 * NXP Wireless LAN device driver: scan ioctl and command handling
   3 *
   4 * Copyright 2011-2020 NXP
   5 *
   6 * This software file (the "File") is distributed by NXP
   7 * under the terms of the GNU General Public License Version 2, June 1991
   8 * (the "License").  You may use, redistribute and/or modify this File in
   9 * accordance with the terms and conditions of the License, a copy of which
  10 * is available by writing to the Free Software Foundation, Inc.,
  11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
  12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
  13 *
  14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
  15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
  16 * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
  17 * this warranty disclaimer.
  18 */
  19
  20#include "decl.h"
  21#include "ioctl.h"
  22#include "util.h"
  23#include "fw.h"
  24#include "main.h"
  25#include "11n.h"
  26#include "cfg80211.h"
  27
  28/* The maximum number of channels the firmware can scan per command */
  29#define MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN   14
  30
  31#define MWIFIEX_DEF_CHANNELS_PER_SCAN_CMD       4
  32
  33/* Memory needed to store a max sized Channel List TLV for a firmware scan */
  34#define CHAN_TLV_MAX_SIZE  (sizeof(struct mwifiex_ie_types_header)         \
  35                                + (MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN     \
  36                                *sizeof(struct mwifiex_chan_scan_param_set)))
  37
  38/* Memory needed to store supported rate */
  39#define RATE_TLV_MAX_SIZE   (sizeof(struct mwifiex_ie_types_rates_param_set) \
  40                                + HOSTCMD_SUPPORTED_RATES)
  41
  42/* Memory needed to store a max number/size WildCard SSID TLV for a firmware
  43        scan */
  44#define WILDCARD_SSID_TLV_MAX_SIZE  \
  45        (MWIFIEX_MAX_SSID_LIST_LENGTH *                                 \
  46                (sizeof(struct mwifiex_ie_types_wildcard_ssid_params)   \
  47                        + IEEE80211_MAX_SSID_LEN))
  48
  49/* Maximum memory needed for a mwifiex_scan_cmd_config with all TLVs at max */
  50#define MAX_SCAN_CFG_ALLOC (sizeof(struct mwifiex_scan_cmd_config)        \
  51                                + sizeof(struct mwifiex_ie_types_num_probes)   \
  52                                + sizeof(struct mwifiex_ie_types_htcap)       \
  53                                + CHAN_TLV_MAX_SIZE                 \
  54                                + RATE_TLV_MAX_SIZE                 \
  55                                + WILDCARD_SSID_TLV_MAX_SIZE)
  56
  57
  58union mwifiex_scan_cmd_config_tlv {
  59        /* Scan configuration (variable length) */
  60        struct mwifiex_scan_cmd_config config;
  61        /* Max allocated block */
  62        u8 config_alloc_buf[MAX_SCAN_CFG_ALLOC];
  63};
  64
  65enum cipher_suite {
  66        CIPHER_SUITE_TKIP,
  67        CIPHER_SUITE_CCMP,
  68        CIPHER_SUITE_MAX
  69};
  70static u8 mwifiex_wpa_oui[CIPHER_SUITE_MAX][4] = {
  71        { 0x00, 0x50, 0xf2, 0x02 },     /* TKIP */
  72        { 0x00, 0x50, 0xf2, 0x04 },     /* AES  */
  73};
  74static u8 mwifiex_rsn_oui[CIPHER_SUITE_MAX][4] = {
  75        { 0x00, 0x0f, 0xac, 0x02 },     /* TKIP */
  76        { 0x00, 0x0f, 0xac, 0x04 },     /* AES  */
  77};
  78
  79static void
  80_dbg_security_flags(int log_level, const char *func, const char *desc,
  81                    struct mwifiex_private *priv,
  82                    struct mwifiex_bssdescriptor *bss_desc)
  83{
  84        _mwifiex_dbg(priv->adapter, log_level,
  85                     "info: %s: %s:\twpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s\tEncMode=%#x privacy=%#x\n",
  86                     func, desc,
  87                     bss_desc->bcn_wpa_ie ?
  88                     bss_desc->bcn_wpa_ie->vend_hdr.element_id : 0,
  89                     bss_desc->bcn_rsn_ie ?
  90                     bss_desc->bcn_rsn_ie->ieee_hdr.element_id : 0,
  91                     priv->sec_info.wep_enabled ? "e" : "d",
  92                     priv->sec_info.wpa_enabled ? "e" : "d",
  93                     priv->sec_info.wpa2_enabled ? "e" : "d",
  94                     priv->sec_info.encryption_mode,
  95                     bss_desc->privacy);
  96}
  97#define dbg_security_flags(mask, desc, priv, bss_desc) \
  98        _dbg_security_flags(MWIFIEX_DBG_##mask, desc, __func__, priv, bss_desc)
  99
 100static bool
 101has_ieee_hdr(struct ieee_types_generic *ie, u8 key)
 102{
 103        return (ie && ie->ieee_hdr.element_id == key);
 104}
 105
 106static bool
 107has_vendor_hdr(struct ieee_types_vendor_specific *ie, u8 key)
 108{
 109        return (ie && ie->vend_hdr.element_id == key);
 110}
 111
 112/*
 113 * This function parses a given IE for a given OUI.
 114 *
 115 * This is used to parse a WPA/RSN IE to find if it has
 116 * a given oui in PTK.
 117 */
 118static u8
 119mwifiex_search_oui_in_ie(struct ie_body *iebody, u8 *oui)
 120{
 121        u8 count;
 122
 123        count = iebody->ptk_cnt[0];
 124
 125        /* There could be multiple OUIs for PTK hence
 126           1) Take the length.
 127           2) Check all the OUIs for AES.
 128           3) If one of them is AES then pass success. */
 129        while (count) {
 130                if (!memcmp(iebody->ptk_body, oui, sizeof(iebody->ptk_body)))
 131                        return MWIFIEX_OUI_PRESENT;
 132
 133                --count;
 134                if (count)
 135                        iebody = (struct ie_body *) ((u8 *) iebody +
 136                                                sizeof(iebody->ptk_body));
 137        }
 138
 139        pr_debug("info: %s: OUI is not found in PTK\n", __func__);
 140        return MWIFIEX_OUI_NOT_PRESENT;
 141}
 142
 143/*
 144 * This function checks if a given OUI is present in a RSN IE.
 145 *
 146 * The function first checks if a RSN IE is present or not in the
 147 * BSS descriptor. It tries to locate the OUI only if such an IE is
 148 * present.
 149 */
 150static u8
 151mwifiex_is_rsn_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher)
 152{
 153        u8 *oui;
 154        struct ie_body *iebody;
 155        u8 ret = MWIFIEX_OUI_NOT_PRESENT;
 156
 157        if (has_ieee_hdr(bss_desc->bcn_rsn_ie, WLAN_EID_RSN)) {
 158                iebody = (struct ie_body *)
 159                         (((u8 *) bss_desc->bcn_rsn_ie->data) +
 160                          RSN_GTK_OUI_OFFSET);
 161                oui = &mwifiex_rsn_oui[cipher][0];
 162                ret = mwifiex_search_oui_in_ie(iebody, oui);
 163                if (ret)
 164                        return ret;
 165        }
 166        return ret;
 167}
 168
 169/*
 170 * This function checks if a given OUI is present in a WPA IE.
 171 *
 172 * The function first checks if a WPA IE is present or not in the
 173 * BSS descriptor. It tries to locate the OUI only if such an IE is
 174 * present.
 175 */
 176static u8
 177mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher)
 178{
 179        u8 *oui;
 180        struct ie_body *iebody;
 181        u8 ret = MWIFIEX_OUI_NOT_PRESENT;
 182
 183        if (has_vendor_hdr(bss_desc->bcn_wpa_ie, WLAN_EID_VENDOR_SPECIFIC)) {
 184                iebody = (struct ie_body *)((u8 *)bss_desc->bcn_wpa_ie->data +
 185                                            WPA_GTK_OUI_OFFSET);
 186                oui = &mwifiex_wpa_oui[cipher][0];
 187                ret = mwifiex_search_oui_in_ie(iebody, oui);
 188                if (ret)
 189                        return ret;
 190        }
 191        return ret;
 192}
 193
 194/*
 195 * This function compares two SSIDs and checks if they match.
 196 */
 197s32
 198mwifiex_ssid_cmp(struct cfg80211_ssid *ssid1, struct cfg80211_ssid *ssid2)
 199{
 200        if (!ssid1 || !ssid2 || (ssid1->ssid_len != ssid2->ssid_len))
 201                return -1;
 202        return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssid_len);
 203}
 204
 205/*
 206 * This function checks if wapi is enabled in driver and scanned network is
 207 * compatible with it.
 208 */
 209static bool
 210mwifiex_is_bss_wapi(struct mwifiex_private *priv,
 211                    struct mwifiex_bssdescriptor *bss_desc)
 212{
 213        if (priv->sec_info.wapi_enabled &&
 214            has_ieee_hdr(bss_desc->bcn_wapi_ie, WLAN_EID_BSS_AC_ACCESS_DELAY))
 215                return true;
 216        return false;
 217}
 218
 219/*
 220 * This function checks if driver is configured with no security mode and
 221 * scanned network is compatible with it.
 222 */
 223static bool
 224mwifiex_is_bss_no_sec(struct mwifiex_private *priv,
 225                      struct mwifiex_bssdescriptor *bss_desc)
 226{
 227        if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled &&
 228            !priv->sec_info.wpa2_enabled &&
 229            !has_vendor_hdr(bss_desc->bcn_wpa_ie, WLAN_EID_VENDOR_SPECIFIC) &&
 230            !has_ieee_hdr(bss_desc->bcn_rsn_ie, WLAN_EID_RSN) &&
 231            !priv->sec_info.encryption_mode && !bss_desc->privacy) {
 232                return true;
 233        }
 234        return false;
 235}
 236
 237/*
 238 * This function checks if static WEP is enabled in driver and scanned network
 239 * is compatible with it.
 240 */
 241static bool
 242mwifiex_is_bss_static_wep(struct mwifiex_private *priv,
 243                          struct mwifiex_bssdescriptor *bss_desc)
 244{
 245        if (priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled &&
 246            !priv->sec_info.wpa2_enabled && bss_desc->privacy) {
 247                return true;
 248        }
 249        return false;
 250}
 251
 252/*
 253 * This function checks if wpa is enabled in driver and scanned network is
 254 * compatible with it.
 255 */
 256static bool
 257mwifiex_is_bss_wpa(struct mwifiex_private *priv,
 258                   struct mwifiex_bssdescriptor *bss_desc)
 259{
 260        if (!priv->sec_info.wep_enabled && priv->sec_info.wpa_enabled &&
 261            !priv->sec_info.wpa2_enabled &&
 262            has_vendor_hdr(bss_desc->bcn_wpa_ie, WLAN_EID_VENDOR_SPECIFIC)
 263           /*
 264            * Privacy bit may NOT be set in some APs like
 265            * LinkSys WRT54G && bss_desc->privacy
 266            */
 267         ) {
 268                dbg_security_flags(INFO, "WPA", priv, bss_desc);
 269                return true;
 270        }
 271        return false;
 272}
 273
 274/*
 275 * This function checks if wpa2 is enabled in driver and scanned network is
 276 * compatible with it.
 277 */
 278static bool
 279mwifiex_is_bss_wpa2(struct mwifiex_private *priv,
 280                    struct mwifiex_bssdescriptor *bss_desc)
 281{
 282        if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled &&
 283            priv->sec_info.wpa2_enabled &&
 284            has_ieee_hdr(bss_desc->bcn_rsn_ie, WLAN_EID_RSN)) {
 285                /*
 286                 * Privacy bit may NOT be set in some APs like
 287                 * LinkSys WRT54G && bss_desc->privacy
 288                 */
 289                dbg_security_flags(INFO, "WAP2", priv, bss_desc);
 290                return true;
 291        }
 292        return false;
 293}
 294
 295/*
 296 * This function checks if adhoc AES is enabled in driver and scanned network is
 297 * compatible with it.
 298 */
 299static bool
 300mwifiex_is_bss_adhoc_aes(struct mwifiex_private *priv,
 301                         struct mwifiex_bssdescriptor *bss_desc)
 302{
 303        if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled &&
 304            !priv->sec_info.wpa2_enabled &&
 305            !has_vendor_hdr(bss_desc->bcn_wpa_ie, WLAN_EID_VENDOR_SPECIFIC) &&
 306            !has_ieee_hdr(bss_desc->bcn_rsn_ie, WLAN_EID_RSN) &&
 307            !priv->sec_info.encryption_mode && bss_desc->privacy) {
 308                return true;
 309        }
 310        return false;
 311}
 312
 313/*
 314 * This function checks if dynamic WEP is enabled in driver and scanned network
 315 * is compatible with it.
 316 */
 317static bool
 318mwifiex_is_bss_dynamic_wep(struct mwifiex_private *priv,
 319                           struct mwifiex_bssdescriptor *bss_desc)
 320{
 321        if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled &&
 322            !priv->sec_info.wpa2_enabled &&
 323            !has_vendor_hdr(bss_desc->bcn_wpa_ie, WLAN_EID_VENDOR_SPECIFIC) &&
 324            !has_ieee_hdr(bss_desc->bcn_rsn_ie, WLAN_EID_RSN) &&
 325            priv->sec_info.encryption_mode && bss_desc->privacy) {
 326                dbg_security_flags(INFO, "dynamic", priv, bss_desc);
 327                return true;
 328        }
 329        return false;
 330}
 331
 332/*
 333 * This function checks if a scanned network is compatible with the driver
 334 * settings.
 335 *
 336 *   WEP     WPA    WPA2   ad-hoc encrypt                  Network
 337 * enabled enabled enabled  AES    mode   Privacy WPA WPA2 Compatible
 338 *    0       0       0      0     NONE      0     0   0   yes No security
 339 *    0       1       0      0      x        1x    1   x   yes WPA (disable
 340 *                                                         HT if no AES)
 341 *    0       0       1      0      x        1x    x   1   yes WPA2 (disable
 342 *                                                         HT if no AES)
 343 *    0       0       0      1     NONE      1     0   0   yes Ad-hoc AES
 344 *    1       0       0      0     NONE      1     0   0   yes Static WEP
 345 *                                                         (disable HT)
 346 *    0       0       0      0    !=NONE     1     0   0   yes Dynamic WEP
 347 *
 348 * Compatibility is not matched while roaming, except for mode.
 349 */
 350static s32
 351mwifiex_is_network_compatible(struct mwifiex_private *priv,
 352                              struct mwifiex_bssdescriptor *bss_desc, u32 mode)
 353{
 354        struct mwifiex_adapter *adapter = priv->adapter;
 355
 356        bss_desc->disable_11n = false;
 357
 358        /* Don't check for compatibility if roaming */
 359        if (priv->media_connected &&
 360            (priv->bss_mode == NL80211_IFTYPE_STATION) &&
 361            (bss_desc->bss_mode == NL80211_IFTYPE_STATION))
 362                return 0;
 363
 364        if (priv->wps.session_enable) {
 365                mwifiex_dbg(adapter, IOCTL,
 366                            "info: return success directly in WPS period\n");
 367                return 0;
 368        }
 369
 370        if (bss_desc->chan_sw_ie_present) {
 371                mwifiex_dbg(adapter, INFO,
 372                            "Don't connect to AP with WLAN_EID_CHANNEL_SWITCH\n");
 373                return -1;
 374        }
 375
 376        if (mwifiex_is_bss_wapi(priv, bss_desc)) {
 377                mwifiex_dbg(adapter, INFO,
 378                            "info: return success for WAPI AP\n");
 379                return 0;
 380        }
 381
 382        if (bss_desc->bss_mode == mode) {
 383                if (mwifiex_is_bss_no_sec(priv, bss_desc)) {
 384                        /* No security */
 385                        return 0;
 386                } else if (mwifiex_is_bss_static_wep(priv, bss_desc)) {
 387                        /* Static WEP enabled */
 388                        mwifiex_dbg(adapter, INFO,
 389                                    "info: Disable 11n in WEP mode.\n");
 390                        bss_desc->disable_11n = true;
 391                        return 0;
 392                } else if (mwifiex_is_bss_wpa(priv, bss_desc)) {
 393                        /* WPA enabled */
 394                        if (((priv->adapter->config_bands & BAND_GN ||
 395                              priv->adapter->config_bands & BAND_AN) &&
 396                             bss_desc->bcn_ht_cap) &&
 397                            !mwifiex_is_wpa_oui_present(bss_desc,
 398                                                         CIPHER_SUITE_CCMP)) {
 399
 400                                if (mwifiex_is_wpa_oui_present
 401                                                (bss_desc, CIPHER_SUITE_TKIP)) {
 402                                        mwifiex_dbg(adapter, INFO,
 403                                                    "info: Disable 11n if AES\t"
 404                                                    "is not supported by AP\n");
 405                                        bss_desc->disable_11n = true;
 406                                } else {
 407                                        return -1;
 408                                }
 409                        }
 410                        return 0;
 411                } else if (mwifiex_is_bss_wpa2(priv, bss_desc)) {
 412                        /* WPA2 enabled */
 413                        if (((priv->adapter->config_bands & BAND_GN ||
 414                              priv->adapter->config_bands & BAND_AN) &&
 415                             bss_desc->bcn_ht_cap) &&
 416                            !mwifiex_is_rsn_oui_present(bss_desc,
 417                                                        CIPHER_SUITE_CCMP)) {
 418
 419                                if (mwifiex_is_rsn_oui_present
 420                                                (bss_desc, CIPHER_SUITE_TKIP)) {
 421                                        mwifiex_dbg(adapter, INFO,
 422                                                    "info: Disable 11n if AES\t"
 423                                                    "is not supported by AP\n");
 424                                        bss_desc->disable_11n = true;
 425                                } else {
 426                                        return -1;
 427                                }
 428                        }
 429                        return 0;
 430                } else if (mwifiex_is_bss_adhoc_aes(priv, bss_desc)) {
 431                        /* Ad-hoc AES enabled */
 432                        return 0;
 433                } else if (mwifiex_is_bss_dynamic_wep(priv, bss_desc)) {
 434                        /* Dynamic WEP enabled */
 435                        return 0;
 436                }
 437
 438                /* Security doesn't match */
 439                dbg_security_flags(ERROR, "failed", priv, bss_desc);
 440                return -1;
 441        }
 442
 443        /* Mode doesn't match */
 444        return -1;
 445}
 446
 447/*
 448 * This function creates a channel list for the driver to scan, based
 449 * on region/band information.
 450 *
 451 * This routine is used for any scan that is not provided with a
 452 * specific channel list to scan.
 453 */
 454static int
 455mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
 456                                 const struct mwifiex_user_scan_cfg
 457                                                        *user_scan_in,
 458                                 struct mwifiex_chan_scan_param_set
 459                                                        *scan_chan_list,
 460                                 u8 filtered_scan)
 461{
 462        enum nl80211_band band;
 463        struct ieee80211_supported_band *sband;
 464        struct ieee80211_channel *ch;
 465        struct mwifiex_adapter *adapter = priv->adapter;
 466        int chan_idx = 0, i;
 467
 468        for (band = 0; (band < NUM_NL80211_BANDS) ; band++) {
 469
 470                if (!priv->wdev.wiphy->bands[band])
 471                        continue;
 472
 473                sband = priv->wdev.wiphy->bands[band];
 474
 475                for (i = 0; (i < sband->n_channels) ; i++) {
 476                        ch = &sband->channels[i];
 477                        if (ch->flags & IEEE80211_CHAN_DISABLED)
 478                                continue;
 479                        scan_chan_list[chan_idx].radio_type = band;
 480
 481                        if (user_scan_in &&
 482                            user_scan_in->chan_list[0].scan_time)
 483                                scan_chan_list[chan_idx].max_scan_time =
 484                                        cpu_to_le16((u16) user_scan_in->
 485                                        chan_list[0].scan_time);
 486                        else if ((ch->flags & IEEE80211_CHAN_NO_IR) ||
 487                                 (ch->flags & IEEE80211_CHAN_RADAR))
 488                                scan_chan_list[chan_idx].max_scan_time =
 489                                        cpu_to_le16(adapter->passive_scan_time);
 490                        else
 491                                scan_chan_list[chan_idx].max_scan_time =
 492                                        cpu_to_le16(adapter->active_scan_time);
 493
 494                        if (ch->flags & IEEE80211_CHAN_NO_IR)
 495                                scan_chan_list[chan_idx].chan_scan_mode_bitmap
 496                                        |= (MWIFIEX_PASSIVE_SCAN |
 497                                            MWIFIEX_HIDDEN_SSID_REPORT);
 498                        else
 499                                scan_chan_list[chan_idx].chan_scan_mode_bitmap
 500                                        &= ~MWIFIEX_PASSIVE_SCAN;
 501                        scan_chan_list[chan_idx].chan_number =
 502                                                        (u32) ch->hw_value;
 503
 504                        scan_chan_list[chan_idx].chan_scan_mode_bitmap
 505                                        |= MWIFIEX_DISABLE_CHAN_FILT;
 506
 507                        if (filtered_scan &&
 508                            !((ch->flags & IEEE80211_CHAN_NO_IR) ||
 509                              (ch->flags & IEEE80211_CHAN_RADAR)))
 510                                scan_chan_list[chan_idx].max_scan_time =
 511                                cpu_to_le16(adapter->specific_scan_time);
 512
 513                        chan_idx++;
 514                }
 515
 516        }
 517        return chan_idx;
 518}
 519
 520/* This function creates a channel list tlv for bgscan config, based
 521 * on region/band information.
 522 */
 523static int
 524mwifiex_bgscan_create_channel_list(struct mwifiex_private *priv,
 525                                   const struct mwifiex_bg_scan_cfg
 526                                                *bgscan_cfg_in,
 527                                   struct mwifiex_chan_scan_param_set
 528                                                *scan_chan_list)
 529{
 530        enum nl80211_band band;
 531        struct ieee80211_supported_band *sband;
 532        struct ieee80211_channel *ch;
 533        struct mwifiex_adapter *adapter = priv->adapter;
 534        int chan_idx = 0, i;
 535
 536        for (band = 0; (band < NUM_NL80211_BANDS); band++) {
 537                if (!priv->wdev.wiphy->bands[band])
 538                        continue;
 539
 540                sband = priv->wdev.wiphy->bands[band];
 541
 542                for (i = 0; (i < sband->n_channels) ; i++) {
 543                        ch = &sband->channels[i];
 544                        if (ch->flags & IEEE80211_CHAN_DISABLED)
 545                                continue;
 546                        scan_chan_list[chan_idx].radio_type = band;
 547
 548                        if (bgscan_cfg_in->chan_list[0].scan_time)
 549                                scan_chan_list[chan_idx].max_scan_time =
 550                                        cpu_to_le16((u16)bgscan_cfg_in->
 551                                        chan_list[0].scan_time);
 552                        else if (ch->flags & IEEE80211_CHAN_NO_IR)
 553                                scan_chan_list[chan_idx].max_scan_time =
 554                                        cpu_to_le16(adapter->passive_scan_time);
 555                        else
 556                                scan_chan_list[chan_idx].max_scan_time =
 557                                        cpu_to_le16(adapter->
 558                                                    specific_scan_time);
 559
 560                        if (ch->flags & IEEE80211_CHAN_NO_IR)
 561                                scan_chan_list[chan_idx].chan_scan_mode_bitmap
 562                                        |= MWIFIEX_PASSIVE_SCAN;
 563                        else
 564                                scan_chan_list[chan_idx].chan_scan_mode_bitmap
 565                                        &= ~MWIFIEX_PASSIVE_SCAN;
 566
 567                        scan_chan_list[chan_idx].chan_number =
 568                                                        (u32)ch->hw_value;
 569                        chan_idx++;
 570                }
 571        }
 572        return chan_idx;
 573}
 574
 575/* This function appends rate TLV to scan config command. */
 576static int
 577mwifiex_append_rate_tlv(struct mwifiex_private *priv,
 578                        struct mwifiex_scan_cmd_config *scan_cfg_out,
 579                        u8 radio)
 580{
 581        struct mwifiex_ie_types_rates_param_set *rates_tlv;
 582        u8 rates[MWIFIEX_SUPPORTED_RATES], *tlv_pos;
 583        u32 rates_size;
 584
 585        memset(rates, 0, sizeof(rates));
 586
 587        tlv_pos = (u8 *)scan_cfg_out->tlv_buf + scan_cfg_out->tlv_buf_len;
 588
 589        if (priv->scan_request)
 590                rates_size = mwifiex_get_rates_from_cfg80211(priv, rates,
 591                                                             radio);
 592        else
 593                rates_size = mwifiex_get_supported_rates(priv, rates);
 594
 595        mwifiex_dbg(priv->adapter, CMD,
 596                    "info: SCAN_CMD: Rates size = %d\n",
 597                rates_size);
 598        rates_tlv = (struct mwifiex_ie_types_rates_param_set *)tlv_pos;
 599        rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES);
 600        rates_tlv->header.len = cpu_to_le16((u16) rates_size);
 601        memcpy(rates_tlv->rates, rates, rates_size);
 602        scan_cfg_out->tlv_buf_len += sizeof(rates_tlv->header) + rates_size;
 603
 604        return rates_size;
 605}
 606
 607/*
 608 * This function constructs and sends multiple scan config commands to
 609 * the firmware.
 610 *
 611 * Previous routines in the code flow have created a scan command configuration
 612 * with any requested TLVs.  This function splits the channel TLV into maximum
 613 * channels supported per scan lists and sends the portion of the channel TLV,
 614 * along with the other TLVs, to the firmware.
 615 */
 616static int
 617mwifiex_scan_channel_list(struct mwifiex_private *priv,
 618                          u32 max_chan_per_scan, u8 filtered_scan,
 619                          struct mwifiex_scan_cmd_config *scan_cfg_out,
 620                          struct mwifiex_ie_types_chan_list_param_set
 621                          *chan_tlv_out,
 622                          struct mwifiex_chan_scan_param_set *scan_chan_list)
 623{
 624        struct mwifiex_adapter *adapter = priv->adapter;
 625        int ret = 0;
 626        struct mwifiex_chan_scan_param_set *tmp_chan_list;
 627        struct mwifiex_chan_scan_param_set *start_chan;
 628        u32 tlv_idx, rates_size, cmd_no;
 629        u32 total_scan_time;
 630        u32 done_early;
 631        u8 radio_type;
 632
 633        if (!scan_cfg_out || !chan_tlv_out || !scan_chan_list) {
 634                mwifiex_dbg(priv->adapter, ERROR,
 635                            "info: Scan: Null detect: %p, %p, %p\n",
 636                            scan_cfg_out, chan_tlv_out, scan_chan_list);
 637                return -1;
 638        }
 639
 640        /* Check csa channel expiry before preparing scan list */
 641        mwifiex_11h_get_csa_closed_channel(priv);
 642
 643        chan_tlv_out->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
 644
 645        /* Set the temp channel struct pointer to the start of the desired
 646           list */
 647        tmp_chan_list = scan_chan_list;
 648
 649        /* Loop through the desired channel list, sending a new firmware scan
 650           commands for each max_chan_per_scan channels (or for 1,6,11
 651           individually if configured accordingly) */
 652        while (tmp_chan_list->chan_number) {
 653
 654                tlv_idx = 0;
 655                total_scan_time = 0;
 656                radio_type = 0;
 657                chan_tlv_out->header.len = 0;
 658                start_chan = tmp_chan_list;
 659                done_early = false;
 660
 661                /*
 662                 * Construct the Channel TLV for the scan command.  Continue to
 663                 * insert channel TLVs until:
 664                 *   - the tlv_idx hits the maximum configured per scan command
 665                 *   - the next channel to insert is 0 (end of desired channel
 666                 *     list)
 667                 *   - done_early is set (controlling individual scanning of
 668                 *     1,6,11)
 669                 */
 670                while (tlv_idx < max_chan_per_scan &&
 671                       tmp_chan_list->chan_number && !done_early) {
 672
 673                        if (tmp_chan_list->chan_number == priv->csa_chan) {
 674                                tmp_chan_list++;
 675                                continue;
 676                        }
 677
 678                        radio_type = tmp_chan_list->radio_type;
 679                        mwifiex_dbg(priv->adapter, INFO,
 680                                    "info: Scan: Chan(%3d), Radio(%d),\t"
 681                                    "Mode(%d, %d), Dur(%d)\n",
 682                                    tmp_chan_list->chan_number,
 683                                    tmp_chan_list->radio_type,
 684                                    tmp_chan_list->chan_scan_mode_bitmap
 685                                    & MWIFIEX_PASSIVE_SCAN,
 686                                    (tmp_chan_list->chan_scan_mode_bitmap
 687                                    & MWIFIEX_DISABLE_CHAN_FILT) >> 1,
 688                                    le16_to_cpu(tmp_chan_list->max_scan_time));
 689
 690                        /* Copy the current channel TLV to the command being
 691                           prepared */
 692                        memcpy(chan_tlv_out->chan_scan_param + tlv_idx,
 693                               tmp_chan_list,
 694                               sizeof(chan_tlv_out->chan_scan_param));
 695
 696                        /* Increment the TLV header length by the size
 697                           appended */
 698                        le16_unaligned_add_cpu(&chan_tlv_out->header.len,
 699                                               sizeof(
 700                                                chan_tlv_out->chan_scan_param));
 701
 702                        /*
 703                         * The tlv buffer length is set to the number of bytes
 704                         * of the between the channel tlv pointer and the start
 705                         * of the tlv buffer.  This compensates for any TLVs
 706                         * that were appended before the channel list.
 707                         */
 708                        scan_cfg_out->tlv_buf_len = (u32) ((u8 *) chan_tlv_out -
 709                                                        scan_cfg_out->tlv_buf);
 710
 711                        /* Add the size of the channel tlv header and the data
 712                           length */
 713                        scan_cfg_out->tlv_buf_len +=
 714                                (sizeof(chan_tlv_out->header)
 715                                 + le16_to_cpu(chan_tlv_out->header.len));
 716
 717                        /* Increment the index to the channel tlv we are
 718                           constructing */
 719                        tlv_idx++;
 720
 721                        /* Count the total scan time per command */
 722                        total_scan_time +=
 723                                le16_to_cpu(tmp_chan_list->max_scan_time);
 724
 725                        done_early = false;
 726
 727                        /* Stop the loop if the *current* channel is in the
 728                           1,6,11 set and we are not filtering on a BSSID
 729                           or SSID. */
 730                        if (!filtered_scan &&
 731                            (tmp_chan_list->chan_number == 1 ||
 732                             tmp_chan_list->chan_number == 6 ||
 733                             tmp_chan_list->chan_number == 11))
 734                                done_early = true;
 735
 736                        /* Increment the tmp pointer to the next channel to
 737                           be scanned */
 738                        tmp_chan_list++;
 739
 740                        /* Stop the loop if the *next* channel is in the 1,6,11
 741                           set.  This will cause it to be the only channel
 742                           scanned on the next interation */
 743                        if (!filtered_scan &&
 744                            (tmp_chan_list->chan_number == 1 ||
 745                             tmp_chan_list->chan_number == 6 ||
 746                             tmp_chan_list->chan_number == 11))
 747                                done_early = true;
 748                }
 749
 750                /* The total scan time should be less than scan command timeout
 751                   value */
 752                if (total_scan_time > MWIFIEX_MAX_TOTAL_SCAN_TIME) {
 753                        mwifiex_dbg(priv->adapter, ERROR,
 754                                    "total scan time %dms\t"
 755                                    "is over limit (%dms), scan skipped\n",
 756                                    total_scan_time,
 757                                    MWIFIEX_MAX_TOTAL_SCAN_TIME);
 758                        ret = -1;
 759                        break;
 760                }
 761
 762                rates_size = mwifiex_append_rate_tlv(priv, scan_cfg_out,
 763                                                     radio_type);
 764
 765                priv->adapter->scan_channels = start_chan;
 766
 767                /* Send the scan command to the firmware with the specified
 768                   cfg */
 769                if (priv->adapter->ext_scan)
 770                        cmd_no = HostCmd_CMD_802_11_SCAN_EXT;
 771                else
 772                        cmd_no = HostCmd_CMD_802_11_SCAN;
 773
 774                ret = mwifiex_send_cmd(priv, cmd_no, HostCmd_ACT_GEN_SET,
 775                                       0, scan_cfg_out, false);
 776
 777                /* rate IE is updated per scan command but same starting
 778                 * pointer is used each time so that rate IE from earlier
 779                 * scan_cfg_out->buf is overwritten with new one.
 780                 */
 781                scan_cfg_out->tlv_buf_len -=
 782                            sizeof(struct mwifiex_ie_types_header) + rates_size;
 783
 784                if (ret) {
 785                        mwifiex_cancel_pending_scan_cmd(adapter);
 786                        break;
 787                }
 788        }
 789
 790        if (ret)
 791                return -1;
 792
 793        return 0;
 794}
 795
 796/*
 797 * This function constructs a scan command configuration structure to use
 798 * in scan commands.
 799 *
 800 * Application layer or other functions can invoke network scanning
 801 * with a scan configuration supplied in a user scan configuration structure.
 802 * This structure is used as the basis of one or many scan command configuration
 803 * commands that are sent to the command processing module and eventually to the
 804 * firmware.
 805 *
 806 * This function creates a scan command configuration structure  based on the
 807 * following user supplied parameters (if present):
 808 *      - SSID filter
 809 *      - BSSID filter
 810 *      - Number of Probes to be sent
 811 *      - Channel list
 812 *
 813 * If the SSID or BSSID filter is not present, the filter is disabled/cleared.
 814 * If the number of probes is not set, adapter default setting is used.
 815 */
 816static void
 817mwifiex_config_scan(struct mwifiex_private *priv,
 818                    const struct mwifiex_user_scan_cfg *user_scan_in,
 819                    struct mwifiex_scan_cmd_config *scan_cfg_out,
 820                    struct mwifiex_ie_types_chan_list_param_set **chan_list_out,
 821                    struct mwifiex_chan_scan_param_set *scan_chan_list,
 822                    u8 *max_chan_per_scan, u8 *filtered_scan,
 823                    u8 *scan_current_only)
 824{
 825        struct mwifiex_adapter *adapter = priv->adapter;
 826        struct mwifiex_ie_types_num_probes *num_probes_tlv;
 827        struct mwifiex_ie_types_scan_chan_gap *chan_gap_tlv;
 828        struct mwifiex_ie_types_random_mac *random_mac_tlv;
 829        struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv;
 830        struct mwifiex_ie_types_bssid_list *bssid_tlv;
 831        u8 *tlv_pos;
 832        u32 num_probes;
 833        u32 ssid_len;
 834        u32 chan_idx;
 835        u32 scan_type;
 836        u16 scan_dur;
 837        u8 channel;
 838        u8 radio_type;
 839        int i;
 840        u8 ssid_filter;
 841        struct mwifiex_ie_types_htcap *ht_cap;
 842        struct mwifiex_ie_types_bss_mode *bss_mode;
 843        const u8 zero_mac[6] = {0, 0, 0, 0, 0, 0};
 844
 845        /* The tlv_buf_len is calculated for each scan command.  The TLVs added
 846           in this routine will be preserved since the routine that sends the
 847           command will append channelTLVs at *chan_list_out.  The difference
 848           between the *chan_list_out and the tlv_buf start will be used to
 849           calculate the size of anything we add in this routine. */
 850        scan_cfg_out->tlv_buf_len = 0;
 851
 852        /* Running tlv pointer.  Assigned to chan_list_out at end of function
 853           so later routines know where channels can be added to the command
 854           buf */
 855        tlv_pos = scan_cfg_out->tlv_buf;
 856
 857        /* Initialize the scan as un-filtered; the flag is later set to TRUE
 858           below if a SSID or BSSID filter is sent in the command */
 859        *filtered_scan = false;
 860
 861        /* Initialize the scan as not being only on the current channel.  If
 862           the channel list is customized, only contains one channel, and is
 863           the active channel, this is set true and data flow is not halted. */
 864        *scan_current_only = false;
 865
 866        if (user_scan_in) {
 867                u8 tmpaddr[ETH_ALEN];
 868
 869                /* Default the ssid_filter flag to TRUE, set false under
 870                   certain wildcard conditions and qualified by the existence
 871                   of an SSID list before marking the scan as filtered */
 872                ssid_filter = true;
 873
 874                /* Set the BSS type scan filter, use Adapter setting if
 875                   unset */
 876                scan_cfg_out->bss_mode =
 877                        (u8)(user_scan_in->bss_mode ?: adapter->scan_mode);
 878
 879                /* Set the number of probes to send, use Adapter setting
 880                   if unset */
 881                num_probes = user_scan_in->num_probes ?: adapter->scan_probes;
 882
 883                /*
 884                 * Set the BSSID filter to the incoming configuration,
 885                 * if non-zero.  If not set, it will remain disabled
 886                 * (all zeros).
 887                 */
 888                memcpy(scan_cfg_out->specific_bssid,
 889                       user_scan_in->specific_bssid,
 890                       sizeof(scan_cfg_out->specific_bssid));
 891
 892                memcpy(tmpaddr, scan_cfg_out->specific_bssid, ETH_ALEN);
 893
 894                if (adapter->ext_scan &&
 895                    !is_zero_ether_addr(tmpaddr)) {
 896                        bssid_tlv =
 897                                (struct mwifiex_ie_types_bssid_list *)tlv_pos;
 898                        bssid_tlv->header.type = cpu_to_le16(TLV_TYPE_BSSID);
 899                        bssid_tlv->header.len = cpu_to_le16(ETH_ALEN);
 900                        memcpy(bssid_tlv->bssid, user_scan_in->specific_bssid,
 901                               ETH_ALEN);
 902                        tlv_pos += sizeof(struct mwifiex_ie_types_bssid_list);
 903                }
 904
 905                for (i = 0; i < user_scan_in->num_ssids; i++) {
 906                        ssid_len = user_scan_in->ssid_list[i].ssid_len;
 907
 908                        wildcard_ssid_tlv =
 909                                (struct mwifiex_ie_types_wildcard_ssid_params *)
 910                                tlv_pos;
 911                        wildcard_ssid_tlv->header.type =
 912                                cpu_to_le16(TLV_TYPE_WILDCARDSSID);
 913                        wildcard_ssid_tlv->header.len = cpu_to_le16(
 914                                (u16) (ssid_len + sizeof(wildcard_ssid_tlv->
 915                                                         max_ssid_length)));
 916
 917                        /*
 918                         * max_ssid_length = 0 tells firmware to perform
 919                         * specific scan for the SSID filled, whereas
 920                         * max_ssid_length = IEEE80211_MAX_SSID_LEN is for
 921                         * wildcard scan.
 922                         */
 923                        if (ssid_len)
 924                                wildcard_ssid_tlv->max_ssid_length = 0;
 925                        else
 926                                wildcard_ssid_tlv->max_ssid_length =
 927                                                        IEEE80211_MAX_SSID_LEN;
 928
 929                        if (!memcmp(user_scan_in->ssid_list[i].ssid,
 930                                    "DIRECT-", 7))
 931                                wildcard_ssid_tlv->max_ssid_length = 0xfe;
 932
 933                        memcpy(wildcard_ssid_tlv->ssid,
 934                               user_scan_in->ssid_list[i].ssid, ssid_len);
 935
 936                        tlv_pos += (sizeof(wildcard_ssid_tlv->header)
 937                                + le16_to_cpu(wildcard_ssid_tlv->header.len));
 938
 939                        mwifiex_dbg(adapter, INFO,
 940                                    "info: scan: ssid[%d]: %s, %d\n",
 941                                    i, wildcard_ssid_tlv->ssid,
 942                                    wildcard_ssid_tlv->max_ssid_length);
 943
 944                        /* Empty wildcard ssid with a maxlen will match many or
 945                           potentially all SSIDs (maxlen == 32), therefore do
 946                           not treat the scan as
 947                           filtered. */
 948                        if (!ssid_len && wildcard_ssid_tlv->max_ssid_length)
 949                                ssid_filter = false;
 950                }
 951
 952                /*
 953                 *  The default number of channels sent in the command is low to
 954                 *  ensure the response buffer from the firmware does not
 955                 *  truncate scan results.  That is not an issue with an SSID
 956                 *  or BSSID filter applied to the scan results in the firmware.
 957                 */
 958                memcpy(tmpaddr, scan_cfg_out->specific_bssid, ETH_ALEN);
 959                if ((i && ssid_filter) ||
 960                    !is_zero_ether_addr(tmpaddr))
 961                        *filtered_scan = true;
 962
 963                if (user_scan_in->scan_chan_gap) {
 964                        mwifiex_dbg(adapter, INFO,
 965                                    "info: scan: channel gap = %d\n",
 966                                    user_scan_in->scan_chan_gap);
 967                        *max_chan_per_scan =
 968                                        MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN;
 969
 970                        chan_gap_tlv = (void *)tlv_pos;
 971                        chan_gap_tlv->header.type =
 972                                         cpu_to_le16(TLV_TYPE_SCAN_CHANNEL_GAP);
 973                        chan_gap_tlv->header.len =
 974                                    cpu_to_le16(sizeof(chan_gap_tlv->chan_gap));
 975                        chan_gap_tlv->chan_gap =
 976                                     cpu_to_le16((user_scan_in->scan_chan_gap));
 977                        tlv_pos +=
 978                                  sizeof(struct mwifiex_ie_types_scan_chan_gap);
 979                }
 980
 981                if (!ether_addr_equal(user_scan_in->random_mac, zero_mac)) {
 982                        random_mac_tlv = (void *)tlv_pos;
 983                        random_mac_tlv->header.type =
 984                                         cpu_to_le16(TLV_TYPE_RANDOM_MAC);
 985                        random_mac_tlv->header.len =
 986                                    cpu_to_le16(sizeof(random_mac_tlv->mac));
 987                        ether_addr_copy(random_mac_tlv->mac,
 988                                        user_scan_in->random_mac);
 989                        tlv_pos +=
 990                                  sizeof(struct mwifiex_ie_types_random_mac);
 991                }
 992        } else {
 993                scan_cfg_out->bss_mode = (u8) adapter->scan_mode;
 994                num_probes = adapter->scan_probes;
 995        }
 996
 997        /*
 998         *  If a specific BSSID or SSID is used, the number of channels in the
 999         *  scan command will be increased to the absolute maximum.
1000         */
1001        if (*filtered_scan) {
1002                *max_chan_per_scan = MWIFIEX_MAX_CHANNELS_PER_SPECIFIC_SCAN;
1003        } else {
1004                if (!priv->media_connected)
1005                        *max_chan_per_scan = MWIFIEX_DEF_CHANNELS_PER_SCAN_CMD;
1006                else
1007                        *max_chan_per_scan =
1008                                        MWIFIEX_DEF_CHANNELS_PER_SCAN_CMD / 2;
1009        }
1010
1011        if (adapter->ext_scan) {
1012                bss_mode = (struct mwifiex_ie_types_bss_mode *)tlv_pos;
1013                bss_mode->header.type = cpu_to_le16(TLV_TYPE_BSS_MODE);
1014                bss_mode->header.len = cpu_to_le16(sizeof(bss_mode->bss_mode));
1015                bss_mode->bss_mode = scan_cfg_out->bss_mode;
1016                tlv_pos += sizeof(bss_mode->header) +
1017                           le16_to_cpu(bss_mode->header.len);
1018        }
1019
1020        /* If the input config or adapter has the number of Probes set,
1021           add tlv */
1022        if (num_probes) {
1023
1024                mwifiex_dbg(adapter, INFO,
1025                            "info: scan: num_probes = %d\n",
1026                            num_probes);
1027
1028                num_probes_tlv = (struct mwifiex_ie_types_num_probes *) tlv_pos;
1029                num_probes_tlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES);
1030                num_probes_tlv->header.len =
1031                        cpu_to_le16(sizeof(num_probes_tlv->num_probes));
1032                num_probes_tlv->num_probes = cpu_to_le16((u16) num_probes);
1033
1034                tlv_pos += sizeof(num_probes_tlv->header) +
1035                        le16_to_cpu(num_probes_tlv->header.len);
1036
1037        }
1038
1039        if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info) &&
1040            (priv->adapter->config_bands & BAND_GN ||
1041             priv->adapter->config_bands & BAND_AN)) {
1042                ht_cap = (struct mwifiex_ie_types_htcap *) tlv_pos;
1043                memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap));
1044                ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY);
1045                ht_cap->header.len =
1046                                cpu_to_le16(sizeof(struct ieee80211_ht_cap));
1047                radio_type =
1048                        mwifiex_band_to_radio_type(priv->adapter->config_bands);
1049                mwifiex_fill_cap_info(priv, radio_type, &ht_cap->ht_cap);
1050                tlv_pos += sizeof(struct mwifiex_ie_types_htcap);
1051        }
1052
1053        /* Append vendor specific IE TLV */
1054        mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_SCAN, &tlv_pos);
1055
1056        /*
1057         * Set the output for the channel TLV to the address in the tlv buffer
1058         *   past any TLVs that were added in this function (SSID, num_probes).
1059         *   Channel TLVs will be added past this for each scan command,
1060         *   preserving the TLVs that were previously added.
1061         */
1062        *chan_list_out =
1063                (struct mwifiex_ie_types_chan_list_param_set *) tlv_pos;
1064
1065        if (user_scan_in && user_scan_in->chan_list[0].chan_number) {
1066
1067                mwifiex_dbg(adapter, INFO,
1068                            "info: Scan: Using supplied channel list\n");
1069
1070                for (chan_idx = 0;
1071                     chan_idx < MWIFIEX_USER_SCAN_CHAN_MAX &&
1072                     user_scan_in->chan_list[chan_idx].chan_number;
1073                     chan_idx++) {
1074
1075                        channel = user_scan_in->chan_list[chan_idx].chan_number;
1076                        scan_chan_list[chan_idx].chan_number = channel;
1077
1078                        radio_type =
1079                                user_scan_in->chan_list[chan_idx].radio_type;
1080                        scan_chan_list[chan_idx].radio_type = radio_type;
1081
1082                        scan_type = user_scan_in->chan_list[chan_idx].scan_type;
1083
1084                        if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
1085                                scan_chan_list[chan_idx].chan_scan_mode_bitmap
1086                                        |= (MWIFIEX_PASSIVE_SCAN |
1087                                            MWIFIEX_HIDDEN_SSID_REPORT);
1088                        else
1089                                scan_chan_list[chan_idx].chan_scan_mode_bitmap
1090                                        &= ~MWIFIEX_PASSIVE_SCAN;
1091
1092                        scan_chan_list[chan_idx].chan_scan_mode_bitmap
1093                                |= MWIFIEX_DISABLE_CHAN_FILT;
1094
1095                        if (user_scan_in->chan_list[chan_idx].scan_time) {
1096                                scan_dur = (u16) user_scan_in->
1097                                        chan_list[chan_idx].scan_time;
1098                        } else {
1099                                if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
1100                                        scan_dur = adapter->passive_scan_time;
1101                                else if (*filtered_scan)
1102                                        scan_dur = adapter->specific_scan_time;
1103                                else
1104                                        scan_dur = adapter->active_scan_time;
1105                        }
1106
1107                        scan_chan_list[chan_idx].min_scan_time =
1108                                cpu_to_le16(scan_dur);
1109                        scan_chan_list[chan_idx].max_scan_time =
1110                                cpu_to_le16(scan_dur);
1111                }
1112
1113                /* Check if we are only scanning the current channel */
1114                if ((chan_idx == 1) &&
1115                    (user_scan_in->chan_list[0].chan_number ==
1116                     priv->curr_bss_params.bss_descriptor.channel)) {
1117                        *scan_current_only = true;
1118                        mwifiex_dbg(adapter, INFO,
1119                                    "info: Scan: Scanning current channel only\n");
1120                }
1121        } else {
1122                mwifiex_dbg(adapter, INFO,
1123                            "info: Scan: Creating full region channel list\n");
1124                mwifiex_scan_create_channel_list(priv, user_scan_in,
1125                                                 scan_chan_list,
1126                                                 *filtered_scan);
1127        }
1128
1129}
1130
1131/*
1132 * This function inspects the scan response buffer for pointers to
1133 * expected TLVs.
1134 *
1135 * TLVs can be included at the end of the scan response BSS information.
1136 *
1137 * Data in the buffer is parsed pointers to TLVs that can potentially
1138 * be passed back in the response.
1139 */
1140static void
1141mwifiex_ret_802_11_scan_get_tlv_ptrs(struct mwifiex_adapter *adapter,
1142                                     struct mwifiex_ie_types_data *tlv,
1143                                     u32 tlv_buf_size, u32 req_tlv_type,
1144                                     struct mwifiex_ie_types_data **tlv_data)
1145{
1146        struct mwifiex_ie_types_data *current_tlv;
1147        u32 tlv_buf_left;
1148        u32 tlv_type;
1149        u32 tlv_len;
1150
1151        current_tlv = tlv;
1152        tlv_buf_left = tlv_buf_size;
1153        *tlv_data = NULL;
1154
1155        mwifiex_dbg(adapter, INFO,
1156                    "info: SCAN_RESP: tlv_buf_size = %d\n",
1157                    tlv_buf_size);
1158
1159        while (tlv_buf_left >= sizeof(struct mwifiex_ie_types_header)) {
1160
1161                tlv_type = le16_to_cpu(current_tlv->header.type);
1162                tlv_len = le16_to_cpu(current_tlv->header.len);
1163
1164                if (sizeof(tlv->header) + tlv_len > tlv_buf_left) {
1165                        mwifiex_dbg(adapter, ERROR,
1166                                    "SCAN_RESP: TLV buffer corrupt\n");
1167                        break;
1168                }
1169
1170                if (req_tlv_type == tlv_type) {
1171                        switch (tlv_type) {
1172                        case TLV_TYPE_TSFTIMESTAMP:
1173                                mwifiex_dbg(adapter, INFO,
1174                                            "info: SCAN_RESP: TSF\t"
1175                                            "timestamp TLV, len = %d\n",
1176                                            tlv_len);
1177                                *tlv_data = current_tlv;
1178                                break;
1179                        case TLV_TYPE_CHANNELBANDLIST:
1180                                mwifiex_dbg(adapter, INFO,
1181                                            "info: SCAN_RESP: channel\t"
1182                                            "band list TLV, len = %d\n",
1183                                            tlv_len);
1184                                *tlv_data = current_tlv;
1185                                break;
1186                        default:
1187                                mwifiex_dbg(adapter, ERROR,
1188                                            "SCAN_RESP: unhandled TLV = %d\n",
1189                                            tlv_type);
1190                                /* Give up, this seems corrupted */
1191                                return;
1192                        }
1193                }
1194
1195                if (*tlv_data)
1196                        break;
1197
1198
1199                tlv_buf_left -= (sizeof(tlv->header) + tlv_len);
1200                current_tlv =
1201                        (struct mwifiex_ie_types_data *) (current_tlv->data +
1202                                                          tlv_len);
1203
1204        }                       /* while */
1205}
1206
1207/*
1208 * This function parses provided beacon buffer and updates
1209 * respective fields in bss descriptor structure.
1210 */
1211int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
1212                                    struct mwifiex_bssdescriptor *bss_entry)
1213{
1214        u8 element_id;
1215        struct ieee_types_fh_param_set *fh_param_set;
1216        struct ieee_types_ds_param_set *ds_param_set;
1217        struct ieee_types_cf_param_set *cf_param_set;
1218        struct ieee_types_ibss_param_set *ibss_param_set;
1219        u8 *current_ptr;
1220        u8 *rate;
1221        u8 element_len;
1222        u16 total_ie_len;
1223        u8 bytes_to_copy;
1224        u8 rate_size;
1225        u8 found_data_rate_ie;
1226        u32 bytes_left;
1227        struct ieee_types_vendor_specific *vendor_ie;
1228        const u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 };
1229        const u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 };
1230
1231        found_data_rate_ie = false;
1232        rate_size = 0;
1233        current_ptr = bss_entry->beacon_buf;
1234        bytes_left = bss_entry->beacon_buf_size;
1235
1236        /* Process variable IE */
1237        while (bytes_left >= 2) {
1238                element_id = *current_ptr;
1239                element_len = *(current_ptr + 1);
1240                total_ie_len = element_len + sizeof(struct ieee_types_header);
1241
1242                if (bytes_left < total_ie_len) {
1243                        mwifiex_dbg(adapter, ERROR,
1244                                    "err: InterpretIE: in processing\t"
1245                                    "IE, bytes left < IE length\n");
1246                        return -EINVAL;
1247                }
1248                switch (element_id) {
1249                case WLAN_EID_SSID:
1250                        if (element_len > IEEE80211_MAX_SSID_LEN)
1251                                return -EINVAL;
1252                        bss_entry->ssid.ssid_len = element_len;
1253                        memcpy(bss_entry->ssid.ssid, (current_ptr + 2),
1254                               element_len);
1255                        mwifiex_dbg(adapter, INFO,
1256                                    "info: InterpretIE: ssid: %-32s\n",
1257                                    bss_entry->ssid.ssid);
1258                        break;
1259
1260                case WLAN_EID_SUPP_RATES:
1261                        if (element_len > MWIFIEX_SUPPORTED_RATES)
1262                                return -EINVAL;
1263                        memcpy(bss_entry->data_rates, current_ptr + 2,
1264                               element_len);
1265                        memcpy(bss_entry->supported_rates, current_ptr + 2,
1266                               element_len);
1267                        rate_size = element_len;
1268                        found_data_rate_ie = true;
1269                        break;
1270
1271                case WLAN_EID_FH_PARAMS:
1272                        if (total_ie_len < sizeof(*fh_param_set))
1273                                return -EINVAL;
1274                        fh_param_set =
1275                                (struct ieee_types_fh_param_set *) current_ptr;
1276                        memcpy(&bss_entry->phy_param_set.fh_param_set,
1277                               fh_param_set,
1278                               sizeof(struct ieee_types_fh_param_set));
1279                        break;
1280
1281                case WLAN_EID_DS_PARAMS:
1282                        if (total_ie_len < sizeof(*ds_param_set))
1283                                return -EINVAL;
1284                        ds_param_set =
1285                                (struct ieee_types_ds_param_set *) current_ptr;
1286
1287                        bss_entry->channel = ds_param_set->current_chan;
1288
1289                        memcpy(&bss_entry->phy_param_set.ds_param_set,
1290                               ds_param_set,
1291                               sizeof(struct ieee_types_ds_param_set));
1292                        break;
1293
1294                case WLAN_EID_CF_PARAMS:
1295                        if (total_ie_len < sizeof(*cf_param_set))
1296                                return -EINVAL;
1297                        cf_param_set =
1298                                (struct ieee_types_cf_param_set *) current_ptr;
1299                        memcpy(&bss_entry->ss_param_set.cf_param_set,
1300                               cf_param_set,
1301                               sizeof(struct ieee_types_cf_param_set));
1302                        break;
1303
1304                case WLAN_EID_IBSS_PARAMS:
1305                        if (total_ie_len < sizeof(*ibss_param_set))
1306                                return -EINVAL;
1307                        ibss_param_set =
1308                                (struct ieee_types_ibss_param_set *)
1309                                current_ptr;
1310                        memcpy(&bss_entry->ss_param_set.ibss_param_set,
1311                               ibss_param_set,
1312                               sizeof(struct ieee_types_ibss_param_set));
1313                        break;
1314
1315                case WLAN_EID_ERP_INFO:
1316                        if (!element_len)
1317                                return -EINVAL;
1318                        bss_entry->erp_flags = *(current_ptr + 2);
1319                        break;
1320
1321                case WLAN_EID_PWR_CONSTRAINT:
1322                        if (!element_len)
1323                                return -EINVAL;
1324                        bss_entry->local_constraint = *(current_ptr + 2);
1325                        bss_entry->sensed_11h = true;
1326                        break;
1327
1328                case WLAN_EID_CHANNEL_SWITCH:
1329                        bss_entry->chan_sw_ie_present = true;
1330                        fallthrough;
1331                case WLAN_EID_PWR_CAPABILITY:
1332                case WLAN_EID_TPC_REPORT:
1333                case WLAN_EID_QUIET:
1334                        bss_entry->sensed_11h = true;
1335                    break;
1336
1337                case WLAN_EID_EXT_SUPP_RATES:
1338                        /*
1339                         * Only process extended supported rate
1340                         * if data rate is already found.
1341                         * Data rate IE should come before
1342                         * extended supported rate IE
1343                         */
1344                        if (found_data_rate_ie) {
1345                                if ((element_len + rate_size) >
1346                                    MWIFIEX_SUPPORTED_RATES)
1347                                        bytes_to_copy =
1348                                                (MWIFIEX_SUPPORTED_RATES -
1349                                                 rate_size);
1350                                else
1351                                        bytes_to_copy = element_len;
1352
1353                                rate = (u8 *) bss_entry->data_rates;
1354                                rate += rate_size;
1355                                memcpy(rate, current_ptr + 2, bytes_to_copy);
1356
1357                                rate = (u8 *) bss_entry->supported_rates;
1358                                rate += rate_size;
1359                                memcpy(rate, current_ptr + 2, bytes_to_copy);
1360                        }
1361                        break;
1362
1363                case WLAN_EID_VENDOR_SPECIFIC:
1364                        vendor_ie = (struct ieee_types_vendor_specific *)
1365                                        current_ptr;
1366
1367                        /* 802.11 requires at least 3-byte OUI. */
1368                        if (element_len < sizeof(vendor_ie->vend_hdr.oui.oui))
1369                                return -EINVAL;
1370
1371                        /* Not long enough for a match? Skip it. */
1372                        if (element_len < sizeof(wpa_oui))
1373                                break;
1374
1375                        if (!memcmp(&vendor_ie->vend_hdr.oui, wpa_oui,
1376                                    sizeof(wpa_oui))) {
1377                                bss_entry->bcn_wpa_ie =
1378                                        (struct ieee_types_vendor_specific *)
1379                                        current_ptr;
1380                                bss_entry->wpa_offset = (u16)
1381                                        (current_ptr - bss_entry->beacon_buf);
1382                        } else if (!memcmp(&vendor_ie->vend_hdr.oui, wmm_oui,
1383                                    sizeof(wmm_oui))) {
1384                                if (total_ie_len ==
1385                                    sizeof(struct ieee_types_wmm_parameter) ||
1386                                    total_ie_len ==
1387                                    sizeof(struct ieee_types_wmm_info))
1388                                        /*
1389                                         * Only accept and copy the WMM IE if
1390                                         * it matches the size expected for the
1391                                         * WMM Info IE or the WMM Parameter IE.
1392                                         */
1393                                        memcpy((u8 *) &bss_entry->wmm_ie,
1394                                               current_ptr, total_ie_len);
1395                        }
1396                        break;
1397                case WLAN_EID_RSN:
1398                        bss_entry->bcn_rsn_ie =
1399                                (struct ieee_types_generic *) current_ptr;
1400                        bss_entry->rsn_offset = (u16) (current_ptr -
1401                                                        bss_entry->beacon_buf);
1402                        break;
1403                case WLAN_EID_BSS_AC_ACCESS_DELAY:
1404                        bss_entry->bcn_wapi_ie =
1405                                (struct ieee_types_generic *) current_ptr;
1406                        bss_entry->wapi_offset = (u16) (current_ptr -
1407                                                        bss_entry->beacon_buf);
1408                        break;
1409                case WLAN_EID_HT_CAPABILITY:
1410                        bss_entry->bcn_ht_cap = (struct ieee80211_ht_cap *)
1411                                        (current_ptr +
1412                                        sizeof(struct ieee_types_header));
1413                        bss_entry->ht_cap_offset = (u16) (current_ptr +
1414                                        sizeof(struct ieee_types_header) -
1415                                        bss_entry->beacon_buf);
1416                        break;
1417                case WLAN_EID_HT_OPERATION:
1418                        bss_entry->bcn_ht_oper =
1419                                (struct ieee80211_ht_operation *)(current_ptr +
1420                                        sizeof(struct ieee_types_header));
1421                        bss_entry->ht_info_offset = (u16) (current_ptr +
1422                                        sizeof(struct ieee_types_header) -
1423                                        bss_entry->beacon_buf);
1424                        break;
1425                case WLAN_EID_VHT_CAPABILITY:
1426                        bss_entry->disable_11ac = false;
1427                        bss_entry->bcn_vht_cap =
1428                                (void *)(current_ptr +
1429                                         sizeof(struct ieee_types_header));
1430                        bss_entry->vht_cap_offset =
1431                                        (u16)((u8 *)bss_entry->bcn_vht_cap -
1432                                              bss_entry->beacon_buf);
1433                        break;
1434                case WLAN_EID_VHT_OPERATION:
1435                        bss_entry->bcn_vht_oper =
1436                                (void *)(current_ptr +
1437                                         sizeof(struct ieee_types_header));
1438                        bss_entry->vht_info_offset =
1439                                        (u16)((u8 *)bss_entry->bcn_vht_oper -
1440                                              bss_entry->beacon_buf);
1441                        break;
1442                case WLAN_EID_BSS_COEX_2040:
1443                        bss_entry->bcn_bss_co_2040 = current_ptr;
1444                        bss_entry->bss_co_2040_offset =
1445                                (u16) (current_ptr - bss_entry->beacon_buf);
1446                        break;
1447                case WLAN_EID_EXT_CAPABILITY:
1448                        bss_entry->bcn_ext_cap = current_ptr;
1449                        bss_entry->ext_cap_offset =
1450                                (u16) (current_ptr - bss_entry->beacon_buf);
1451                        break;
1452                case WLAN_EID_OPMODE_NOTIF:
1453                        bss_entry->oper_mode = (void *)current_ptr;
1454                        bss_entry->oper_mode_offset =
1455                                        (u16)((u8 *)bss_entry->oper_mode -
1456                                              bss_entry->beacon_buf);
1457                        break;
1458                default:
1459                        break;
1460                }
1461
1462                current_ptr += total_ie_len;
1463                bytes_left -= total_ie_len;
1464
1465        }       /* while (bytes_left > 2) */
1466        return 0;
1467}
1468
1469/*
1470 * This function converts radio type scan parameter to a band configuration
1471 * to be used in join command.
1472 */
1473static u8
1474mwifiex_radio_type_to_band(u8 radio_type)
1475{
1476        switch (radio_type) {
1477        case HostCmd_SCAN_RADIO_TYPE_A:
1478                return BAND_A;
1479        case HostCmd_SCAN_RADIO_TYPE_BG:
1480        default:
1481                return BAND_G;
1482        }
1483}
1484
1485/*
1486 * This is an internal function used to start a scan based on an input
1487 * configuration.
1488 *
1489 * This uses the input user scan configuration information when provided in
1490 * order to send the appropriate scan commands to firmware to populate or
1491 * update the internal driver scan table.
1492 */
1493int mwifiex_scan_networks(struct mwifiex_private *priv,
1494                          const struct mwifiex_user_scan_cfg *user_scan_in)
1495{
1496        int ret;
1497        struct mwifiex_adapter *adapter = priv->adapter;
1498        struct cmd_ctrl_node *cmd_node;
1499        union mwifiex_scan_cmd_config_tlv *scan_cfg_out;
1500        struct mwifiex_ie_types_chan_list_param_set *chan_list_out;
1501        struct mwifiex_chan_scan_param_set *scan_chan_list;
1502        u8 filtered_scan;
1503        u8 scan_current_chan_only;
1504        u8 max_chan_per_scan;
1505
1506        if (adapter->scan_processing) {
1507                mwifiex_dbg(adapter, WARN,
1508                            "cmd: Scan already in process...\n");
1509                return -EBUSY;
1510        }
1511
1512        if (priv->scan_block) {
1513                mwifiex_dbg(adapter, WARN,
1514                            "cmd: Scan is blocked during association...\n");
1515                return -EBUSY;
1516        }
1517
1518        if (test_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags) ||
1519            test_bit(MWIFIEX_IS_CMD_TIMEDOUT, &adapter->work_flags)) {
1520                mwifiex_dbg(adapter, ERROR,
1521                            "Ignore scan. Card removed or firmware in bad state\n");
1522                return -EFAULT;
1523        }
1524
1525        spin_lock_bh(&adapter->mwifiex_cmd_lock);
1526        adapter->scan_processing = true;
1527        spin_unlock_bh(&adapter->mwifiex_cmd_lock);
1528
1529        scan_cfg_out = kzalloc(sizeof(union mwifiex_scan_cmd_config_tlv),
1530                               GFP_KERNEL);
1531        if (!scan_cfg_out) {
1532                ret = -ENOMEM;
1533                goto done;
1534        }
1535
1536        scan_chan_list = kcalloc(MWIFIEX_USER_SCAN_CHAN_MAX,
1537                                 sizeof(struct mwifiex_chan_scan_param_set),
1538                                 GFP_KERNEL);
1539        if (!scan_chan_list) {
1540                kfree(scan_cfg_out);
1541                ret = -ENOMEM;
1542                goto done;
1543        }
1544
1545        mwifiex_config_scan(priv, user_scan_in, &scan_cfg_out->config,
1546                            &chan_list_out, scan_chan_list, &max_chan_per_scan,
1547                            &filtered_scan, &scan_current_chan_only);
1548
1549        ret = mwifiex_scan_channel_list(priv, max_chan_per_scan, filtered_scan,
1550                                        &scan_cfg_out->config, chan_list_out,
1551                                        scan_chan_list);
1552
1553        /* Get scan command from scan_pending_q and put to cmd_pending_q */
1554        if (!ret) {
1555                spin_lock_bh(&adapter->scan_pending_q_lock);
1556                if (!list_empty(&adapter->scan_pending_q)) {
1557                        cmd_node = list_first_entry(&adapter->scan_pending_q,
1558                                                    struct cmd_ctrl_node, list);
1559                        list_del(&cmd_node->list);
1560                        spin_unlock_bh(&adapter->scan_pending_q_lock);
1561                        mwifiex_insert_cmd_to_pending_q(adapter, cmd_node);
1562                        queue_work(adapter->workqueue, &adapter->main_work);
1563
1564                        /* Perform internal scan synchronously */
1565                        if (!priv->scan_request) {
1566                                mwifiex_dbg(adapter, INFO,
1567                                            "wait internal scan\n");
1568                                mwifiex_wait_queue_complete(adapter, cmd_node);
1569                        }
1570                } else {
1571                        spin_unlock_bh(&adapter->scan_pending_q_lock);
1572                }
1573        }
1574
1575        kfree(scan_cfg_out);
1576        kfree(scan_chan_list);
1577done:
1578        if (ret) {
1579                spin_lock_bh(&adapter->mwifiex_cmd_lock);
1580                adapter->scan_processing = false;
1581                spin_unlock_bh(&adapter->mwifiex_cmd_lock);
1582        }
1583        return ret;
1584}
1585
1586/*
1587 * This function prepares a scan command to be sent to the firmware.
1588 *
1589 * This uses the scan command configuration sent to the command processing
1590 * module in command preparation stage to configure a scan command structure
1591 * to send to firmware.
1592 *
1593 * The fixed fields specifying the BSS type and BSSID filters as well as a
1594 * variable number/length of TLVs are sent in the command to firmware.
1595 *
1596 * Preparation also includes -
1597 *      - Setting command ID, and proper size
1598 *      - Ensuring correct endian-ness
1599 */
1600int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd,
1601                            struct mwifiex_scan_cmd_config *scan_cfg)
1602{
1603        struct host_cmd_ds_802_11_scan *scan_cmd = &cmd->params.scan;
1604
1605        /* Set fixed field variables in scan command */
1606        scan_cmd->bss_mode = scan_cfg->bss_mode;
1607        memcpy(scan_cmd->bssid, scan_cfg->specific_bssid,
1608               sizeof(scan_cmd->bssid));
1609        memcpy(scan_cmd->tlv_buffer, scan_cfg->tlv_buf, scan_cfg->tlv_buf_len);
1610
1611        cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SCAN);
1612
1613        /* Size is equal to the sizeof(fixed portions) + the TLV len + header */
1614        cmd->size = cpu_to_le16((u16) (sizeof(scan_cmd->bss_mode)
1615                                          + sizeof(scan_cmd->bssid)
1616                                          + scan_cfg->tlv_buf_len + S_DS_GEN));
1617
1618        return 0;
1619}
1620
1621/*
1622 * This function checks compatibility of requested network with current
1623 * driver settings.
1624 */
1625int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
1626                                        struct mwifiex_bssdescriptor *bss_desc)
1627{
1628        int ret = -1;
1629
1630        if (!bss_desc)
1631                return -1;
1632
1633        if ((mwifiex_get_cfp(priv, (u8) bss_desc->bss_band,
1634                             (u16) bss_desc->channel, 0))) {
1635                switch (priv->bss_mode) {
1636                case NL80211_IFTYPE_STATION:
1637                case NL80211_IFTYPE_ADHOC:
1638                        ret = mwifiex_is_network_compatible(priv, bss_desc,
1639                                                            priv->bss_mode);
1640                        if (ret)
1641                                mwifiex_dbg(priv->adapter, ERROR,
1642                                            "Incompatible network settings\n");
1643                        break;
1644                default:
1645                        ret = 0;
1646                }
1647        }
1648
1649        return ret;
1650}
1651
1652/* This function checks if SSID string contains all zeroes or length is zero */
1653static bool mwifiex_is_hidden_ssid(struct cfg80211_ssid *ssid)
1654{
1655        int idx;
1656
1657        for (idx = 0; idx < ssid->ssid_len; idx++) {
1658                if (ssid->ssid[idx])
1659                        return false;
1660        }
1661
1662        return true;
1663}
1664
1665/* This function checks if any hidden SSID found in passive scan channels
1666 * and save those channels for specific SSID active scan
1667 */
1668static int mwifiex_save_hidden_ssid_channels(struct mwifiex_private *priv,
1669                                             struct cfg80211_bss *bss)
1670{
1671        struct mwifiex_bssdescriptor *bss_desc;
1672        int ret;
1673        int chid;
1674
1675        /* Allocate and fill new bss descriptor */
1676        bss_desc = kzalloc(sizeof(*bss_desc), GFP_KERNEL);
1677        if (!bss_desc)
1678                return -ENOMEM;
1679
1680        ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc);
1681        if (ret)
1682                goto done;
1683
1684        if (mwifiex_is_hidden_ssid(&bss_desc->ssid)) {
1685                mwifiex_dbg(priv->adapter, INFO, "found hidden SSID\n");
1686                for (chid = 0 ; chid < MWIFIEX_USER_SCAN_CHAN_MAX; chid++) {
1687                        if (priv->hidden_chan[chid].chan_number ==
1688                            bss->channel->hw_value)
1689                                break;
1690
1691                        if (!priv->hidden_chan[chid].chan_number) {
1692                                priv->hidden_chan[chid].chan_number =
1693                                        bss->channel->hw_value;
1694                                priv->hidden_chan[chid].radio_type =
1695                                        bss->channel->band;
1696                                priv->hidden_chan[chid].scan_type =
1697                                        MWIFIEX_SCAN_TYPE_ACTIVE;
1698                                break;
1699                        }
1700                }
1701        }
1702
1703done:
1704        /* beacon_ie buffer was allocated in function
1705         * mwifiex_fill_new_bss_desc(). Free it now.
1706         */
1707        kfree(bss_desc->beacon_buf);
1708        kfree(bss_desc);
1709        return 0;
1710}
1711
1712static int mwifiex_update_curr_bss_params(struct mwifiex_private *priv,
1713                                          struct cfg80211_bss *bss)
1714{
1715        struct mwifiex_bssdescriptor *bss_desc;
1716        int ret;
1717
1718        /* Allocate and fill new bss descriptor */
1719        bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor), GFP_KERNEL);
1720        if (!bss_desc)
1721                return -ENOMEM;
1722
1723        ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc);
1724        if (ret)
1725                goto done;
1726
1727        ret = mwifiex_check_network_compatibility(priv, bss_desc);
1728        if (ret)
1729                goto done;
1730
1731        spin_lock_bh(&priv->curr_bcn_buf_lock);
1732        /* Make a copy of current BSSID descriptor */
1733        memcpy(&priv->curr_bss_params.bss_descriptor, bss_desc,
1734               sizeof(priv->curr_bss_params.bss_descriptor));
1735
1736        /* The contents of beacon_ie will be copied to its own buffer
1737         * in mwifiex_save_curr_bcn()
1738         */
1739        mwifiex_save_curr_bcn(priv);
1740        spin_unlock_bh(&priv->curr_bcn_buf_lock);
1741
1742done:
1743        /* beacon_ie buffer was allocated in function
1744         * mwifiex_fill_new_bss_desc(). Free it now.
1745         */
1746        kfree(bss_desc->beacon_buf);
1747        kfree(bss_desc);
1748        return 0;
1749}
1750
1751static int
1752mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info,
1753                                  u32 *bytes_left, u64 fw_tsf, u8 *radio_type,
1754                                  bool ext_scan, s32 rssi_val)
1755{
1756        struct mwifiex_adapter *adapter = priv->adapter;
1757        struct mwifiex_chan_freq_power *cfp;
1758        struct cfg80211_bss *bss;
1759        u8 bssid[ETH_ALEN];
1760        s32 rssi;
1761        const u8 *ie_buf;
1762        size_t ie_len;
1763        u16 channel = 0;
1764        u16 beacon_size = 0;
1765        u32 curr_bcn_bytes;
1766        u32 freq;
1767        u16 beacon_period;
1768        u16 cap_info_bitmap;
1769        u8 *current_ptr;
1770        u64 timestamp;
1771        struct mwifiex_fixed_bcn_param *bcn_param;
1772        struct mwifiex_bss_priv *bss_priv;
1773
1774        if (*bytes_left >= sizeof(beacon_size)) {
1775                /* Extract & convert beacon size from command buffer */
1776                beacon_size = get_unaligned_le16((*bss_info));
1777                *bytes_left -= sizeof(beacon_size);
1778                *bss_info += sizeof(beacon_size);
1779        }
1780
1781        if (!beacon_size || beacon_size > *bytes_left) {
1782                *bss_info += *bytes_left;
1783                *bytes_left = 0;
1784                return -EFAULT;
1785        }
1786
1787        /* Initialize the current working beacon pointer for this BSS
1788         * iteration
1789         */
1790        current_ptr = *bss_info;
1791
1792        /* Advance the return beacon pointer past the current beacon */
1793        *bss_info += beacon_size;
1794        *bytes_left -= beacon_size;
1795
1796        curr_bcn_bytes = beacon_size;
1797
1798        /* First 5 fields are bssid, RSSI(for legacy scan only),
1799         * time stamp, beacon interval, and capability information
1800         */
1801        if (curr_bcn_bytes < ETH_ALEN + sizeof(u8) +
1802            sizeof(struct mwifiex_fixed_bcn_param)) {
1803                mwifiex_dbg(adapter, ERROR,
1804                            "InterpretIE: not enough bytes left\n");
1805                return -EFAULT;
1806        }
1807
1808        memcpy(bssid, current_ptr, ETH_ALEN);
1809        current_ptr += ETH_ALEN;
1810        curr_bcn_bytes -= ETH_ALEN;
1811
1812        if (!ext_scan) {
1813                rssi = (s32) *current_ptr;
1814                rssi = (-rssi) * 100;           /* Convert dBm to mBm */
1815                current_ptr += sizeof(u8);
1816                curr_bcn_bytes -= sizeof(u8);
1817                mwifiex_dbg(adapter, INFO,
1818                            "info: InterpretIE: RSSI=%d\n", rssi);
1819        } else {
1820                rssi = rssi_val;
1821        }
1822
1823        bcn_param = (struct mwifiex_fixed_bcn_param *)current_ptr;
1824        current_ptr += sizeof(*bcn_param);
1825        curr_bcn_bytes -= sizeof(*bcn_param);
1826
1827        timestamp = le64_to_cpu(bcn_param->timestamp);
1828        beacon_period = le16_to_cpu(bcn_param->beacon_period);
1829
1830        cap_info_bitmap = le16_to_cpu(bcn_param->cap_info_bitmap);
1831        mwifiex_dbg(adapter, INFO,
1832                    "info: InterpretIE: capabilities=0x%X\n",
1833                    cap_info_bitmap);
1834
1835        /* Rest of the current buffer are IE's */
1836        ie_buf = current_ptr;
1837        ie_len = curr_bcn_bytes;
1838        mwifiex_dbg(adapter, INFO,
1839                    "info: InterpretIE: IELength for this AP = %d\n",
1840                    curr_bcn_bytes);
1841
1842        while (curr_bcn_bytes >= sizeof(struct ieee_types_header)) {
1843                u8 element_id, element_len;
1844
1845                element_id = *current_ptr;
1846                element_len = *(current_ptr + 1);
1847                if (curr_bcn_bytes < element_len +
1848                                sizeof(struct ieee_types_header)) {
1849                        mwifiex_dbg(adapter, ERROR,
1850                                    "%s: bytes left < IE length\n", __func__);
1851                        return -EFAULT;
1852                }
1853                if (element_id == WLAN_EID_DS_PARAMS) {
1854                        channel = *(current_ptr +
1855                                    sizeof(struct ieee_types_header));
1856                        break;
1857                }
1858
1859                current_ptr += element_len + sizeof(struct ieee_types_header);
1860                curr_bcn_bytes -= element_len +
1861                                        sizeof(struct ieee_types_header);
1862        }
1863
1864        if (channel) {
1865                struct ieee80211_channel *chan;
1866                u8 band;
1867
1868                /* Skip entry if on csa closed channel */
1869                if (channel == priv->csa_chan) {
1870                        mwifiex_dbg(adapter, WARN,
1871                                    "Dropping entry on csa closed channel\n");
1872                        return 0;
1873                }
1874
1875                band = BAND_G;
1876                if (radio_type)
1877                        band = mwifiex_radio_type_to_band(*radio_type &
1878                                                          (BIT(0) | BIT(1)));
1879
1880                cfp = mwifiex_get_cfp(priv, band, channel, 0);
1881
1882                freq = cfp ? cfp->freq : 0;
1883
1884                chan = ieee80211_get_channel(priv->wdev.wiphy, freq);
1885
1886                if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) {
1887                        bss = cfg80211_inform_bss(priv->wdev.wiphy,
1888                                            chan, CFG80211_BSS_FTYPE_UNKNOWN,
1889                                            bssid, timestamp,
1890                                            cap_info_bitmap, beacon_period,
1891                                            ie_buf, ie_len, rssi, GFP_ATOMIC);
1892                        if (bss) {
1893                                bss_priv = (struct mwifiex_bss_priv *)bss->priv;
1894                                bss_priv->band = band;
1895                                bss_priv->fw_tsf = fw_tsf;
1896                                if (priv->media_connected &&
1897                                    !memcmp(bssid, priv->curr_bss_params.
1898                                            bss_descriptor.mac_address,
1899                                            ETH_ALEN))
1900                                        mwifiex_update_curr_bss_params(priv,
1901                                                                       bss);
1902
1903                                if ((chan->flags & IEEE80211_CHAN_RADAR) ||
1904                                    (chan->flags & IEEE80211_CHAN_NO_IR)) {
1905                                        mwifiex_dbg(adapter, INFO,
1906                                                    "radar or passive channel %d\n",
1907                                                    channel);
1908                                        mwifiex_save_hidden_ssid_channels(priv,
1909                                                                          bss);
1910                                }
1911
1912                                cfg80211_put_bss(priv->wdev.wiphy, bss);
1913                        }
1914                }
1915        } else {
1916                mwifiex_dbg(adapter, WARN, "missing BSS channel IE\n");
1917        }
1918
1919        return 0;
1920}
1921
1922static void mwifiex_complete_scan(struct mwifiex_private *priv)
1923{
1924        struct mwifiex_adapter *adapter = priv->adapter;
1925
1926        adapter->survey_idx = 0;
1927        if (adapter->curr_cmd->wait_q_enabled) {
1928                adapter->cmd_wait_q.status = 0;
1929                if (!priv->scan_request) {
1930                        mwifiex_dbg(adapter, INFO,
1931                                    "complete internal scan\n");
1932                        mwifiex_complete_cmd(adapter, adapter->curr_cmd);
1933                }
1934        }
1935}
1936
1937/* This function checks if any hidden SSID found in passive scan channels
1938 * and do specific SSID active scan for those channels
1939 */
1940static int
1941mwifiex_active_scan_req_for_passive_chan(struct mwifiex_private *priv)
1942{
1943        int ret;
1944        struct mwifiex_adapter *adapter = priv->adapter;
1945        u8 id = 0;
1946        struct mwifiex_user_scan_cfg  *user_scan_cfg;
1947
1948        if (adapter->active_scan_triggered || !priv->scan_request ||
1949            priv->scan_aborting) {
1950                adapter->active_scan_triggered = false;
1951                return 0;
1952        }
1953
1954        if (!priv->hidden_chan[0].chan_number) {
1955                mwifiex_dbg(adapter, INFO, "No BSS with hidden SSID found on DFS channels\n");
1956                return 0;
1957        }
1958        user_scan_cfg = kzalloc(sizeof(*user_scan_cfg), GFP_KERNEL);
1959
1960        if (!user_scan_cfg)
1961                return -ENOMEM;
1962
1963        for (id = 0; id < MWIFIEX_USER_SCAN_CHAN_MAX; id++) {
1964                if (!priv->hidden_chan[id].chan_number)
1965                        break;
1966                memcpy(&user_scan_cfg->chan_list[id],
1967                       &priv->hidden_chan[id],
1968                       sizeof(struct mwifiex_user_scan_chan));
1969        }
1970
1971        adapter->active_scan_triggered = true;
1972        if (priv->scan_request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR)
1973                ether_addr_copy(user_scan_cfg->random_mac,
1974                                priv->scan_request->mac_addr);
1975        user_scan_cfg->num_ssids = priv->scan_request->n_ssids;
1976        user_scan_cfg->ssid_list = priv->scan_request->ssids;
1977
1978        ret = mwifiex_scan_networks(priv, user_scan_cfg);
1979        kfree(user_scan_cfg);
1980
1981        memset(&priv->hidden_chan, 0, sizeof(priv->hidden_chan));
1982
1983        if (ret) {
1984                dev_err(priv->adapter->dev, "scan failed: %d\n", ret);
1985                return ret;
1986        }
1987
1988        return 0;
1989}
1990static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)
1991{
1992        struct mwifiex_adapter *adapter = priv->adapter;
1993        struct cmd_ctrl_node *cmd_node;
1994
1995        spin_lock_bh(&adapter->scan_pending_q_lock);
1996        if (list_empty(&adapter->scan_pending_q)) {
1997                spin_unlock_bh(&adapter->scan_pending_q_lock);
1998
1999                spin_lock_bh(&adapter->mwifiex_cmd_lock);
2000                adapter->scan_processing = false;
2001                spin_unlock_bh(&adapter->mwifiex_cmd_lock);
2002
2003                mwifiex_active_scan_req_for_passive_chan(priv);
2004
2005                if (!adapter->ext_scan)
2006                        mwifiex_complete_scan(priv);
2007
2008                if (priv->scan_request) {
2009                        struct cfg80211_scan_info info = {
2010                                .aborted = false,
2011                        };
2012
2013                        mwifiex_dbg(adapter, INFO,
2014                                    "info: notifying scan done\n");
2015                        cfg80211_scan_done(priv->scan_request, &info);
2016                        priv->scan_request = NULL;
2017                        priv->scan_aborting = false;
2018                } else {
2019                        priv->scan_aborting = false;
2020                        mwifiex_dbg(adapter, INFO,
2021                                    "info: scan already aborted\n");
2022                }
2023        } else if ((priv->scan_aborting && !priv->scan_request) ||
2024                   priv->scan_block) {
2025                spin_unlock_bh(&adapter->scan_pending_q_lock);
2026
2027                mwifiex_cancel_pending_scan_cmd(adapter);
2028
2029                spin_lock_bh(&adapter->mwifiex_cmd_lock);
2030                adapter->scan_processing = false;
2031                spin_unlock_bh(&adapter->mwifiex_cmd_lock);
2032
2033                if (!adapter->active_scan_triggered) {
2034                        if (priv->scan_request) {
2035                                struct cfg80211_scan_info info = {
2036                                        .aborted = true,
2037                                };
2038
2039                                mwifiex_dbg(adapter, INFO,
2040                                            "info: aborting scan\n");
2041                                cfg80211_scan_done(priv->scan_request, &info);
2042                                priv->scan_request = NULL;
2043                                priv->scan_aborting = false;
2044                        } else {
2045                                priv->scan_aborting = false;
2046                                mwifiex_dbg(adapter, INFO,
2047                                            "info: scan already aborted\n");
2048                        }
2049                }
2050        } else {
2051                /* Get scan command from scan_pending_q and put to
2052                 * cmd_pending_q
2053                 */
2054                cmd_node = list_first_entry(&adapter->scan_pending_q,
2055                                            struct cmd_ctrl_node, list);
2056                list_del(&cmd_node->list);
2057                spin_unlock_bh(&adapter->scan_pending_q_lock);
2058                mwifiex_insert_cmd_to_pending_q(adapter, cmd_node);
2059        }
2060
2061        return;
2062}
2063
2064void mwifiex_cancel_scan(struct mwifiex_adapter *adapter)
2065{
2066        struct mwifiex_private *priv;
2067        int i;
2068
2069        mwifiex_cancel_pending_scan_cmd(adapter);
2070
2071        if (adapter->scan_processing) {
2072                spin_lock_bh(&adapter->mwifiex_cmd_lock);
2073                adapter->scan_processing = false;
2074                spin_unlock_bh(&adapter->mwifiex_cmd_lock);
2075                for (i = 0; i < adapter->priv_num; i++) {
2076                        priv = adapter->priv[i];
2077                        if (!priv)
2078                                continue;
2079                        if (priv->scan_request) {
2080                                struct cfg80211_scan_info info = {
2081                                        .aborted = true,
2082                                };
2083
2084                                mwifiex_dbg(adapter, INFO,
2085                                            "info: aborting scan\n");
2086                                cfg80211_scan_done(priv->scan_request, &info);
2087                                priv->scan_request = NULL;
2088                                priv->scan_aborting = false;
2089                        }
2090                }
2091        }
2092}
2093
2094/*
2095 * This function handles the command response of scan.
2096 *
2097 * The response buffer for the scan command has the following
2098 * memory layout:
2099 *
2100 *      .-------------------------------------------------------------.
2101 *      |  Header (4 * sizeof(t_u16)):  Standard command response hdr |
2102 *      .-------------------------------------------------------------.
2103 *      |  BufSize (t_u16) : sizeof the BSS Description data          |
2104 *      .-------------------------------------------------------------.
2105 *      |  NumOfSet (t_u8) : Number of BSS Descs returned             |
2106 *      .-------------------------------------------------------------.
2107 *      |  BSSDescription data (variable, size given in BufSize)      |
2108 *      .-------------------------------------------------------------.
2109 *      |  TLV data (variable, size calculated using Header->Size,    |
2110 *      |            BufSize and sizeof the fixed fields above)       |
2111 *      .-------------------------------------------------------------.
2112 */
2113int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
2114                            struct host_cmd_ds_command *resp)
2115{
2116        int ret = 0;
2117        struct mwifiex_adapter *adapter = priv->adapter;
2118        struct host_cmd_ds_802_11_scan_rsp *scan_rsp;
2119        struct mwifiex_ie_types_data *tlv_data;
2120        struct mwifiex_ie_types_tsf_timestamp *tsf_tlv;
2121        u8 *bss_info;
2122        u32 scan_resp_size;
2123        u32 bytes_left;
2124        u32 idx;
2125        u32 tlv_buf_size;
2126        struct mwifiex_ie_types_chan_band_list_param_set *chan_band_tlv;
2127        struct chan_band_param_set *chan_band;
2128        u8 is_bgscan_resp;
2129        __le64 fw_tsf = 0;
2130        u8 *radio_type;
2131        struct cfg80211_wowlan_nd_match *pmatch;
2132        struct cfg80211_sched_scan_request *nd_config = NULL;
2133
2134        is_bgscan_resp = (le16_to_cpu(resp->command)
2135                          == HostCmd_CMD_802_11_BG_SCAN_QUERY);
2136        if (is_bgscan_resp)
2137                scan_rsp = &resp->params.bg_scan_query_resp.scan_resp;
2138        else
2139                scan_rsp = &resp->params.scan_resp;
2140
2141
2142        if (scan_rsp->number_of_sets > MWIFIEX_MAX_AP) {
2143                mwifiex_dbg(adapter, ERROR,
2144                            "SCAN_RESP: too many AP returned (%d)\n",
2145                            scan_rsp->number_of_sets);
2146                ret = -1;
2147                goto check_next_scan;
2148        }
2149
2150        /* Check csa channel expiry before parsing scan response */
2151        mwifiex_11h_get_csa_closed_channel(priv);
2152
2153        bytes_left = le16_to_cpu(scan_rsp->bss_descript_size);
2154        mwifiex_dbg(adapter, INFO,
2155                    "info: SCAN_RESP: bss_descript_size %d\n",
2156                    bytes_left);
2157
2158        scan_resp_size = le16_to_cpu(resp->size);
2159
2160        mwifiex_dbg(adapter, INFO,
2161                    "info: SCAN_RESP: returned %d APs before parsing\n",
2162                    scan_rsp->number_of_sets);
2163
2164        bss_info = scan_rsp->bss_desc_and_tlv_buffer;
2165
2166        /*
2167         * The size of the TLV buffer is equal to the entire command response
2168         *   size (scan_resp_size) minus the fixed fields (sizeof()'s), the
2169         *   BSS Descriptions (bss_descript_size as bytesLef) and the command
2170         *   response header (S_DS_GEN)
2171         */
2172        tlv_buf_size = scan_resp_size - (bytes_left
2173                                         + sizeof(scan_rsp->bss_descript_size)
2174                                         + sizeof(scan_rsp->number_of_sets)
2175                                         + S_DS_GEN);
2176
2177        tlv_data = (struct mwifiex_ie_types_data *) (scan_rsp->
2178                                                 bss_desc_and_tlv_buffer +
2179                                                 bytes_left);
2180
2181        /* Search the TLV buffer space in the scan response for any valid
2182           TLVs */
2183        mwifiex_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size,
2184                                             TLV_TYPE_TSFTIMESTAMP,
2185                                             (struct mwifiex_ie_types_data **)
2186                                             &tsf_tlv);
2187
2188        /* Search the TLV buffer space in the scan response for any valid
2189           TLVs */
2190        mwifiex_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size,
2191                                             TLV_TYPE_CHANNELBANDLIST,
2192                                             (struct mwifiex_ie_types_data **)
2193                                             &chan_band_tlv);
2194
2195#ifdef CONFIG_PM
2196        if (priv->wdev.wiphy->wowlan_config)
2197                nd_config = priv->wdev.wiphy->wowlan_config->nd_config;
2198#endif
2199
2200        if (nd_config) {
2201                adapter->nd_info =
2202                        kzalloc(sizeof(struct cfg80211_wowlan_nd_match) +
2203                                sizeof(struct cfg80211_wowlan_nd_match *) *
2204                                scan_rsp->number_of_sets, GFP_ATOMIC);
2205
2206                if (adapter->nd_info)
2207                        adapter->nd_info->n_matches = scan_rsp->number_of_sets;
2208        }
2209
2210        for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) {
2211                /*
2212                 * If the TSF TLV was appended to the scan results, save this
2213                 * entry's TSF value in the fw_tsf field. It is the firmware's
2214                 * TSF value at the time the beacon or probe response was
2215                 * received.
2216                 */
2217                if (tsf_tlv)
2218                        memcpy(&fw_tsf, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE],
2219                               sizeof(fw_tsf));
2220
2221                if (chan_band_tlv) {
2222                        chan_band = &chan_band_tlv->chan_band_param[idx];
2223                        radio_type = &chan_band->radio_type;
2224                } else {
2225                        radio_type = NULL;
2226                }
2227
2228                if (chan_band_tlv && adapter->nd_info) {
2229                        adapter->nd_info->matches[idx] =
2230                                kzalloc(sizeof(*pmatch) + sizeof(u32),
2231                                        GFP_ATOMIC);
2232
2233                        pmatch = adapter->nd_info->matches[idx];
2234
2235                        if (pmatch) {
2236                                pmatch->n_channels = 1;
2237                                pmatch->channels[0] = chan_band->chan_number;
2238                        }
2239                }
2240
2241                ret = mwifiex_parse_single_response_buf(priv, &bss_info,
2242                                                        &bytes_left,
2243                                                        le64_to_cpu(fw_tsf),
2244                                                        radio_type, false, 0);
2245                if (ret)
2246                        goto check_next_scan;
2247        }
2248
2249check_next_scan:
2250        mwifiex_check_next_scan_command(priv);
2251        return ret;
2252}
2253
2254/*
2255 * This function prepares an extended scan command to be sent to the firmware
2256 *
2257 * This uses the scan command configuration sent to the command processing
2258 * module in command preparation stage to configure a extended scan command
2259 * structure to send to firmware.
2260 */
2261int mwifiex_cmd_802_11_scan_ext(struct mwifiex_private *priv,
2262                                struct host_cmd_ds_command *cmd,
2263                                void *data_buf)
2264{
2265        struct host_cmd_ds_802_11_scan_ext *ext_scan = &cmd->params.ext_scan;
2266        struct mwifiex_scan_cmd_config *scan_cfg = data_buf;
2267
2268        memcpy(ext_scan->tlv_buffer, scan_cfg->tlv_buf, scan_cfg->tlv_buf_len);
2269
2270        cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SCAN_EXT);
2271
2272        /* Size is equal to the sizeof(fixed portions) + the TLV len + header */
2273        cmd->size = cpu_to_le16((u16)(sizeof(ext_scan->reserved)
2274                                      + scan_cfg->tlv_buf_len + S_DS_GEN));
2275
2276        return 0;
2277}
2278
2279/* This function prepares an background scan config command to be sent
2280 * to the firmware
2281 */
2282int mwifiex_cmd_802_11_bg_scan_config(struct mwifiex_private *priv,
2283                                      struct host_cmd_ds_command *cmd,
2284                                      void *data_buf)
2285{
2286        struct host_cmd_ds_802_11_bg_scan_config *bgscan_config =
2287                                        &cmd->params.bg_scan_config;
2288        struct mwifiex_bg_scan_cfg *bgscan_cfg_in = data_buf;
2289        u8 *tlv_pos = bgscan_config->tlv;
2290        u8 num_probes;
2291        u32 ssid_len, chan_idx, scan_type, scan_dur, chan_num;
2292        int i;
2293        struct mwifiex_ie_types_num_probes *num_probes_tlv;
2294        struct mwifiex_ie_types_repeat_count *repeat_count_tlv;
2295        struct mwifiex_ie_types_min_rssi_threshold *rssi_threshold_tlv;
2296        struct mwifiex_ie_types_bgscan_start_later *start_later_tlv;
2297        struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv;
2298        struct mwifiex_ie_types_chan_list_param_set *chan_list_tlv;
2299        struct mwifiex_chan_scan_param_set *temp_chan;
2300
2301        cmd->command = cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_CONFIG);
2302        cmd->size = cpu_to_le16(sizeof(*bgscan_config) + S_DS_GEN);
2303
2304        bgscan_config->action = cpu_to_le16(bgscan_cfg_in->action);
2305        bgscan_config->enable = bgscan_cfg_in->enable;
2306        bgscan_config->bss_type = bgscan_cfg_in->bss_type;
2307        bgscan_config->scan_interval =
2308                cpu_to_le32(bgscan_cfg_in->scan_interval);
2309        bgscan_config->report_condition =
2310                cpu_to_le32(bgscan_cfg_in->report_condition);
2311
2312        /*  stop sched scan  */
2313        if (!bgscan_config->enable)
2314                return 0;
2315
2316        bgscan_config->chan_per_scan = bgscan_cfg_in->chan_per_scan;
2317
2318        num_probes = (bgscan_cfg_in->num_probes ? bgscan_cfg_in->
2319                      num_probes : priv->adapter->scan_probes);
2320
2321        if (num_probes) {
2322                num_probes_tlv = (struct mwifiex_ie_types_num_probes *)tlv_pos;
2323                num_probes_tlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES);
2324                num_probes_tlv->header.len =
2325                        cpu_to_le16(sizeof(num_probes_tlv->num_probes));
2326                num_probes_tlv->num_probes = cpu_to_le16((u16)num_probes);
2327
2328                tlv_pos += sizeof(num_probes_tlv->header) +
2329                        le16_to_cpu(num_probes_tlv->header.len);
2330        }
2331
2332        if (bgscan_cfg_in->repeat_count) {
2333                repeat_count_tlv =
2334                        (struct mwifiex_ie_types_repeat_count *)tlv_pos;
2335                repeat_count_tlv->header.type =
2336                        cpu_to_le16(TLV_TYPE_REPEAT_COUNT);
2337                repeat_count_tlv->header.len =
2338                        cpu_to_le16(sizeof(repeat_count_tlv->repeat_count));
2339                repeat_count_tlv->repeat_count =
2340                        cpu_to_le16(bgscan_cfg_in->repeat_count);
2341
2342                tlv_pos += sizeof(repeat_count_tlv->header) +
2343                        le16_to_cpu(repeat_count_tlv->header.len);
2344        }
2345
2346        if (bgscan_cfg_in->rssi_threshold) {
2347                rssi_threshold_tlv =
2348                        (struct mwifiex_ie_types_min_rssi_threshold *)tlv_pos;
2349                rssi_threshold_tlv->header.type =
2350                        cpu_to_le16(TLV_TYPE_RSSI_LOW);
2351                rssi_threshold_tlv->header.len =
2352                        cpu_to_le16(sizeof(rssi_threshold_tlv->rssi_threshold));
2353                rssi_threshold_tlv->rssi_threshold =
2354                        cpu_to_le16(bgscan_cfg_in->rssi_threshold);
2355
2356                tlv_pos += sizeof(rssi_threshold_tlv->header) +
2357                        le16_to_cpu(rssi_threshold_tlv->header.len);
2358        }
2359
2360        for (i = 0; i < bgscan_cfg_in->num_ssids; i++) {
2361                ssid_len = bgscan_cfg_in->ssid_list[i].ssid.ssid_len;
2362
2363                wildcard_ssid_tlv =
2364                        (struct mwifiex_ie_types_wildcard_ssid_params *)tlv_pos;
2365                wildcard_ssid_tlv->header.type =
2366                                cpu_to_le16(TLV_TYPE_WILDCARDSSID);
2367                wildcard_ssid_tlv->header.len = cpu_to_le16(
2368                                (u16)(ssid_len + sizeof(wildcard_ssid_tlv->
2369                                                         max_ssid_length)));
2370
2371                /* max_ssid_length = 0 tells firmware to perform
2372                 * specific scan for the SSID filled, whereas
2373                 * max_ssid_length = IEEE80211_MAX_SSID_LEN is for
2374                 * wildcard scan.
2375                 */
2376                if (ssid_len)
2377                        wildcard_ssid_tlv->max_ssid_length = 0;
2378                else
2379                        wildcard_ssid_tlv->max_ssid_length =
2380                                                IEEE80211_MAX_SSID_LEN;
2381
2382                memcpy(wildcard_ssid_tlv->ssid,
2383                       bgscan_cfg_in->ssid_list[i].ssid.ssid, ssid_len);
2384
2385                tlv_pos += (sizeof(wildcard_ssid_tlv->header)
2386                                + le16_to_cpu(wildcard_ssid_tlv->header.len));
2387        }
2388
2389        chan_list_tlv = (struct mwifiex_ie_types_chan_list_param_set *)tlv_pos;
2390
2391        if (bgscan_cfg_in->chan_list[0].chan_number) {
2392                dev_dbg(priv->adapter->dev, "info: bgscan: Using supplied channel list\n");
2393
2394                chan_list_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
2395
2396                for (chan_idx = 0;
2397                     chan_idx < MWIFIEX_BG_SCAN_CHAN_MAX &&
2398                     bgscan_cfg_in->chan_list[chan_idx].chan_number;
2399                     chan_idx++) {
2400                        temp_chan = chan_list_tlv->chan_scan_param + chan_idx;
2401
2402                        /* Increment the TLV header length by size appended */
2403                        le16_unaligned_add_cpu(&chan_list_tlv->header.len,
2404                                               sizeof(
2405                                               chan_list_tlv->chan_scan_param));
2406
2407                        temp_chan->chan_number =
2408                                bgscan_cfg_in->chan_list[chan_idx].chan_number;
2409                        temp_chan->radio_type =
2410                                bgscan_cfg_in->chan_list[chan_idx].radio_type;
2411
2412                        scan_type =
2413                                bgscan_cfg_in->chan_list[chan_idx].scan_type;
2414
2415                        if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
2416                                temp_chan->chan_scan_mode_bitmap
2417                                        |= MWIFIEX_PASSIVE_SCAN;
2418                        else
2419                                temp_chan->chan_scan_mode_bitmap
2420                                        &= ~MWIFIEX_PASSIVE_SCAN;
2421
2422                        if (bgscan_cfg_in->chan_list[chan_idx].scan_time) {
2423                                scan_dur = (u16)bgscan_cfg_in->
2424                                        chan_list[chan_idx].scan_time;
2425                        } else {
2426                                scan_dur = (scan_type ==
2427                                            MWIFIEX_SCAN_TYPE_PASSIVE) ?
2428                                            priv->adapter->passive_scan_time :
2429                                            priv->adapter->specific_scan_time;
2430                        }
2431
2432                        temp_chan->min_scan_time = cpu_to_le16(scan_dur);
2433                        temp_chan->max_scan_time = cpu_to_le16(scan_dur);
2434                }
2435        } else {
2436                dev_dbg(priv->adapter->dev,
2437                        "info: bgscan: Creating full region channel list\n");
2438                chan_num =
2439                        mwifiex_bgscan_create_channel_list(priv, bgscan_cfg_in,
2440                                                           chan_list_tlv->
2441                                                           chan_scan_param);
2442                le16_unaligned_add_cpu(&chan_list_tlv->header.len,
2443                                       chan_num *
2444                             sizeof(chan_list_tlv->chan_scan_param[0]));
2445        }
2446
2447        tlv_pos += (sizeof(chan_list_tlv->header)
2448                        + le16_to_cpu(chan_list_tlv->header.len));
2449
2450        if (bgscan_cfg_in->start_later) {
2451                start_later_tlv =
2452                        (struct mwifiex_ie_types_bgscan_start_later *)tlv_pos;
2453                start_later_tlv->header.type =
2454                        cpu_to_le16(TLV_TYPE_BGSCAN_START_LATER);
2455                start_later_tlv->header.len =
2456                        cpu_to_le16(sizeof(start_later_tlv->start_later));
2457                start_later_tlv->start_later =
2458                        cpu_to_le16(bgscan_cfg_in->start_later);
2459
2460                tlv_pos += sizeof(start_later_tlv->header) +
2461                        le16_to_cpu(start_later_tlv->header.len);
2462        }
2463
2464        /* Append vendor specific IE TLV */
2465        mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_BGSCAN, &tlv_pos);
2466
2467        le16_unaligned_add_cpu(&cmd->size, tlv_pos - bgscan_config->tlv);
2468
2469        return 0;
2470}
2471
2472int mwifiex_stop_bg_scan(struct mwifiex_private *priv)
2473{
2474        struct mwifiex_bg_scan_cfg *bgscan_cfg;
2475
2476        if (!priv->sched_scanning) {
2477                dev_dbg(priv->adapter->dev, "bgscan already stopped!\n");
2478                return 0;
2479        }
2480
2481        bgscan_cfg = kzalloc(sizeof(*bgscan_cfg), GFP_KERNEL);
2482        if (!bgscan_cfg)
2483                return -ENOMEM;
2484
2485        bgscan_cfg->bss_type = MWIFIEX_BSS_MODE_INFRA;
2486        bgscan_cfg->action = MWIFIEX_BGSCAN_ACT_SET;
2487        bgscan_cfg->enable = false;
2488
2489        if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11_BG_SCAN_CONFIG,
2490                             HostCmd_ACT_GEN_SET, 0, bgscan_cfg, true)) {
2491                kfree(bgscan_cfg);
2492                return -EFAULT;
2493        }
2494
2495        kfree(bgscan_cfg);
2496        priv->sched_scanning = false;
2497
2498        return 0;
2499}
2500
2501static void
2502mwifiex_update_chan_statistics(struct mwifiex_private *priv,
2503                               struct mwifiex_ietypes_chanstats *tlv_stat)
2504{
2505        struct mwifiex_adapter *adapter = priv->adapter;
2506        u8 i, num_chan;
2507        struct mwifiex_fw_chan_stats *fw_chan_stats;
2508        struct mwifiex_chan_stats chan_stats;
2509
2510        fw_chan_stats = (void *)((u8 *)tlv_stat +
2511                              sizeof(struct mwifiex_ie_types_header));
2512        num_chan = le16_to_cpu(tlv_stat->header.len) /
2513                                              sizeof(struct mwifiex_chan_stats);
2514
2515        for (i = 0 ; i < num_chan; i++) {
2516                if (adapter->survey_idx >= adapter->num_in_chan_stats) {
2517                        mwifiex_dbg(adapter, WARN,
2518                                    "FW reported too many channel results (max %d)\n",
2519                                    adapter->num_in_chan_stats);
2520                        return;
2521                }
2522                chan_stats.chan_num = fw_chan_stats->chan_num;
2523                chan_stats.bandcfg = fw_chan_stats->bandcfg;
2524                chan_stats.flags = fw_chan_stats->flags;
2525                chan_stats.noise = fw_chan_stats->noise;
2526                chan_stats.total_bss = le16_to_cpu(fw_chan_stats->total_bss);
2527                chan_stats.cca_scan_dur =
2528                                       le16_to_cpu(fw_chan_stats->cca_scan_dur);
2529                chan_stats.cca_busy_dur =
2530                                       le16_to_cpu(fw_chan_stats->cca_busy_dur);
2531                mwifiex_dbg(adapter, INFO,
2532                            "chan=%d, noise=%d, total_network=%d scan_duration=%d, busy_duration=%d\n",
2533                            chan_stats.chan_num,
2534                            chan_stats.noise,
2535                            chan_stats.total_bss,
2536                            chan_stats.cca_scan_dur,
2537                            chan_stats.cca_busy_dur);
2538                memcpy(&adapter->chan_stats[adapter->survey_idx++], &chan_stats,
2539                       sizeof(struct mwifiex_chan_stats));
2540                fw_chan_stats++;
2541        }
2542}
2543
2544/* This function handles the command response of extended scan */
2545int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv,
2546                                struct host_cmd_ds_command *resp)
2547{
2548        struct mwifiex_adapter *adapter = priv->adapter;
2549        struct host_cmd_ds_802_11_scan_ext *ext_scan_resp;
2550        struct mwifiex_ie_types_header *tlv;
2551        struct mwifiex_ietypes_chanstats *tlv_stat;
2552        u16 buf_left, type, len;
2553
2554        struct host_cmd_ds_command *cmd_ptr;
2555        struct cmd_ctrl_node *cmd_node;
2556        bool complete_scan = false;
2557
2558        mwifiex_dbg(adapter, INFO, "info: EXT scan returns successfully\n");
2559
2560        ext_scan_resp = &resp->params.ext_scan;
2561
2562        tlv = (void *)ext_scan_resp->tlv_buffer;
2563        buf_left = le16_to_cpu(resp->size) - (sizeof(*ext_scan_resp) + S_DS_GEN
2564                                              - 1);
2565
2566        while (buf_left >= sizeof(struct mwifiex_ie_types_header)) {
2567                type = le16_to_cpu(tlv->type);
2568                len = le16_to_cpu(tlv->len);
2569
2570                if (buf_left < (sizeof(struct mwifiex_ie_types_header) + len)) {
2571                        mwifiex_dbg(adapter, ERROR,
2572                                    "error processing scan response TLVs");
2573                        break;
2574                }
2575
2576                switch (type) {
2577                case TLV_TYPE_CHANNEL_STATS:
2578                        tlv_stat = (void *)tlv;
2579                        mwifiex_update_chan_statistics(priv, tlv_stat);
2580                        break;
2581                default:
2582                        break;
2583                }
2584
2585                buf_left -= len + sizeof(struct mwifiex_ie_types_header);
2586                tlv = (void *)((u8 *)tlv + len +
2587                               sizeof(struct mwifiex_ie_types_header));
2588        }
2589
2590        spin_lock_bh(&adapter->cmd_pending_q_lock);
2591        spin_lock_bh(&adapter->scan_pending_q_lock);
2592        if (list_empty(&adapter->scan_pending_q)) {
2593                complete_scan = true;
2594                list_for_each_entry(cmd_node, &adapter->cmd_pending_q, list) {
2595                        cmd_ptr = (void *)cmd_node->cmd_skb->data;
2596                        if (le16_to_cpu(cmd_ptr->command) ==
2597                            HostCmd_CMD_802_11_SCAN_EXT) {
2598                                mwifiex_dbg(adapter, INFO,
2599                                            "Scan pending in command pending list");
2600                                complete_scan = false;
2601                                break;
2602                        }
2603                }
2604        }
2605        spin_unlock_bh(&adapter->scan_pending_q_lock);
2606        spin_unlock_bh(&adapter->cmd_pending_q_lock);
2607
2608        if (complete_scan)
2609                mwifiex_complete_scan(priv);
2610
2611        return 0;
2612}
2613
2614/* This function This function handles the event extended scan report. It
2615 * parses extended scan results and informs to cfg80211 stack.
2616 */
2617int mwifiex_handle_event_ext_scan_report(struct mwifiex_private *priv,
2618                                         void *buf)
2619{
2620        int ret = 0;
2621        struct mwifiex_adapter *adapter = priv->adapter;
2622        u8 *bss_info;
2623        u32 bytes_left, bytes_left_for_tlv, idx;
2624        u16 type, len;
2625        struct mwifiex_ie_types_data *tlv;
2626        struct mwifiex_ie_types_bss_scan_rsp *scan_rsp_tlv;
2627        struct mwifiex_ie_types_bss_scan_info *scan_info_tlv;
2628        u8 *radio_type;
2629        u64 fw_tsf = 0;
2630        s32 rssi = 0;
2631        struct mwifiex_event_scan_result *event_scan = buf;
2632        u8 num_of_set = event_scan->num_of_set;
2633        u8 *scan_resp = buf + sizeof(struct mwifiex_event_scan_result);
2634        u16 scan_resp_size = le16_to_cpu(event_scan->buf_size);
2635
2636        if (num_of_set > MWIFIEX_MAX_AP) {
2637                mwifiex_dbg(adapter, ERROR,
2638                            "EXT_SCAN: Invalid number of AP returned (%d)!!\n",
2639                            num_of_set);
2640                ret = -1;
2641                goto check_next_scan;
2642        }
2643
2644        bytes_left = scan_resp_size;
2645        mwifiex_dbg(adapter, INFO,
2646                    "EXT_SCAN: size %d, returned %d APs...",
2647                    scan_resp_size, num_of_set);
2648        mwifiex_dbg_dump(adapter, CMD_D, "EXT_SCAN buffer:", buf,
2649                         scan_resp_size +
2650                         sizeof(struct mwifiex_event_scan_result));
2651
2652        tlv = (struct mwifiex_ie_types_data *)scan_resp;
2653
2654        for (idx = 0; idx < num_of_set && bytes_left; idx++) {
2655                type = le16_to_cpu(tlv->header.type);
2656                len = le16_to_cpu(tlv->header.len);
2657                if (bytes_left < sizeof(struct mwifiex_ie_types_header) + len) {
2658                        mwifiex_dbg(adapter, ERROR,
2659                                    "EXT_SCAN: Error bytes left < TLV length\n");
2660                        break;
2661                }
2662                scan_rsp_tlv = NULL;
2663                scan_info_tlv = NULL;
2664                bytes_left_for_tlv = bytes_left;
2665
2666                /* BSS response TLV with beacon or probe response buffer
2667                 * at the initial position of each descriptor
2668                 */
2669                if (type != TLV_TYPE_BSS_SCAN_RSP)
2670                        break;
2671
2672                bss_info = (u8 *)tlv;
2673                scan_rsp_tlv = (struct mwifiex_ie_types_bss_scan_rsp *)tlv;
2674                tlv = (struct mwifiex_ie_types_data *)(tlv->data + len);
2675                bytes_left_for_tlv -=
2676                                (len + sizeof(struct mwifiex_ie_types_header));
2677
2678                while (bytes_left_for_tlv >=
2679                       sizeof(struct mwifiex_ie_types_header) &&
2680                       le16_to_cpu(tlv->header.type) != TLV_TYPE_BSS_SCAN_RSP) {
2681                        type = le16_to_cpu(tlv->header.type);
2682                        len = le16_to_cpu(tlv->header.len);
2683                        if (bytes_left_for_tlv <
2684                            sizeof(struct mwifiex_ie_types_header) + len) {
2685                                mwifiex_dbg(adapter, ERROR,
2686                                            "EXT_SCAN: Error in processing TLV,\t"
2687                                            "bytes left < TLV length\n");
2688                                scan_rsp_tlv = NULL;
2689                                bytes_left_for_tlv = 0;
2690                                continue;
2691                        }
2692                        switch (type) {
2693                        case TLV_TYPE_BSS_SCAN_INFO:
2694                                scan_info_tlv =
2695                                  (struct mwifiex_ie_types_bss_scan_info *)tlv;
2696                                if (len !=
2697                                 sizeof(struct mwifiex_ie_types_bss_scan_info) -
2698                                 sizeof(struct mwifiex_ie_types_header)) {
2699                                        bytes_left_for_tlv = 0;
2700                                        continue;
2701                                }
2702                                break;
2703                        default:
2704                                break;
2705                        }
2706                        tlv = (struct mwifiex_ie_types_data *)(tlv->data + len);
2707                        bytes_left -=
2708                                (len + sizeof(struct mwifiex_ie_types_header));
2709                        bytes_left_for_tlv -=
2710                                (len + sizeof(struct mwifiex_ie_types_header));
2711                }
2712
2713                if (!scan_rsp_tlv)
2714                        break;
2715
2716                /* Advance pointer to the beacon buffer length and
2717                 * update the bytes count so that the function
2718                 * wlan_interpret_bss_desc_with_ie() can handle the
2719                 * scan buffer withut any change
2720                 */
2721                bss_info += sizeof(u16);
2722                bytes_left -= sizeof(u16);
2723
2724                if (scan_info_tlv) {
2725                        rssi = (s32)(s16)(le16_to_cpu(scan_info_tlv->rssi));
2726                        rssi *= 100;           /* Convert dBm to mBm */
2727                        mwifiex_dbg(adapter, INFO,
2728                                    "info: InterpretIE: RSSI=%d\n", rssi);
2729                        fw_tsf = le64_to_cpu(scan_info_tlv->tsf);
2730                        radio_type = &scan_info_tlv->radio_type;
2731                } else {
2732                        radio_type = NULL;
2733                }
2734                ret = mwifiex_parse_single_response_buf(priv, &bss_info,
2735                                                        &bytes_left, fw_tsf,
2736                                                        radio_type, true, rssi);
2737                if (ret)
2738                        goto check_next_scan;
2739        }
2740
2741check_next_scan:
2742        if (!event_scan->more_event)
2743                mwifiex_check_next_scan_command(priv);
2744
2745        return ret;
2746}
2747
2748/*
2749 * This function prepares command for background scan query.
2750 *
2751 * Preparation includes -
2752 *      - Setting command ID and proper size
2753 *      - Setting background scan flush parameter
2754 *      - Ensuring correct endian-ness
2755 */
2756int mwifiex_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd)
2757{
2758        struct host_cmd_ds_802_11_bg_scan_query *bg_query =
2759                &cmd->params.bg_scan_query;
2760
2761        cmd->command = cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_QUERY);
2762        cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_bg_scan_query)
2763                                + S_DS_GEN);
2764
2765        bg_query->flush = 1;
2766
2767        return 0;
2768}
2769
2770/*
2771 * This function inserts scan command node to the scan pending queue.
2772 */
2773void
2774mwifiex_queue_scan_cmd(struct mwifiex_private *priv,
2775                       struct cmd_ctrl_node *cmd_node)
2776{
2777        struct mwifiex_adapter *adapter = priv->adapter;
2778
2779        cmd_node->wait_q_enabled = true;
2780        cmd_node->condition = &adapter->scan_wait_q_woken;
2781        spin_lock_bh(&adapter->scan_pending_q_lock);
2782        list_add_tail(&cmd_node->list, &adapter->scan_pending_q);
2783        spin_unlock_bh(&adapter->scan_pending_q_lock);
2784}
2785
2786/*
2787 * This function sends a scan command for all available channels to the
2788 * firmware, filtered on a specific SSID.
2789 */
2790static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv,
2791                                      struct cfg80211_ssid *req_ssid)
2792{
2793        struct mwifiex_adapter *adapter = priv->adapter;
2794        int ret;
2795        struct mwifiex_user_scan_cfg *scan_cfg;
2796
2797        if (adapter->scan_processing) {
2798                mwifiex_dbg(adapter, WARN,
2799                            "cmd: Scan already in process...\n");
2800                return -EBUSY;
2801        }
2802
2803        if (priv->scan_block) {
2804                mwifiex_dbg(adapter, WARN,
2805                            "cmd: Scan is blocked during association...\n");
2806                return -EBUSY;
2807        }
2808
2809        scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL);
2810        if (!scan_cfg)
2811                return -ENOMEM;
2812
2813        scan_cfg->ssid_list = req_ssid;
2814        scan_cfg->num_ssids = 1;
2815
2816        ret = mwifiex_scan_networks(priv, scan_cfg);
2817
2818        kfree(scan_cfg);
2819        return ret;
2820}
2821
2822/*
2823 * Sends IOCTL request to start a scan.
2824 *
2825 * This function allocates the IOCTL request buffer, fills it
2826 * with requisite parameters and calls the IOCTL handler.
2827 *
2828 * Scan command can be issued for both normal scan and specific SSID
2829 * scan, depending upon whether an SSID is provided or not.
2830 */
2831int mwifiex_request_scan(struct mwifiex_private *priv,
2832                         struct cfg80211_ssid *req_ssid)
2833{
2834        int ret;
2835
2836        if (mutex_lock_interruptible(&priv->async_mutex)) {
2837                mwifiex_dbg(priv->adapter, ERROR,
2838                            "%s: acquire semaphore fail\n",
2839                            __func__);
2840                return -1;
2841        }
2842
2843        priv->adapter->scan_wait_q_woken = false;
2844
2845        if (req_ssid && req_ssid->ssid_len != 0)
2846                /* Specific SSID scan */
2847                ret = mwifiex_scan_specific_ssid(priv, req_ssid);
2848        else
2849                /* Normal scan */
2850                ret = mwifiex_scan_networks(priv, NULL);
2851
2852        mutex_unlock(&priv->async_mutex);
2853
2854        return ret;
2855}
2856
2857/*
2858 * This function appends the vendor specific IE TLV to a buffer.
2859 */
2860int
2861mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv,
2862                            u16 vsie_mask, u8 **buffer)
2863{
2864        int id, ret_len = 0;
2865        struct mwifiex_ie_types_vendor_param_set *vs_param_set;
2866
2867        if (!buffer)
2868                return 0;
2869        if (!(*buffer))
2870                return 0;
2871
2872        /*
2873         * Traverse through the saved vendor specific IE array and append
2874         * the selected(scan/assoc/adhoc) IE as TLV to the command
2875         */
2876        for (id = 0; id < MWIFIEX_MAX_VSIE_NUM; id++) {
2877                if (priv->vs_ie[id].mask & vsie_mask) {
2878                        vs_param_set =
2879                                (struct mwifiex_ie_types_vendor_param_set *)
2880                                *buffer;
2881                        vs_param_set->header.type =
2882                                cpu_to_le16(TLV_TYPE_PASSTHROUGH);
2883                        vs_param_set->header.len =
2884                                cpu_to_le16((((u16) priv->vs_ie[id].ie[1])
2885                                & 0x00FF) + 2);
2886                        if (le16_to_cpu(vs_param_set->header.len) >
2887                                MWIFIEX_MAX_VSIE_LEN) {
2888                                mwifiex_dbg(priv->adapter, ERROR,
2889                                            "Invalid param length!\n");
2890                                break;
2891                        }
2892
2893                        memcpy(vs_param_set->ie, priv->vs_ie[id].ie,
2894                               le16_to_cpu(vs_param_set->header.len));
2895                        *buffer += le16_to_cpu(vs_param_set->header.len) +
2896                                   sizeof(struct mwifiex_ie_types_header);
2897                        ret_len += le16_to_cpu(vs_param_set->header.len) +
2898                                   sizeof(struct mwifiex_ie_types_header);
2899                }
2900        }
2901        return ret_len;
2902}
2903
2904/*
2905 * This function saves a beacon buffer of the current BSS descriptor.
2906 *
2907 * The current beacon buffer is saved so that it can be restored in the
2908 * following cases that makes the beacon buffer not to contain the current
2909 * ssid's beacon buffer.
2910 *      - The current ssid was not found somehow in the last scan.
2911 *      - The current ssid was the last entry of the scan table and overloaded.
2912 */
2913void
2914mwifiex_save_curr_bcn(struct mwifiex_private *priv)
2915{
2916        struct mwifiex_bssdescriptor *curr_bss =
2917                &priv->curr_bss_params.bss_descriptor;
2918
2919        if (!curr_bss->beacon_buf_size)
2920                return;
2921
2922        /* allocate beacon buffer at 1st time; or if it's size has changed */
2923        if (!priv->curr_bcn_buf ||
2924            priv->curr_bcn_size != curr_bss->beacon_buf_size) {
2925                priv->curr_bcn_size = curr_bss->beacon_buf_size;
2926
2927                kfree(priv->curr_bcn_buf);
2928                priv->curr_bcn_buf = kmalloc(curr_bss->beacon_buf_size,
2929                                             GFP_ATOMIC);
2930                if (!priv->curr_bcn_buf)
2931                        return;
2932        }
2933
2934        memcpy(priv->curr_bcn_buf, curr_bss->beacon_buf,
2935               curr_bss->beacon_buf_size);
2936        mwifiex_dbg(priv->adapter, INFO,
2937                    "info: current beacon saved %d\n",
2938                    priv->curr_bcn_size);
2939
2940        curr_bss->beacon_buf = priv->curr_bcn_buf;
2941
2942        /* adjust the pointers in the current BSS descriptor */
2943        if (curr_bss->bcn_wpa_ie)
2944                curr_bss->bcn_wpa_ie =
2945                        (struct ieee_types_vendor_specific *)
2946                        (curr_bss->beacon_buf +
2947                         curr_bss->wpa_offset);
2948
2949        if (curr_bss->bcn_rsn_ie)
2950                curr_bss->bcn_rsn_ie = (struct ieee_types_generic *)
2951                        (curr_bss->beacon_buf +
2952                         curr_bss->rsn_offset);
2953
2954        if (curr_bss->bcn_ht_cap)
2955                curr_bss->bcn_ht_cap = (struct ieee80211_ht_cap *)
2956                        (curr_bss->beacon_buf +
2957                         curr_bss->ht_cap_offset);
2958
2959        if (curr_bss->bcn_ht_oper)
2960                curr_bss->bcn_ht_oper = (struct ieee80211_ht_operation *)
2961                        (curr_bss->beacon_buf +
2962                         curr_bss->ht_info_offset);
2963
2964        if (curr_bss->bcn_vht_cap)
2965                curr_bss->bcn_vht_cap = (void *)(curr_bss->beacon_buf +
2966                                                 curr_bss->vht_cap_offset);
2967
2968        if (curr_bss->bcn_vht_oper)
2969                curr_bss->bcn_vht_oper = (void *)(curr_bss->beacon_buf +
2970                                                  curr_bss->vht_info_offset);
2971
2972        if (curr_bss->bcn_bss_co_2040)
2973                curr_bss->bcn_bss_co_2040 =
2974                        (curr_bss->beacon_buf + curr_bss->bss_co_2040_offset);
2975
2976        if (curr_bss->bcn_ext_cap)
2977                curr_bss->bcn_ext_cap = curr_bss->beacon_buf +
2978                        curr_bss->ext_cap_offset;
2979
2980        if (curr_bss->oper_mode)
2981                curr_bss->oper_mode = (void *)(curr_bss->beacon_buf +
2982                                               curr_bss->oper_mode_offset);
2983}
2984
2985/*
2986 * This function frees the current BSS descriptor beacon buffer.
2987 */
2988void
2989mwifiex_free_curr_bcn(struct mwifiex_private *priv)
2990{
2991        kfree(priv->curr_bcn_buf);
2992        priv->curr_bcn_buf = NULL;
2993}
2994