linux/drivers/net/wireless/marvell/mwifiex/scan.c
<<
>>
Prefs
   1/*
   2 * Marvell Wireless LAN device driver: scan ioctl and command handling
   3 *
   4 * Copyright (C) 2011-2014, Marvell International Ltd.
   5 *
   6 * This software file (the "File") is distributed by Marvell International
   7 * Ltd. 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        int ret = 0;
1215        u8 element_id;
1216        struct ieee_types_fh_param_set *fh_param_set;
1217        struct ieee_types_ds_param_set *ds_param_set;
1218        struct ieee_types_cf_param_set *cf_param_set;
1219        struct ieee_types_ibss_param_set *ibss_param_set;
1220        u8 *current_ptr;
1221        u8 *rate;
1222        u8 element_len;
1223        u16 total_ie_len;
1224        u8 bytes_to_copy;
1225        u8 rate_size;
1226        u8 found_data_rate_ie;
1227        u32 bytes_left;
1228        struct ieee_types_vendor_specific *vendor_ie;
1229        const u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 };
1230        const u8 wmm_oui[4] = { 0x00, 0x50, 0xf2, 0x02 };
1231
1232        found_data_rate_ie = false;
1233        rate_size = 0;
1234        current_ptr = bss_entry->beacon_buf;
1235        bytes_left = bss_entry->beacon_buf_size;
1236
1237        /* Process variable IE */
1238        while (bytes_left >= 2) {
1239                element_id = *current_ptr;
1240                element_len = *(current_ptr + 1);
1241                total_ie_len = element_len + sizeof(struct ieee_types_header);
1242
1243                if (bytes_left < total_ie_len) {
1244                        mwifiex_dbg(adapter, ERROR,
1245                                    "err: InterpretIE: in processing\t"
1246                                    "IE, bytes left < IE length\n");
1247                        return -EINVAL;
1248                }
1249                switch (element_id) {
1250                case WLAN_EID_SSID:
1251                        if (element_len > IEEE80211_MAX_SSID_LEN)
1252                                return -EINVAL;
1253                        bss_entry->ssid.ssid_len = element_len;
1254                        memcpy(bss_entry->ssid.ssid, (current_ptr + 2),
1255                               element_len);
1256                        mwifiex_dbg(adapter, INFO,
1257                                    "info: InterpretIE: ssid: %-32s\n",
1258                                    bss_entry->ssid.ssid);
1259                        break;
1260
1261                case WLAN_EID_SUPP_RATES:
1262                        if (element_len > MWIFIEX_SUPPORTED_RATES)
1263                                return -EINVAL;
1264                        memcpy(bss_entry->data_rates, current_ptr + 2,
1265                               element_len);
1266                        memcpy(bss_entry->supported_rates, current_ptr + 2,
1267                               element_len);
1268                        rate_size = element_len;
1269                        found_data_rate_ie = true;
1270                        break;
1271
1272                case WLAN_EID_FH_PARAMS:
1273                        if (element_len + 2 < sizeof(*fh_param_set))
1274                                return -EINVAL;
1275                        fh_param_set =
1276                                (struct ieee_types_fh_param_set *) current_ptr;
1277                        memcpy(&bss_entry->phy_param_set.fh_param_set,
1278                               fh_param_set,
1279                               sizeof(struct ieee_types_fh_param_set));
1280                        break;
1281
1282                case WLAN_EID_DS_PARAMS:
1283                        if (element_len + 2 < sizeof(*ds_param_set))
1284                                return -EINVAL;
1285                        ds_param_set =
1286                                (struct ieee_types_ds_param_set *) current_ptr;
1287
1288                        bss_entry->channel = ds_param_set->current_chan;
1289
1290                        memcpy(&bss_entry->phy_param_set.ds_param_set,
1291                               ds_param_set,
1292                               sizeof(struct ieee_types_ds_param_set));
1293                        break;
1294
1295                case WLAN_EID_CF_PARAMS:
1296                        if (element_len + 2 < sizeof(*cf_param_set))
1297                                return -EINVAL;
1298                        cf_param_set =
1299                                (struct ieee_types_cf_param_set *) current_ptr;
1300                        memcpy(&bss_entry->ss_param_set.cf_param_set,
1301                               cf_param_set,
1302                               sizeof(struct ieee_types_cf_param_set));
1303                        break;
1304
1305                case WLAN_EID_IBSS_PARAMS:
1306                        if (element_len + 2 < sizeof(*ibss_param_set))
1307                                return -EINVAL;
1308                        ibss_param_set =
1309                                (struct ieee_types_ibss_param_set *)
1310                                current_ptr;
1311                        memcpy(&bss_entry->ss_param_set.ibss_param_set,
1312                               ibss_param_set,
1313                               sizeof(struct ieee_types_ibss_param_set));
1314                        break;
1315
1316                case WLAN_EID_ERP_INFO:
1317                        if (!element_len)
1318                                return -EINVAL;
1319                        bss_entry->erp_flags = *(current_ptr + 2);
1320                        break;
1321
1322                case WLAN_EID_PWR_CONSTRAINT:
1323                        if (!element_len)
1324                                return -EINVAL;
1325                        bss_entry->local_constraint = *(current_ptr + 2);
1326                        bss_entry->sensed_11h = true;
1327                        break;
1328
1329                case WLAN_EID_CHANNEL_SWITCH:
1330                        bss_entry->chan_sw_ie_present = true;
1331                        /* fall through */
1332                case WLAN_EID_PWR_CAPABILITY:
1333                case WLAN_EID_TPC_REPORT:
1334                case WLAN_EID_QUIET:
1335                        bss_entry->sensed_11h = true;
1336                    break;
1337
1338                case WLAN_EID_EXT_SUPP_RATES:
1339                        /*
1340                         * Only process extended supported rate
1341                         * if data rate is already found.
1342                         * Data rate IE should come before
1343                         * extended supported rate IE
1344                         */
1345                        if (found_data_rate_ie) {
1346                                if ((element_len + rate_size) >
1347                                    MWIFIEX_SUPPORTED_RATES)
1348                                        bytes_to_copy =
1349                                                (MWIFIEX_SUPPORTED_RATES -
1350                                                 rate_size);
1351                                else
1352                                        bytes_to_copy = element_len;
1353
1354                                rate = (u8 *) bss_entry->data_rates;
1355                                rate += rate_size;
1356                                memcpy(rate, current_ptr + 2, bytes_to_copy);
1357
1358                                rate = (u8 *) bss_entry->supported_rates;
1359                                rate += rate_size;
1360                                memcpy(rate, current_ptr + 2, bytes_to_copy);
1361                        }
1362                        break;
1363
1364                case WLAN_EID_VENDOR_SPECIFIC:
1365                        vendor_ie = (struct ieee_types_vendor_specific *)
1366                                        current_ptr;
1367
1368                        /* 802.11 requires at least 3-byte OUI. */
1369                        if (element_len < sizeof(vendor_ie->vend_hdr.oui.oui))
1370                                return -EINVAL;
1371
1372                        /* Not long enough for a match? Skip it. */
1373                        if (element_len < sizeof(wpa_oui))
1374                                break;
1375
1376                        if (!memcmp(&vendor_ie->vend_hdr.oui, wpa_oui,
1377                                    sizeof(wpa_oui))) {
1378                                bss_entry->bcn_wpa_ie =
1379                                        (struct ieee_types_vendor_specific *)
1380                                        current_ptr;
1381                                bss_entry->wpa_offset = (u16)
1382                                        (current_ptr - bss_entry->beacon_buf);
1383                        } else if (!memcmp(&vendor_ie->vend_hdr.oui, wmm_oui,
1384                                    sizeof(wmm_oui))) {
1385                                if (total_ie_len ==
1386                                    sizeof(struct ieee_types_wmm_parameter) ||
1387                                    total_ie_len ==
1388                                    sizeof(struct ieee_types_wmm_info))
1389                                        /*
1390                                         * Only accept and copy the WMM IE if
1391                                         * it matches the size expected for the
1392                                         * WMM Info IE or the WMM Parameter IE.
1393                                         */
1394                                        memcpy((u8 *) &bss_entry->wmm_ie,
1395                                               current_ptr, total_ie_len);
1396                        }
1397                        break;
1398                case WLAN_EID_RSN:
1399                        bss_entry->bcn_rsn_ie =
1400                                (struct ieee_types_generic *) current_ptr;
1401                        bss_entry->rsn_offset = (u16) (current_ptr -
1402                                                        bss_entry->beacon_buf);
1403                        break;
1404                case WLAN_EID_BSS_AC_ACCESS_DELAY:
1405                        bss_entry->bcn_wapi_ie =
1406                                (struct ieee_types_generic *) current_ptr;
1407                        bss_entry->wapi_offset = (u16) (current_ptr -
1408                                                        bss_entry->beacon_buf);
1409                        break;
1410                case WLAN_EID_HT_CAPABILITY:
1411                        bss_entry->bcn_ht_cap = (struct ieee80211_ht_cap *)
1412                                        (current_ptr +
1413                                        sizeof(struct ieee_types_header));
1414                        bss_entry->ht_cap_offset = (u16) (current_ptr +
1415                                        sizeof(struct ieee_types_header) -
1416                                        bss_entry->beacon_buf);
1417                        break;
1418                case WLAN_EID_HT_OPERATION:
1419                        bss_entry->bcn_ht_oper =
1420                                (struct ieee80211_ht_operation *)(current_ptr +
1421                                        sizeof(struct ieee_types_header));
1422                        bss_entry->ht_info_offset = (u16) (current_ptr +
1423                                        sizeof(struct ieee_types_header) -
1424                                        bss_entry->beacon_buf);
1425                        break;
1426                case WLAN_EID_VHT_CAPABILITY:
1427                        bss_entry->disable_11ac = false;
1428                        bss_entry->bcn_vht_cap =
1429                                (void *)(current_ptr +
1430                                         sizeof(struct ieee_types_header));
1431                        bss_entry->vht_cap_offset =
1432                                        (u16)((u8 *)bss_entry->bcn_vht_cap -
1433                                              bss_entry->beacon_buf);
1434                        break;
1435                case WLAN_EID_VHT_OPERATION:
1436                        bss_entry->bcn_vht_oper =
1437                                (void *)(current_ptr +
1438                                         sizeof(struct ieee_types_header));
1439                        bss_entry->vht_info_offset =
1440                                        (u16)((u8 *)bss_entry->bcn_vht_oper -
1441                                              bss_entry->beacon_buf);
1442                        break;
1443                case WLAN_EID_BSS_COEX_2040:
1444                        bss_entry->bcn_bss_co_2040 = current_ptr;
1445                        bss_entry->bss_co_2040_offset =
1446                                (u16) (current_ptr - bss_entry->beacon_buf);
1447                        break;
1448                case WLAN_EID_EXT_CAPABILITY:
1449                        bss_entry->bcn_ext_cap = current_ptr;
1450                        bss_entry->ext_cap_offset =
1451                                (u16) (current_ptr - bss_entry->beacon_buf);
1452                        break;
1453                case WLAN_EID_OPMODE_NOTIF:
1454                        bss_entry->oper_mode = (void *)current_ptr;
1455                        bss_entry->oper_mode_offset =
1456                                        (u16)((u8 *)bss_entry->oper_mode -
1457                                              bss_entry->beacon_buf);
1458                        break;
1459                default:
1460                        break;
1461                }
1462
1463                current_ptr += element_len + 2;
1464
1465                /* Need to account for IE ID and IE Len */
1466                bytes_left -= (element_len + 2);
1467
1468        }       /* while (bytes_left > 2) */
1469        return ret;
1470}
1471
1472/*
1473 * This function converts radio type scan parameter to a band configuration
1474 * to be used in join command.
1475 */
1476static u8
1477mwifiex_radio_type_to_band(u8 radio_type)
1478{
1479        switch (radio_type) {
1480        case HostCmd_SCAN_RADIO_TYPE_A:
1481                return BAND_A;
1482        case HostCmd_SCAN_RADIO_TYPE_BG:
1483        default:
1484                return BAND_G;
1485        }
1486}
1487
1488/*
1489 * This is an internal function used to start a scan based on an input
1490 * configuration.
1491 *
1492 * This uses the input user scan configuration information when provided in
1493 * order to send the appropriate scan commands to firmware to populate or
1494 * update the internal driver scan table.
1495 */
1496int mwifiex_scan_networks(struct mwifiex_private *priv,
1497                          const struct mwifiex_user_scan_cfg *user_scan_in)
1498{
1499        int ret;
1500        struct mwifiex_adapter *adapter = priv->adapter;
1501        struct cmd_ctrl_node *cmd_node;
1502        union mwifiex_scan_cmd_config_tlv *scan_cfg_out;
1503        struct mwifiex_ie_types_chan_list_param_set *chan_list_out;
1504        struct mwifiex_chan_scan_param_set *scan_chan_list;
1505        u8 filtered_scan;
1506        u8 scan_current_chan_only;
1507        u8 max_chan_per_scan;
1508
1509        if (adapter->scan_processing) {
1510                mwifiex_dbg(adapter, WARN,
1511                            "cmd: Scan already in process...\n");
1512                return -EBUSY;
1513        }
1514
1515        if (priv->scan_block) {
1516                mwifiex_dbg(adapter, WARN,
1517                            "cmd: Scan is blocked during association...\n");
1518                return -EBUSY;
1519        }
1520
1521        if (test_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags) ||
1522            test_bit(MWIFIEX_IS_CMD_TIMEDOUT, &adapter->work_flags)) {
1523                mwifiex_dbg(adapter, ERROR,
1524                            "Ignore scan. Card removed or firmware in bad state\n");
1525                return -EFAULT;
1526        }
1527
1528        spin_lock_bh(&adapter->mwifiex_cmd_lock);
1529        adapter->scan_processing = true;
1530        spin_unlock_bh(&adapter->mwifiex_cmd_lock);
1531
1532        scan_cfg_out = kzalloc(sizeof(union mwifiex_scan_cmd_config_tlv),
1533                               GFP_KERNEL);
1534        if (!scan_cfg_out) {
1535                ret = -ENOMEM;
1536                goto done;
1537        }
1538
1539        scan_chan_list = kcalloc(MWIFIEX_USER_SCAN_CHAN_MAX,
1540                                 sizeof(struct mwifiex_chan_scan_param_set),
1541                                 GFP_KERNEL);
1542        if (!scan_chan_list) {
1543                kfree(scan_cfg_out);
1544                ret = -ENOMEM;
1545                goto done;
1546        }
1547
1548        mwifiex_config_scan(priv, user_scan_in, &scan_cfg_out->config,
1549                            &chan_list_out, scan_chan_list, &max_chan_per_scan,
1550                            &filtered_scan, &scan_current_chan_only);
1551
1552        ret = mwifiex_scan_channel_list(priv, max_chan_per_scan, filtered_scan,
1553                                        &scan_cfg_out->config, chan_list_out,
1554                                        scan_chan_list);
1555
1556        /* Get scan command from scan_pending_q and put to cmd_pending_q */
1557        if (!ret) {
1558                spin_lock_bh(&adapter->scan_pending_q_lock);
1559                if (!list_empty(&adapter->scan_pending_q)) {
1560                        cmd_node = list_first_entry(&adapter->scan_pending_q,
1561                                                    struct cmd_ctrl_node, list);
1562                        list_del(&cmd_node->list);
1563                        spin_unlock_bh(&adapter->scan_pending_q_lock);
1564                        mwifiex_insert_cmd_to_pending_q(adapter, cmd_node);
1565                        queue_work(adapter->workqueue, &adapter->main_work);
1566
1567                        /* Perform internal scan synchronously */
1568                        if (!priv->scan_request) {
1569                                mwifiex_dbg(adapter, INFO,
1570                                            "wait internal scan\n");
1571                                mwifiex_wait_queue_complete(adapter, cmd_node);
1572                        }
1573                } else {
1574                        spin_unlock_bh(&adapter->scan_pending_q_lock);
1575                }
1576        }
1577
1578        kfree(scan_cfg_out);
1579        kfree(scan_chan_list);
1580done:
1581        if (ret) {
1582                spin_lock_bh(&adapter->mwifiex_cmd_lock);
1583                adapter->scan_processing = false;
1584                spin_unlock_bh(&adapter->mwifiex_cmd_lock);
1585        }
1586        return ret;
1587}
1588
1589/*
1590 * This function prepares a scan command to be sent to the firmware.
1591 *
1592 * This uses the scan command configuration sent to the command processing
1593 * module in command preparation stage to configure a scan command structure
1594 * to send to firmware.
1595 *
1596 * The fixed fields specifying the BSS type and BSSID filters as well as a
1597 * variable number/length of TLVs are sent in the command to firmware.
1598 *
1599 * Preparation also includes -
1600 *      - Setting command ID, and proper size
1601 *      - Ensuring correct endian-ness
1602 */
1603int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd,
1604                            struct mwifiex_scan_cmd_config *scan_cfg)
1605{
1606        struct host_cmd_ds_802_11_scan *scan_cmd = &cmd->params.scan;
1607
1608        /* Set fixed field variables in scan command */
1609        scan_cmd->bss_mode = scan_cfg->bss_mode;
1610        memcpy(scan_cmd->bssid, scan_cfg->specific_bssid,
1611               sizeof(scan_cmd->bssid));
1612        memcpy(scan_cmd->tlv_buffer, scan_cfg->tlv_buf, scan_cfg->tlv_buf_len);
1613
1614        cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SCAN);
1615
1616        /* Size is equal to the sizeof(fixed portions) + the TLV len + header */
1617        cmd->size = cpu_to_le16((u16) (sizeof(scan_cmd->bss_mode)
1618                                          + sizeof(scan_cmd->bssid)
1619                                          + scan_cfg->tlv_buf_len + S_DS_GEN));
1620
1621        return 0;
1622}
1623
1624/*
1625 * This function checks compatibility of requested network with current
1626 * driver settings.
1627 */
1628int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
1629                                        struct mwifiex_bssdescriptor *bss_desc)
1630{
1631        int ret = -1;
1632
1633        if (!bss_desc)
1634                return -1;
1635
1636        if ((mwifiex_get_cfp(priv, (u8) bss_desc->bss_band,
1637                             (u16) bss_desc->channel, 0))) {
1638                switch (priv->bss_mode) {
1639                case NL80211_IFTYPE_STATION:
1640                case NL80211_IFTYPE_ADHOC:
1641                        ret = mwifiex_is_network_compatible(priv, bss_desc,
1642                                                            priv->bss_mode);
1643                        if (ret)
1644                                mwifiex_dbg(priv->adapter, ERROR,
1645                                            "Incompatible network settings\n");
1646                        break;
1647                default:
1648                        ret = 0;
1649                }
1650        }
1651
1652        return ret;
1653}
1654
1655/* This function checks if SSID string contains all zeroes or length is zero */
1656static bool mwifiex_is_hidden_ssid(struct cfg80211_ssid *ssid)
1657{
1658        int idx;
1659
1660        for (idx = 0; idx < ssid->ssid_len; idx++) {
1661                if (ssid->ssid[idx])
1662                        return false;
1663        }
1664
1665        return true;
1666}
1667
1668/* This function checks if any hidden SSID found in passive scan channels
1669 * and save those channels for specific SSID active scan
1670 */
1671static int mwifiex_save_hidden_ssid_channels(struct mwifiex_private *priv,
1672                                             struct cfg80211_bss *bss)
1673{
1674        struct mwifiex_bssdescriptor *bss_desc;
1675        int ret;
1676        int chid;
1677
1678        /* Allocate and fill new bss descriptor */
1679        bss_desc = kzalloc(sizeof(*bss_desc), GFP_KERNEL);
1680        if (!bss_desc)
1681                return -ENOMEM;
1682
1683        ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc);
1684        if (ret)
1685                goto done;
1686
1687        if (mwifiex_is_hidden_ssid(&bss_desc->ssid)) {
1688                mwifiex_dbg(priv->adapter, INFO, "found hidden SSID\n");
1689                for (chid = 0 ; chid < MWIFIEX_USER_SCAN_CHAN_MAX; chid++) {
1690                        if (priv->hidden_chan[chid].chan_number ==
1691                            bss->channel->hw_value)
1692                                break;
1693
1694                        if (!priv->hidden_chan[chid].chan_number) {
1695                                priv->hidden_chan[chid].chan_number =
1696                                        bss->channel->hw_value;
1697                                priv->hidden_chan[chid].radio_type =
1698                                        bss->channel->band;
1699                                priv->hidden_chan[chid].scan_type =
1700                                        MWIFIEX_SCAN_TYPE_ACTIVE;
1701                                break;
1702                        }
1703                }
1704        }
1705
1706done:
1707        /* beacon_ie buffer was allocated in function
1708         * mwifiex_fill_new_bss_desc(). Free it now.
1709         */
1710        kfree(bss_desc->beacon_buf);
1711        kfree(bss_desc);
1712        return 0;
1713}
1714
1715static int mwifiex_update_curr_bss_params(struct mwifiex_private *priv,
1716                                          struct cfg80211_bss *bss)
1717{
1718        struct mwifiex_bssdescriptor *bss_desc;
1719        int ret;
1720
1721        /* Allocate and fill new bss descriptor */
1722        bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor), GFP_KERNEL);
1723        if (!bss_desc)
1724                return -ENOMEM;
1725
1726        ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc);
1727        if (ret)
1728                goto done;
1729
1730        ret = mwifiex_check_network_compatibility(priv, bss_desc);
1731        if (ret)
1732                goto done;
1733
1734        spin_lock_bh(&priv->curr_bcn_buf_lock);
1735        /* Make a copy of current BSSID descriptor */
1736        memcpy(&priv->curr_bss_params.bss_descriptor, bss_desc,
1737               sizeof(priv->curr_bss_params.bss_descriptor));
1738
1739        /* The contents of beacon_ie will be copied to its own buffer
1740         * in mwifiex_save_curr_bcn()
1741         */
1742        mwifiex_save_curr_bcn(priv);
1743        spin_unlock_bh(&priv->curr_bcn_buf_lock);
1744
1745done:
1746        /* beacon_ie buffer was allocated in function
1747         * mwifiex_fill_new_bss_desc(). Free it now.
1748         */
1749        kfree(bss_desc->beacon_buf);
1750        kfree(bss_desc);
1751        return 0;
1752}
1753
1754static int
1755mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info,
1756                                  u32 *bytes_left, u64 fw_tsf, u8 *radio_type,
1757                                  bool ext_scan, s32 rssi_val)
1758{
1759        struct mwifiex_adapter *adapter = priv->adapter;
1760        struct mwifiex_chan_freq_power *cfp;
1761        struct cfg80211_bss *bss;
1762        u8 bssid[ETH_ALEN];
1763        s32 rssi;
1764        const u8 *ie_buf;
1765        size_t ie_len;
1766        u16 channel = 0;
1767        u16 beacon_size = 0;
1768        u32 curr_bcn_bytes;
1769        u32 freq;
1770        u16 beacon_period;
1771        u16 cap_info_bitmap;
1772        u8 *current_ptr;
1773        u64 timestamp;
1774        struct mwifiex_fixed_bcn_param *bcn_param;
1775        struct mwifiex_bss_priv *bss_priv;
1776
1777        if (*bytes_left >= sizeof(beacon_size)) {
1778                /* Extract & convert beacon size from command buffer */
1779                beacon_size = get_unaligned_le16((*bss_info));
1780                *bytes_left -= sizeof(beacon_size);
1781                *bss_info += sizeof(beacon_size);
1782        }
1783
1784        if (!beacon_size || beacon_size > *bytes_left) {
1785                *bss_info += *bytes_left;
1786                *bytes_left = 0;
1787                return -EFAULT;
1788        }
1789
1790        /* Initialize the current working beacon pointer for this BSS
1791         * iteration
1792         */
1793        current_ptr = *bss_info;
1794
1795        /* Advance the return beacon pointer past the current beacon */
1796        *bss_info += beacon_size;
1797        *bytes_left -= beacon_size;
1798
1799        curr_bcn_bytes = beacon_size;
1800
1801        /* First 5 fields are bssid, RSSI(for legacy scan only),
1802         * time stamp, beacon interval, and capability information
1803         */
1804        if (curr_bcn_bytes < ETH_ALEN + sizeof(u8) +
1805            sizeof(struct mwifiex_fixed_bcn_param)) {
1806                mwifiex_dbg(adapter, ERROR,
1807                            "InterpretIE: not enough bytes left\n");
1808                return -EFAULT;
1809        }
1810
1811        memcpy(bssid, current_ptr, ETH_ALEN);
1812        current_ptr += ETH_ALEN;
1813        curr_bcn_bytes -= ETH_ALEN;
1814
1815        if (!ext_scan) {
1816                rssi = (s32) *current_ptr;
1817                rssi = (-rssi) * 100;           /* Convert dBm to mBm */
1818                current_ptr += sizeof(u8);
1819                curr_bcn_bytes -= sizeof(u8);
1820                mwifiex_dbg(adapter, INFO,
1821                            "info: InterpretIE: RSSI=%d\n", rssi);
1822        } else {
1823                rssi = rssi_val;
1824        }
1825
1826        bcn_param = (struct mwifiex_fixed_bcn_param *)current_ptr;
1827        current_ptr += sizeof(*bcn_param);
1828        curr_bcn_bytes -= sizeof(*bcn_param);
1829
1830        timestamp = le64_to_cpu(bcn_param->timestamp);
1831        beacon_period = le16_to_cpu(bcn_param->beacon_period);
1832
1833        cap_info_bitmap = le16_to_cpu(bcn_param->cap_info_bitmap);
1834        mwifiex_dbg(adapter, INFO,
1835                    "info: InterpretIE: capabilities=0x%X\n",
1836                    cap_info_bitmap);
1837
1838        /* Rest of the current buffer are IE's */
1839        ie_buf = current_ptr;
1840        ie_len = curr_bcn_bytes;
1841        mwifiex_dbg(adapter, INFO,
1842                    "info: InterpretIE: IELength for this AP = %d\n",
1843                    curr_bcn_bytes);
1844
1845        while (curr_bcn_bytes >= sizeof(struct ieee_types_header)) {
1846                u8 element_id, element_len;
1847
1848                element_id = *current_ptr;
1849                element_len = *(current_ptr + 1);
1850                if (curr_bcn_bytes < element_len +
1851                                sizeof(struct ieee_types_header)) {
1852                        mwifiex_dbg(adapter, ERROR,
1853                                    "%s: bytes left < IE length\n", __func__);
1854                        return -EFAULT;
1855                }
1856                if (element_id == WLAN_EID_DS_PARAMS) {
1857                        channel = *(current_ptr +
1858                                    sizeof(struct ieee_types_header));
1859                        break;
1860                }
1861
1862                current_ptr += element_len + sizeof(struct ieee_types_header);
1863                curr_bcn_bytes -= element_len +
1864                                        sizeof(struct ieee_types_header);
1865        }
1866
1867        if (channel) {
1868                struct ieee80211_channel *chan;
1869                u8 band;
1870
1871                /* Skip entry if on csa closed channel */
1872                if (channel == priv->csa_chan) {
1873                        mwifiex_dbg(adapter, WARN,
1874                                    "Dropping entry on csa closed channel\n");
1875                        return 0;
1876                }
1877
1878                band = BAND_G;
1879                if (radio_type)
1880                        band = mwifiex_radio_type_to_band(*radio_type &
1881                                                          (BIT(0) | BIT(1)));
1882
1883                cfp = mwifiex_get_cfp(priv, band, channel, 0);
1884
1885                freq = cfp ? cfp->freq : 0;
1886
1887                chan = ieee80211_get_channel(priv->wdev.wiphy, freq);
1888
1889                if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) {
1890                        bss = cfg80211_inform_bss(priv->wdev.wiphy,
1891                                            chan, CFG80211_BSS_FTYPE_UNKNOWN,
1892                                            bssid, timestamp,
1893                                            cap_info_bitmap, beacon_period,
1894                                            ie_buf, ie_len, rssi, GFP_KERNEL);
1895                        if (bss) {
1896                                bss_priv = (struct mwifiex_bss_priv *)bss->priv;
1897                                bss_priv->band = band;
1898                                bss_priv->fw_tsf = fw_tsf;
1899                                if (priv->media_connected &&
1900                                    !memcmp(bssid, priv->curr_bss_params.
1901                                            bss_descriptor.mac_address,
1902                                            ETH_ALEN))
1903                                        mwifiex_update_curr_bss_params(priv,
1904                                                                       bss);
1905
1906                                if ((chan->flags & IEEE80211_CHAN_RADAR) ||
1907                                    (chan->flags & IEEE80211_CHAN_NO_IR)) {
1908                                        mwifiex_dbg(adapter, INFO,
1909                                                    "radar or passive channel %d\n",
1910                                                    channel);
1911                                        mwifiex_save_hidden_ssid_channels(priv,
1912                                                                          bss);
1913                                }
1914
1915                                cfg80211_put_bss(priv->wdev.wiphy, bss);
1916                        }
1917                }
1918        } else {
1919                mwifiex_dbg(adapter, WARN, "missing BSS channel IE\n");
1920        }
1921
1922        return 0;
1923}
1924
1925static void mwifiex_complete_scan(struct mwifiex_private *priv)
1926{
1927        struct mwifiex_adapter *adapter = priv->adapter;
1928
1929        adapter->survey_idx = 0;
1930        if (adapter->curr_cmd->wait_q_enabled) {
1931                adapter->cmd_wait_q.status = 0;
1932                if (!priv->scan_request) {
1933                        mwifiex_dbg(adapter, INFO,
1934                                    "complete internal scan\n");
1935                        mwifiex_complete_cmd(adapter, adapter->curr_cmd);
1936                }
1937        }
1938}
1939
1940/* This function checks if any hidden SSID found in passive scan channels
1941 * and do specific SSID active scan for those channels
1942 */
1943static int
1944mwifiex_active_scan_req_for_passive_chan(struct mwifiex_private *priv)
1945{
1946        int ret;
1947        struct mwifiex_adapter *adapter = priv->adapter;
1948        u8 id = 0;
1949        struct mwifiex_user_scan_cfg  *user_scan_cfg;
1950
1951        if (adapter->active_scan_triggered || !priv->scan_request ||
1952            priv->scan_aborting) {
1953                adapter->active_scan_triggered = false;
1954                return 0;
1955        }
1956
1957        if (!priv->hidden_chan[0].chan_number) {
1958                mwifiex_dbg(adapter, INFO, "No BSS with hidden SSID found on DFS channels\n");
1959                return 0;
1960        }
1961        user_scan_cfg = kzalloc(sizeof(*user_scan_cfg), GFP_KERNEL);
1962
1963        if (!user_scan_cfg)
1964                return -ENOMEM;
1965
1966        for (id = 0; id < MWIFIEX_USER_SCAN_CHAN_MAX; id++) {
1967                if (!priv->hidden_chan[id].chan_number)
1968                        break;
1969                memcpy(&user_scan_cfg->chan_list[id],
1970                       &priv->hidden_chan[id],
1971                       sizeof(struct mwifiex_user_scan_chan));
1972        }
1973
1974        adapter->active_scan_triggered = true;
1975        if (priv->scan_request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR)
1976                ether_addr_copy(user_scan_cfg->random_mac,
1977                                priv->scan_request->mac_addr);
1978        user_scan_cfg->num_ssids = priv->scan_request->n_ssids;
1979        user_scan_cfg->ssid_list = priv->scan_request->ssids;
1980
1981        ret = mwifiex_scan_networks(priv, user_scan_cfg);
1982        kfree(user_scan_cfg);
1983
1984        memset(&priv->hidden_chan, 0, sizeof(priv->hidden_chan));
1985
1986        if (ret) {
1987                dev_err(priv->adapter->dev, "scan failed: %d\n", ret);
1988                return ret;
1989        }
1990
1991        return 0;
1992}
1993static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)
1994{
1995        struct mwifiex_adapter *adapter = priv->adapter;
1996        struct cmd_ctrl_node *cmd_node;
1997
1998        spin_lock_bh(&adapter->scan_pending_q_lock);
1999        if (list_empty(&adapter->scan_pending_q)) {
2000                spin_unlock_bh(&adapter->scan_pending_q_lock);
2001
2002                spin_lock_bh(&adapter->mwifiex_cmd_lock);
2003                adapter->scan_processing = false;
2004                spin_unlock_bh(&adapter->mwifiex_cmd_lock);
2005
2006                mwifiex_active_scan_req_for_passive_chan(priv);
2007
2008                if (!adapter->ext_scan)
2009                        mwifiex_complete_scan(priv);
2010
2011                if (priv->scan_request) {
2012                        struct cfg80211_scan_info info = {
2013                                .aborted = false,
2014                        };
2015
2016                        mwifiex_dbg(adapter, INFO,
2017                                    "info: notifying scan done\n");
2018                        cfg80211_scan_done(priv->scan_request, &info);
2019                        priv->scan_request = NULL;
2020                        priv->scan_aborting = false;
2021                } else {
2022                        priv->scan_aborting = false;
2023                        mwifiex_dbg(adapter, INFO,
2024                                    "info: scan already aborted\n");
2025                }
2026        } else if ((priv->scan_aborting && !priv->scan_request) ||
2027                   priv->scan_block) {
2028                spin_unlock_bh(&adapter->scan_pending_q_lock);
2029
2030                mwifiex_cancel_pending_scan_cmd(adapter);
2031
2032                spin_lock_bh(&adapter->mwifiex_cmd_lock);
2033                adapter->scan_processing = false;
2034                spin_unlock_bh(&adapter->mwifiex_cmd_lock);
2035
2036                if (!adapter->active_scan_triggered) {
2037                        if (priv->scan_request) {
2038                                struct cfg80211_scan_info info = {
2039                                        .aborted = true,
2040                                };
2041
2042                                mwifiex_dbg(adapter, INFO,
2043                                            "info: aborting scan\n");
2044                                cfg80211_scan_done(priv->scan_request, &info);
2045                                priv->scan_request = NULL;
2046                                priv->scan_aborting = false;
2047                        } else {
2048                                priv->scan_aborting = false;
2049                                mwifiex_dbg(adapter, INFO,
2050                                            "info: scan already aborted\n");
2051                        }
2052                }
2053        } else {
2054                /* Get scan command from scan_pending_q and put to
2055                 * cmd_pending_q
2056                 */
2057                cmd_node = list_first_entry(&adapter->scan_pending_q,
2058                                            struct cmd_ctrl_node, list);
2059                list_del(&cmd_node->list);
2060                spin_unlock_bh(&adapter->scan_pending_q_lock);
2061                mwifiex_insert_cmd_to_pending_q(adapter, cmd_node);
2062        }
2063
2064        return;
2065}
2066
2067void mwifiex_cancel_scan(struct mwifiex_adapter *adapter)
2068{
2069        struct mwifiex_private *priv;
2070        int i;
2071
2072        mwifiex_cancel_pending_scan_cmd(adapter);
2073
2074        if (adapter->scan_processing) {
2075                spin_lock_bh(&adapter->mwifiex_cmd_lock);
2076                adapter->scan_processing = false;
2077                spin_unlock_bh(&adapter->mwifiex_cmd_lock);
2078                for (i = 0; i < adapter->priv_num; i++) {
2079                        priv = adapter->priv[i];
2080                        if (!priv)
2081                                continue;
2082                        if (priv->scan_request) {
2083                                struct cfg80211_scan_info info = {
2084                                        .aborted = true,
2085                                };
2086
2087                                mwifiex_dbg(adapter, INFO,
2088                                            "info: aborting scan\n");
2089                                cfg80211_scan_done(priv->scan_request, &info);
2090                                priv->scan_request = NULL;
2091                                priv->scan_aborting = false;
2092                        }
2093                }
2094        }
2095}
2096
2097/*
2098 * This function handles the command response of scan.
2099 *
2100 * The response buffer for the scan command has the following
2101 * memory layout:
2102 *
2103 *      .-------------------------------------------------------------.
2104 *      |  Header (4 * sizeof(t_u16)):  Standard command response hdr |
2105 *      .-------------------------------------------------------------.
2106 *      |  BufSize (t_u16) : sizeof the BSS Description data          |
2107 *      .-------------------------------------------------------------.
2108 *      |  NumOfSet (t_u8) : Number of BSS Descs returned             |
2109 *      .-------------------------------------------------------------.
2110 *      |  BSSDescription data (variable, size given in BufSize)      |
2111 *      .-------------------------------------------------------------.
2112 *      |  TLV data (variable, size calculated using Header->Size,    |
2113 *      |            BufSize and sizeof the fixed fields above)       |
2114 *      .-------------------------------------------------------------.
2115 */
2116int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
2117                            struct host_cmd_ds_command *resp)
2118{
2119        int ret = 0;
2120        struct mwifiex_adapter *adapter = priv->adapter;
2121        struct host_cmd_ds_802_11_scan_rsp *scan_rsp;
2122        struct mwifiex_ie_types_data *tlv_data;
2123        struct mwifiex_ie_types_tsf_timestamp *tsf_tlv;
2124        u8 *bss_info;
2125        u32 scan_resp_size;
2126        u32 bytes_left;
2127        u32 idx;
2128        u32 tlv_buf_size;
2129        struct mwifiex_ie_types_chan_band_list_param_set *chan_band_tlv;
2130        struct chan_band_param_set *chan_band;
2131        u8 is_bgscan_resp;
2132        __le64 fw_tsf = 0;
2133        u8 *radio_type;
2134        struct cfg80211_wowlan_nd_match *pmatch;
2135        struct cfg80211_sched_scan_request *nd_config = NULL;
2136
2137        is_bgscan_resp = (le16_to_cpu(resp->command)
2138                          == HostCmd_CMD_802_11_BG_SCAN_QUERY);
2139        if (is_bgscan_resp)
2140                scan_rsp = &resp->params.bg_scan_query_resp.scan_resp;
2141        else
2142                scan_rsp = &resp->params.scan_resp;
2143
2144
2145        if (scan_rsp->number_of_sets > MWIFIEX_MAX_AP) {
2146                mwifiex_dbg(adapter, ERROR,
2147                            "SCAN_RESP: too many AP returned (%d)\n",
2148                            scan_rsp->number_of_sets);
2149                ret = -1;
2150                goto check_next_scan;
2151        }
2152
2153        /* Check csa channel expiry before parsing scan response */
2154        mwifiex_11h_get_csa_closed_channel(priv);
2155
2156        bytes_left = le16_to_cpu(scan_rsp->bss_descript_size);
2157        mwifiex_dbg(adapter, INFO,
2158                    "info: SCAN_RESP: bss_descript_size %d\n",
2159                    bytes_left);
2160
2161        scan_resp_size = le16_to_cpu(resp->size);
2162
2163        mwifiex_dbg(adapter, INFO,
2164                    "info: SCAN_RESP: returned %d APs before parsing\n",
2165                    scan_rsp->number_of_sets);
2166
2167        bss_info = scan_rsp->bss_desc_and_tlv_buffer;
2168
2169        /*
2170         * The size of the TLV buffer is equal to the entire command response
2171         *   size (scan_resp_size) minus the fixed fields (sizeof()'s), the
2172         *   BSS Descriptions (bss_descript_size as bytesLef) and the command
2173         *   response header (S_DS_GEN)
2174         */
2175        tlv_buf_size = scan_resp_size - (bytes_left
2176                                         + sizeof(scan_rsp->bss_descript_size)
2177                                         + sizeof(scan_rsp->number_of_sets)
2178                                         + S_DS_GEN);
2179
2180        tlv_data = (struct mwifiex_ie_types_data *) (scan_rsp->
2181                                                 bss_desc_and_tlv_buffer +
2182                                                 bytes_left);
2183
2184        /* Search the TLV buffer space in the scan response for any valid
2185           TLVs */
2186        mwifiex_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size,
2187                                             TLV_TYPE_TSFTIMESTAMP,
2188                                             (struct mwifiex_ie_types_data **)
2189                                             &tsf_tlv);
2190
2191        /* Search the TLV buffer space in the scan response for any valid
2192           TLVs */
2193        mwifiex_ret_802_11_scan_get_tlv_ptrs(adapter, tlv_data, tlv_buf_size,
2194                                             TLV_TYPE_CHANNELBANDLIST,
2195                                             (struct mwifiex_ie_types_data **)
2196                                             &chan_band_tlv);
2197
2198#ifdef CONFIG_PM
2199        if (priv->wdev.wiphy->wowlan_config)
2200                nd_config = priv->wdev.wiphy->wowlan_config->nd_config;
2201#endif
2202
2203        if (nd_config) {
2204                adapter->nd_info =
2205                        kzalloc(sizeof(struct cfg80211_wowlan_nd_match) +
2206                                sizeof(struct cfg80211_wowlan_nd_match *) *
2207                                scan_rsp->number_of_sets, GFP_ATOMIC);
2208
2209                if (adapter->nd_info)
2210                        adapter->nd_info->n_matches = scan_rsp->number_of_sets;
2211        }
2212
2213        for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) {
2214                /*
2215                 * If the TSF TLV was appended to the scan results, save this
2216                 * entry's TSF value in the fw_tsf field. It is the firmware's
2217                 * TSF value at the time the beacon or probe response was
2218                 * received.
2219                 */
2220                if (tsf_tlv)
2221                        memcpy(&fw_tsf, &tsf_tlv->tsf_data[idx * TSF_DATA_SIZE],
2222                               sizeof(fw_tsf));
2223
2224                if (chan_band_tlv) {
2225                        chan_band = &chan_band_tlv->chan_band_param[idx];
2226                        radio_type = &chan_band->radio_type;
2227                } else {
2228                        radio_type = NULL;
2229                }
2230
2231                if (chan_band_tlv && adapter->nd_info) {
2232                        adapter->nd_info->matches[idx] =
2233                                kzalloc(sizeof(*pmatch) + sizeof(u32),
2234                                        GFP_ATOMIC);
2235
2236                        pmatch = adapter->nd_info->matches[idx];
2237
2238                        if (pmatch) {
2239                                pmatch->n_channels = 1;
2240                                pmatch->channels[0] = chan_band->chan_number;
2241                        }
2242                }
2243
2244                ret = mwifiex_parse_single_response_buf(priv, &bss_info,
2245                                                        &bytes_left,
2246                                                        le64_to_cpu(fw_tsf),
2247                                                        radio_type, false, 0);
2248                if (ret)
2249                        goto check_next_scan;
2250        }
2251
2252check_next_scan:
2253        mwifiex_check_next_scan_command(priv);
2254        return ret;
2255}
2256
2257/*
2258 * This function prepares an extended scan command to be sent to the firmware
2259 *
2260 * This uses the scan command configuration sent to the command processing
2261 * module in command preparation stage to configure a extended scan command
2262 * structure to send to firmware.
2263 */
2264int mwifiex_cmd_802_11_scan_ext(struct mwifiex_private *priv,
2265                                struct host_cmd_ds_command *cmd,
2266                                void *data_buf)
2267{
2268        struct host_cmd_ds_802_11_scan_ext *ext_scan = &cmd->params.ext_scan;
2269        struct mwifiex_scan_cmd_config *scan_cfg = data_buf;
2270
2271        memcpy(ext_scan->tlv_buffer, scan_cfg->tlv_buf, scan_cfg->tlv_buf_len);
2272
2273        cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SCAN_EXT);
2274
2275        /* Size is equal to the sizeof(fixed portions) + the TLV len + header */
2276        cmd->size = cpu_to_le16((u16)(sizeof(ext_scan->reserved)
2277                                      + scan_cfg->tlv_buf_len + S_DS_GEN));
2278
2279        return 0;
2280}
2281
2282/* This function prepares an background scan config command to be sent
2283 * to the firmware
2284 */
2285int mwifiex_cmd_802_11_bg_scan_config(struct mwifiex_private *priv,
2286                                      struct host_cmd_ds_command *cmd,
2287                                      void *data_buf)
2288{
2289        struct host_cmd_ds_802_11_bg_scan_config *bgscan_config =
2290                                        &cmd->params.bg_scan_config;
2291        struct mwifiex_bg_scan_cfg *bgscan_cfg_in = data_buf;
2292        u8 *tlv_pos = bgscan_config->tlv;
2293        u8 num_probes;
2294        u32 ssid_len, chan_idx, scan_type, scan_dur, chan_num;
2295        int i;
2296        struct mwifiex_ie_types_num_probes *num_probes_tlv;
2297        struct mwifiex_ie_types_repeat_count *repeat_count_tlv;
2298        struct mwifiex_ie_types_min_rssi_threshold *rssi_threshold_tlv;
2299        struct mwifiex_ie_types_bgscan_start_later *start_later_tlv;
2300        struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv;
2301        struct mwifiex_ie_types_chan_list_param_set *chan_list_tlv;
2302        struct mwifiex_chan_scan_param_set *temp_chan;
2303
2304        cmd->command = cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_CONFIG);
2305        cmd->size = cpu_to_le16(sizeof(*bgscan_config) + S_DS_GEN);
2306
2307        bgscan_config->action = cpu_to_le16(bgscan_cfg_in->action);
2308        bgscan_config->enable = bgscan_cfg_in->enable;
2309        bgscan_config->bss_type = bgscan_cfg_in->bss_type;
2310        bgscan_config->scan_interval =
2311                cpu_to_le32(bgscan_cfg_in->scan_interval);
2312        bgscan_config->report_condition =
2313                cpu_to_le32(bgscan_cfg_in->report_condition);
2314
2315        /*  stop sched scan  */
2316        if (!bgscan_config->enable)
2317                return 0;
2318
2319        bgscan_config->chan_per_scan = bgscan_cfg_in->chan_per_scan;
2320
2321        num_probes = (bgscan_cfg_in->num_probes ? bgscan_cfg_in->
2322                      num_probes : priv->adapter->scan_probes);
2323
2324        if (num_probes) {
2325                num_probes_tlv = (struct mwifiex_ie_types_num_probes *)tlv_pos;
2326                num_probes_tlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES);
2327                num_probes_tlv->header.len =
2328                        cpu_to_le16(sizeof(num_probes_tlv->num_probes));
2329                num_probes_tlv->num_probes = cpu_to_le16((u16)num_probes);
2330
2331                tlv_pos += sizeof(num_probes_tlv->header) +
2332                        le16_to_cpu(num_probes_tlv->header.len);
2333        }
2334
2335        if (bgscan_cfg_in->repeat_count) {
2336                repeat_count_tlv =
2337                        (struct mwifiex_ie_types_repeat_count *)tlv_pos;
2338                repeat_count_tlv->header.type =
2339                        cpu_to_le16(TLV_TYPE_REPEAT_COUNT);
2340                repeat_count_tlv->header.len =
2341                        cpu_to_le16(sizeof(repeat_count_tlv->repeat_count));
2342                repeat_count_tlv->repeat_count =
2343                        cpu_to_le16(bgscan_cfg_in->repeat_count);
2344
2345                tlv_pos += sizeof(repeat_count_tlv->header) +
2346                        le16_to_cpu(repeat_count_tlv->header.len);
2347        }
2348
2349        if (bgscan_cfg_in->rssi_threshold) {
2350                rssi_threshold_tlv =
2351                        (struct mwifiex_ie_types_min_rssi_threshold *)tlv_pos;
2352                rssi_threshold_tlv->header.type =
2353                        cpu_to_le16(TLV_TYPE_RSSI_LOW);
2354                rssi_threshold_tlv->header.len =
2355                        cpu_to_le16(sizeof(rssi_threshold_tlv->rssi_threshold));
2356                rssi_threshold_tlv->rssi_threshold =
2357                        cpu_to_le16(bgscan_cfg_in->rssi_threshold);
2358
2359                tlv_pos += sizeof(rssi_threshold_tlv->header) +
2360                        le16_to_cpu(rssi_threshold_tlv->header.len);
2361        }
2362
2363        for (i = 0; i < bgscan_cfg_in->num_ssids; i++) {
2364                ssid_len = bgscan_cfg_in->ssid_list[i].ssid.ssid_len;
2365
2366                wildcard_ssid_tlv =
2367                        (struct mwifiex_ie_types_wildcard_ssid_params *)tlv_pos;
2368                wildcard_ssid_tlv->header.type =
2369                                cpu_to_le16(TLV_TYPE_WILDCARDSSID);
2370                wildcard_ssid_tlv->header.len = cpu_to_le16(
2371                                (u16)(ssid_len + sizeof(wildcard_ssid_tlv->
2372                                                         max_ssid_length)));
2373
2374                /* max_ssid_length = 0 tells firmware to perform
2375                 * specific scan for the SSID filled, whereas
2376                 * max_ssid_length = IEEE80211_MAX_SSID_LEN is for
2377                 * wildcard scan.
2378                 */
2379                if (ssid_len)
2380                        wildcard_ssid_tlv->max_ssid_length = 0;
2381                else
2382                        wildcard_ssid_tlv->max_ssid_length =
2383                                                IEEE80211_MAX_SSID_LEN;
2384
2385                memcpy(wildcard_ssid_tlv->ssid,
2386                       bgscan_cfg_in->ssid_list[i].ssid.ssid, ssid_len);
2387
2388                tlv_pos += (sizeof(wildcard_ssid_tlv->header)
2389                                + le16_to_cpu(wildcard_ssid_tlv->header.len));
2390        }
2391
2392        chan_list_tlv = (struct mwifiex_ie_types_chan_list_param_set *)tlv_pos;
2393
2394        if (bgscan_cfg_in->chan_list[0].chan_number) {
2395                dev_dbg(priv->adapter->dev, "info: bgscan: Using supplied channel list\n");
2396
2397                chan_list_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
2398
2399                for (chan_idx = 0;
2400                     chan_idx < MWIFIEX_BG_SCAN_CHAN_MAX &&
2401                     bgscan_cfg_in->chan_list[chan_idx].chan_number;
2402                     chan_idx++) {
2403                        temp_chan = chan_list_tlv->chan_scan_param + chan_idx;
2404
2405                        /* Increment the TLV header length by size appended */
2406                        le16_unaligned_add_cpu(&chan_list_tlv->header.len,
2407                                               sizeof(
2408                                               chan_list_tlv->chan_scan_param));
2409
2410                        temp_chan->chan_number =
2411                                bgscan_cfg_in->chan_list[chan_idx].chan_number;
2412                        temp_chan->radio_type =
2413                                bgscan_cfg_in->chan_list[chan_idx].radio_type;
2414
2415                        scan_type =
2416                                bgscan_cfg_in->chan_list[chan_idx].scan_type;
2417
2418                        if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
2419                                temp_chan->chan_scan_mode_bitmap
2420                                        |= MWIFIEX_PASSIVE_SCAN;
2421                        else
2422                                temp_chan->chan_scan_mode_bitmap
2423                                        &= ~MWIFIEX_PASSIVE_SCAN;
2424
2425                        if (bgscan_cfg_in->chan_list[chan_idx].scan_time) {
2426                                scan_dur = (u16)bgscan_cfg_in->
2427                                        chan_list[chan_idx].scan_time;
2428                        } else {
2429                                scan_dur = (scan_type ==
2430                                            MWIFIEX_SCAN_TYPE_PASSIVE) ?
2431                                            priv->adapter->passive_scan_time :
2432                                            priv->adapter->specific_scan_time;
2433                        }
2434
2435                        temp_chan->min_scan_time = cpu_to_le16(scan_dur);
2436                        temp_chan->max_scan_time = cpu_to_le16(scan_dur);
2437                }
2438        } else {
2439                dev_dbg(priv->adapter->dev,
2440                        "info: bgscan: Creating full region channel list\n");
2441                chan_num =
2442                        mwifiex_bgscan_create_channel_list(priv, bgscan_cfg_in,
2443                                                           chan_list_tlv->
2444                                                           chan_scan_param);
2445                le16_unaligned_add_cpu(&chan_list_tlv->header.len,
2446                                       chan_num *
2447                             sizeof(chan_list_tlv->chan_scan_param[0]));
2448        }
2449
2450        tlv_pos += (sizeof(chan_list_tlv->header)
2451                        + le16_to_cpu(chan_list_tlv->header.len));
2452
2453        if (bgscan_cfg_in->start_later) {
2454                start_later_tlv =
2455                        (struct mwifiex_ie_types_bgscan_start_later *)tlv_pos;
2456                start_later_tlv->header.type =
2457                        cpu_to_le16(TLV_TYPE_BGSCAN_START_LATER);
2458                start_later_tlv->header.len =
2459                        cpu_to_le16(sizeof(start_later_tlv->start_later));
2460                start_later_tlv->start_later =
2461                        cpu_to_le16(bgscan_cfg_in->start_later);
2462
2463                tlv_pos += sizeof(start_later_tlv->header) +
2464                        le16_to_cpu(start_later_tlv->header.len);
2465        }
2466
2467        /* Append vendor specific IE TLV */
2468        mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_BGSCAN, &tlv_pos);
2469
2470        le16_unaligned_add_cpu(&cmd->size, tlv_pos - bgscan_config->tlv);
2471
2472        return 0;
2473}
2474
2475int mwifiex_stop_bg_scan(struct mwifiex_private *priv)
2476{
2477        struct mwifiex_bg_scan_cfg *bgscan_cfg;
2478
2479        if (!priv->sched_scanning) {
2480                dev_dbg(priv->adapter->dev, "bgscan already stopped!\n");
2481                return 0;
2482        }
2483
2484        bgscan_cfg = kzalloc(sizeof(*bgscan_cfg), GFP_KERNEL);
2485        if (!bgscan_cfg)
2486                return -ENOMEM;
2487
2488        bgscan_cfg->bss_type = MWIFIEX_BSS_MODE_INFRA;
2489        bgscan_cfg->action = MWIFIEX_BGSCAN_ACT_SET;
2490        bgscan_cfg->enable = false;
2491
2492        if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11_BG_SCAN_CONFIG,
2493                             HostCmd_ACT_GEN_SET, 0, bgscan_cfg, true)) {
2494                kfree(bgscan_cfg);
2495                return -EFAULT;
2496        }
2497
2498        kfree(bgscan_cfg);
2499        priv->sched_scanning = false;
2500
2501        return 0;
2502}
2503
2504static void
2505mwifiex_update_chan_statistics(struct mwifiex_private *priv,
2506                               struct mwifiex_ietypes_chanstats *tlv_stat)
2507{
2508        struct mwifiex_adapter *adapter = priv->adapter;
2509        u8 i, num_chan;
2510        struct mwifiex_fw_chan_stats *fw_chan_stats;
2511        struct mwifiex_chan_stats chan_stats;
2512
2513        fw_chan_stats = (void *)((u8 *)tlv_stat +
2514                              sizeof(struct mwifiex_ie_types_header));
2515        num_chan = le16_to_cpu(tlv_stat->header.len) /
2516                                              sizeof(struct mwifiex_chan_stats);
2517
2518        for (i = 0 ; i < num_chan; i++) {
2519                if (adapter->survey_idx >= adapter->num_in_chan_stats) {
2520                        mwifiex_dbg(adapter, WARN,
2521                                    "FW reported too many channel results (max %d)\n",
2522                                    adapter->num_in_chan_stats);
2523                        return;
2524                }
2525                chan_stats.chan_num = fw_chan_stats->chan_num;
2526                chan_stats.bandcfg = fw_chan_stats->bandcfg;
2527                chan_stats.flags = fw_chan_stats->flags;
2528                chan_stats.noise = fw_chan_stats->noise;
2529                chan_stats.total_bss = le16_to_cpu(fw_chan_stats->total_bss);
2530                chan_stats.cca_scan_dur =
2531                                       le16_to_cpu(fw_chan_stats->cca_scan_dur);
2532                chan_stats.cca_busy_dur =
2533                                       le16_to_cpu(fw_chan_stats->cca_busy_dur);
2534                mwifiex_dbg(adapter, INFO,
2535                            "chan=%d, noise=%d, total_network=%d scan_duration=%d, busy_duration=%d\n",
2536                            chan_stats.chan_num,
2537                            chan_stats.noise,
2538                            chan_stats.total_bss,
2539                            chan_stats.cca_scan_dur,
2540                            chan_stats.cca_busy_dur);
2541                memcpy(&adapter->chan_stats[adapter->survey_idx++], &chan_stats,
2542                       sizeof(struct mwifiex_chan_stats));
2543                fw_chan_stats++;
2544        }
2545}
2546
2547/* This function handles the command response of extended scan */
2548int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv,
2549                                struct host_cmd_ds_command *resp)
2550{
2551        struct mwifiex_adapter *adapter = priv->adapter;
2552        struct host_cmd_ds_802_11_scan_ext *ext_scan_resp;
2553        struct mwifiex_ie_types_header *tlv;
2554        struct mwifiex_ietypes_chanstats *tlv_stat;
2555        u16 buf_left, type, len;
2556
2557        struct host_cmd_ds_command *cmd_ptr;
2558        struct cmd_ctrl_node *cmd_node;
2559        bool complete_scan = false;
2560
2561        mwifiex_dbg(adapter, INFO, "info: EXT scan returns successfully\n");
2562
2563        ext_scan_resp = &resp->params.ext_scan;
2564
2565        tlv = (void *)ext_scan_resp->tlv_buffer;
2566        buf_left = le16_to_cpu(resp->size) - (sizeof(*ext_scan_resp) + S_DS_GEN
2567                                              - 1);
2568
2569        while (buf_left >= sizeof(struct mwifiex_ie_types_header)) {
2570                type = le16_to_cpu(tlv->type);
2571                len = le16_to_cpu(tlv->len);
2572
2573                if (buf_left < (sizeof(struct mwifiex_ie_types_header) + len)) {
2574                        mwifiex_dbg(adapter, ERROR,
2575                                    "error processing scan response TLVs");
2576                        break;
2577                }
2578
2579                switch (type) {
2580                case TLV_TYPE_CHANNEL_STATS:
2581                        tlv_stat = (void *)tlv;
2582                        mwifiex_update_chan_statistics(priv, tlv_stat);
2583                        break;
2584                default:
2585                        break;
2586                }
2587
2588                buf_left -= len + sizeof(struct mwifiex_ie_types_header);
2589                tlv = (void *)((u8 *)tlv + len +
2590                               sizeof(struct mwifiex_ie_types_header));
2591        }
2592
2593        spin_lock_bh(&adapter->cmd_pending_q_lock);
2594        spin_lock_bh(&adapter->scan_pending_q_lock);
2595        if (list_empty(&adapter->scan_pending_q)) {
2596                complete_scan = true;
2597                list_for_each_entry(cmd_node, &adapter->cmd_pending_q, list) {
2598                        cmd_ptr = (void *)cmd_node->cmd_skb->data;
2599                        if (le16_to_cpu(cmd_ptr->command) ==
2600                            HostCmd_CMD_802_11_SCAN_EXT) {
2601                                mwifiex_dbg(adapter, INFO,
2602                                            "Scan pending in command pending list");
2603                                complete_scan = false;
2604                                break;
2605                        }
2606                }
2607        }
2608        spin_unlock_bh(&adapter->scan_pending_q_lock);
2609        spin_unlock_bh(&adapter->cmd_pending_q_lock);
2610
2611        if (complete_scan)
2612                mwifiex_complete_scan(priv);
2613
2614        return 0;
2615}
2616
2617/* This function This function handles the event extended scan report. It
2618 * parses extended scan results and informs to cfg80211 stack.
2619 */
2620int mwifiex_handle_event_ext_scan_report(struct mwifiex_private *priv,
2621                                         void *buf)
2622{
2623        int ret = 0;
2624        struct mwifiex_adapter *adapter = priv->adapter;
2625        u8 *bss_info;
2626        u32 bytes_left, bytes_left_for_tlv, idx;
2627        u16 type, len;
2628        struct mwifiex_ie_types_data *tlv;
2629        struct mwifiex_ie_types_bss_scan_rsp *scan_rsp_tlv;
2630        struct mwifiex_ie_types_bss_scan_info *scan_info_tlv;
2631        u8 *radio_type;
2632        u64 fw_tsf = 0;
2633        s32 rssi = 0;
2634        struct mwifiex_event_scan_result *event_scan = buf;
2635        u8 num_of_set = event_scan->num_of_set;
2636        u8 *scan_resp = buf + sizeof(struct mwifiex_event_scan_result);
2637        u16 scan_resp_size = le16_to_cpu(event_scan->buf_size);
2638
2639        if (num_of_set > MWIFIEX_MAX_AP) {
2640                mwifiex_dbg(adapter, ERROR,
2641                            "EXT_SCAN: Invalid number of AP returned (%d)!!\n",
2642                            num_of_set);
2643                ret = -1;
2644                goto check_next_scan;
2645        }
2646
2647        bytes_left = scan_resp_size;
2648        mwifiex_dbg(adapter, INFO,
2649                    "EXT_SCAN: size %d, returned %d APs...",
2650                    scan_resp_size, num_of_set);
2651        mwifiex_dbg_dump(adapter, CMD_D, "EXT_SCAN buffer:", buf,
2652                         scan_resp_size +
2653                         sizeof(struct mwifiex_event_scan_result));
2654
2655        tlv = (struct mwifiex_ie_types_data *)scan_resp;
2656
2657        for (idx = 0; idx < num_of_set && bytes_left; idx++) {
2658                type = le16_to_cpu(tlv->header.type);
2659                len = le16_to_cpu(tlv->header.len);
2660                if (bytes_left < sizeof(struct mwifiex_ie_types_header) + len) {
2661                        mwifiex_dbg(adapter, ERROR,
2662                                    "EXT_SCAN: Error bytes left < TLV length\n");
2663                        break;
2664                }
2665                scan_rsp_tlv = NULL;
2666                scan_info_tlv = NULL;
2667                bytes_left_for_tlv = bytes_left;
2668
2669                /* BSS response TLV with beacon or probe response buffer
2670                 * at the initial position of each descriptor
2671                 */
2672                if (type != TLV_TYPE_BSS_SCAN_RSP)
2673                        break;
2674
2675                bss_info = (u8 *)tlv;
2676                scan_rsp_tlv = (struct mwifiex_ie_types_bss_scan_rsp *)tlv;
2677                tlv = (struct mwifiex_ie_types_data *)(tlv->data + len);
2678                bytes_left_for_tlv -=
2679                                (len + sizeof(struct mwifiex_ie_types_header));
2680
2681                while (bytes_left_for_tlv >=
2682                       sizeof(struct mwifiex_ie_types_header) &&
2683                       le16_to_cpu(tlv->header.type) != TLV_TYPE_BSS_SCAN_RSP) {
2684                        type = le16_to_cpu(tlv->header.type);
2685                        len = le16_to_cpu(tlv->header.len);
2686                        if (bytes_left_for_tlv <
2687                            sizeof(struct mwifiex_ie_types_header) + len) {
2688                                mwifiex_dbg(adapter, ERROR,
2689                                            "EXT_SCAN: Error in processing TLV,\t"
2690                                            "bytes left < TLV length\n");
2691                                scan_rsp_tlv = NULL;
2692                                bytes_left_for_tlv = 0;
2693                                continue;
2694                        }
2695                        switch (type) {
2696                        case TLV_TYPE_BSS_SCAN_INFO:
2697                                scan_info_tlv =
2698                                  (struct mwifiex_ie_types_bss_scan_info *)tlv;
2699                                if (len !=
2700                                 sizeof(struct mwifiex_ie_types_bss_scan_info) -
2701                                 sizeof(struct mwifiex_ie_types_header)) {
2702                                        bytes_left_for_tlv = 0;
2703                                        continue;
2704                                }
2705                                break;
2706                        default:
2707                                break;
2708                        }
2709                        tlv = (struct mwifiex_ie_types_data *)(tlv->data + len);
2710                        bytes_left -=
2711                                (len + sizeof(struct mwifiex_ie_types_header));
2712                        bytes_left_for_tlv -=
2713                                (len + sizeof(struct mwifiex_ie_types_header));
2714                }
2715
2716                if (!scan_rsp_tlv)
2717                        break;
2718
2719                /* Advance pointer to the beacon buffer length and
2720                 * update the bytes count so that the function
2721                 * wlan_interpret_bss_desc_with_ie() can handle the
2722                 * scan buffer withut any change
2723                 */
2724                bss_info += sizeof(u16);
2725                bytes_left -= sizeof(u16);
2726
2727                if (scan_info_tlv) {
2728                        rssi = (s32)(s16)(le16_to_cpu(scan_info_tlv->rssi));
2729                        rssi *= 100;           /* Convert dBm to mBm */
2730                        mwifiex_dbg(adapter, INFO,
2731                                    "info: InterpretIE: RSSI=%d\n", rssi);
2732                        fw_tsf = le64_to_cpu(scan_info_tlv->tsf);
2733                        radio_type = &scan_info_tlv->radio_type;
2734                } else {
2735                        radio_type = NULL;
2736                }
2737                ret = mwifiex_parse_single_response_buf(priv, &bss_info,
2738                                                        &bytes_left, fw_tsf,
2739                                                        radio_type, true, rssi);
2740                if (ret)
2741                        goto check_next_scan;
2742        }
2743
2744check_next_scan:
2745        if (!event_scan->more_event)
2746                mwifiex_check_next_scan_command(priv);
2747
2748        return ret;
2749}
2750
2751/*
2752 * This function prepares command for background scan query.
2753 *
2754 * Preparation includes -
2755 *      - Setting command ID and proper size
2756 *      - Setting background scan flush parameter
2757 *      - Ensuring correct endian-ness
2758 */
2759int mwifiex_cmd_802_11_bg_scan_query(struct host_cmd_ds_command *cmd)
2760{
2761        struct host_cmd_ds_802_11_bg_scan_query *bg_query =
2762                &cmd->params.bg_scan_query;
2763
2764        cmd->command = cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_QUERY);
2765        cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_bg_scan_query)
2766                                + S_DS_GEN);
2767
2768        bg_query->flush = 1;
2769
2770        return 0;
2771}
2772
2773/*
2774 * This function inserts scan command node to the scan pending queue.
2775 */
2776void
2777mwifiex_queue_scan_cmd(struct mwifiex_private *priv,
2778                       struct cmd_ctrl_node *cmd_node)
2779{
2780        struct mwifiex_adapter *adapter = priv->adapter;
2781
2782        cmd_node->wait_q_enabled = true;
2783        cmd_node->condition = &adapter->scan_wait_q_woken;
2784        spin_lock_bh(&adapter->scan_pending_q_lock);
2785        list_add_tail(&cmd_node->list, &adapter->scan_pending_q);
2786        spin_unlock_bh(&adapter->scan_pending_q_lock);
2787}
2788
2789/*
2790 * This function sends a scan command for all available channels to the
2791 * firmware, filtered on a specific SSID.
2792 */
2793static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv,
2794                                      struct cfg80211_ssid *req_ssid)
2795{
2796        struct mwifiex_adapter *adapter = priv->adapter;
2797        int ret;
2798        struct mwifiex_user_scan_cfg *scan_cfg;
2799
2800        if (adapter->scan_processing) {
2801                mwifiex_dbg(adapter, WARN,
2802                            "cmd: Scan already in process...\n");
2803                return -EBUSY;
2804        }
2805
2806        if (priv->scan_block) {
2807                mwifiex_dbg(adapter, WARN,
2808                            "cmd: Scan is blocked during association...\n");
2809                return -EBUSY;
2810        }
2811
2812        scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL);
2813        if (!scan_cfg)
2814                return -ENOMEM;
2815
2816        scan_cfg->ssid_list = req_ssid;
2817        scan_cfg->num_ssids = 1;
2818
2819        ret = mwifiex_scan_networks(priv, scan_cfg);
2820
2821        kfree(scan_cfg);
2822        return ret;
2823}
2824
2825/*
2826 * Sends IOCTL request to start a scan.
2827 *
2828 * This function allocates the IOCTL request buffer, fills it
2829 * with requisite parameters and calls the IOCTL handler.
2830 *
2831 * Scan command can be issued for both normal scan and specific SSID
2832 * scan, depending upon whether an SSID is provided or not.
2833 */
2834int mwifiex_request_scan(struct mwifiex_private *priv,
2835                         struct cfg80211_ssid *req_ssid)
2836{
2837        int ret;
2838
2839        if (mutex_lock_interruptible(&priv->async_mutex)) {
2840                mwifiex_dbg(priv->adapter, ERROR,
2841                            "%s: acquire semaphore fail\n",
2842                            __func__);
2843                return -1;
2844        }
2845
2846        priv->adapter->scan_wait_q_woken = false;
2847
2848        if (req_ssid && req_ssid->ssid_len != 0)
2849                /* Specific SSID scan */
2850                ret = mwifiex_scan_specific_ssid(priv, req_ssid);
2851        else
2852                /* Normal scan */
2853                ret = mwifiex_scan_networks(priv, NULL);
2854
2855        mutex_unlock(&priv->async_mutex);
2856
2857        return ret;
2858}
2859
2860/*
2861 * This function appends the vendor specific IE TLV to a buffer.
2862 */
2863int
2864mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv,
2865                            u16 vsie_mask, u8 **buffer)
2866{
2867        int id, ret_len = 0;
2868        struct mwifiex_ie_types_vendor_param_set *vs_param_set;
2869
2870        if (!buffer)
2871                return 0;
2872        if (!(*buffer))
2873                return 0;
2874
2875        /*
2876         * Traverse through the saved vendor specific IE array and append
2877         * the selected(scan/assoc/adhoc) IE as TLV to the command
2878         */
2879        for (id = 0; id < MWIFIEX_MAX_VSIE_NUM; id++) {
2880                if (priv->vs_ie[id].mask & vsie_mask) {
2881                        vs_param_set =
2882                                (struct mwifiex_ie_types_vendor_param_set *)
2883                                *buffer;
2884                        vs_param_set->header.type =
2885                                cpu_to_le16(TLV_TYPE_PASSTHROUGH);
2886                        vs_param_set->header.len =
2887                                cpu_to_le16((((u16) priv->vs_ie[id].ie[1])
2888                                & 0x00FF) + 2);
2889                        memcpy(vs_param_set->ie, priv->vs_ie[id].ie,
2890                               le16_to_cpu(vs_param_set->header.len));
2891                        *buffer += le16_to_cpu(vs_param_set->header.len) +
2892                                   sizeof(struct mwifiex_ie_types_header);
2893                        ret_len += le16_to_cpu(vs_param_set->header.len) +
2894                                   sizeof(struct mwifiex_ie_types_header);
2895                }
2896        }
2897        return ret_len;
2898}
2899
2900/*
2901 * This function saves a beacon buffer of the current BSS descriptor.
2902 *
2903 * The current beacon buffer is saved so that it can be restored in the
2904 * following cases that makes the beacon buffer not to contain the current
2905 * ssid's beacon buffer.
2906 *      - The current ssid was not found somehow in the last scan.
2907 *      - The current ssid was the last entry of the scan table and overloaded.
2908 */
2909void
2910mwifiex_save_curr_bcn(struct mwifiex_private *priv)
2911{
2912        struct mwifiex_bssdescriptor *curr_bss =
2913                &priv->curr_bss_params.bss_descriptor;
2914
2915        if (!curr_bss->beacon_buf_size)
2916                return;
2917
2918        /* allocate beacon buffer at 1st time; or if it's size has changed */
2919        if (!priv->curr_bcn_buf ||
2920            priv->curr_bcn_size != curr_bss->beacon_buf_size) {
2921                priv->curr_bcn_size = curr_bss->beacon_buf_size;
2922
2923                kfree(priv->curr_bcn_buf);
2924                priv->curr_bcn_buf = kmalloc(curr_bss->beacon_buf_size,
2925                                             GFP_ATOMIC);
2926                if (!priv->curr_bcn_buf)
2927                        return;
2928        }
2929
2930        memcpy(priv->curr_bcn_buf, curr_bss->beacon_buf,
2931               curr_bss->beacon_buf_size);
2932        mwifiex_dbg(priv->adapter, INFO,
2933                    "info: current beacon saved %d\n",
2934                    priv->curr_bcn_size);
2935
2936        curr_bss->beacon_buf = priv->curr_bcn_buf;
2937
2938        /* adjust the pointers in the current BSS descriptor */
2939        if (curr_bss->bcn_wpa_ie)
2940                curr_bss->bcn_wpa_ie =
2941                        (struct ieee_types_vendor_specific *)
2942                        (curr_bss->beacon_buf +
2943                         curr_bss->wpa_offset);
2944
2945        if (curr_bss->bcn_rsn_ie)
2946                curr_bss->bcn_rsn_ie = (struct ieee_types_generic *)
2947                        (curr_bss->beacon_buf +
2948                         curr_bss->rsn_offset);
2949
2950        if (curr_bss->bcn_ht_cap)
2951                curr_bss->bcn_ht_cap = (struct ieee80211_ht_cap *)
2952                        (curr_bss->beacon_buf +
2953                         curr_bss->ht_cap_offset);
2954
2955        if (curr_bss->bcn_ht_oper)
2956                curr_bss->bcn_ht_oper = (struct ieee80211_ht_operation *)
2957                        (curr_bss->beacon_buf +
2958                         curr_bss->ht_info_offset);
2959
2960        if (curr_bss->bcn_vht_cap)
2961                curr_bss->bcn_vht_cap = (void *)(curr_bss->beacon_buf +
2962                                                 curr_bss->vht_cap_offset);
2963
2964        if (curr_bss->bcn_vht_oper)
2965                curr_bss->bcn_vht_oper = (void *)(curr_bss->beacon_buf +
2966                                                  curr_bss->vht_info_offset);
2967
2968        if (curr_bss->bcn_bss_co_2040)
2969                curr_bss->bcn_bss_co_2040 =
2970                        (curr_bss->beacon_buf + curr_bss->bss_co_2040_offset);
2971
2972        if (curr_bss->bcn_ext_cap)
2973                curr_bss->bcn_ext_cap = curr_bss->beacon_buf +
2974                        curr_bss->ext_cap_offset;
2975
2976        if (curr_bss->oper_mode)
2977                curr_bss->oper_mode = (void *)(curr_bss->beacon_buf +
2978                                               curr_bss->oper_mode_offset);
2979}
2980
2981/*
2982 * This function frees the current BSS descriptor beacon buffer.
2983 */
2984void
2985mwifiex_free_curr_bcn(struct mwifiex_private *priv)
2986{
2987        kfree(priv->curr_bcn_buf);
2988        priv->curr_bcn_buf = NULL;
2989}
2990