linux/drivers/net/wireless/marvell/mwifiex/uap_cmd.c
<<
>>
Prefs
   1/*
   2 * NXP Wireless LAN device driver: AP specific command handling
   3 *
   4 * Copyright 2011-2020 NXP
   5 *
   6 * This software file (the "File") is distributed by NXP
   7 * under the terms of the GNU General Public License Version 2, June 1991
   8 * (the "License").  You may use, redistribute and/or modify this File in
   9 * accordance with the terms and conditions of the License, a copy of which
  10 * is available by writing to the Free Software Foundation, Inc.,
  11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
  12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
  13 *
  14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
  15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
  16 * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
  17 * this warranty disclaimer.
  18 */
  19
  20#include "main.h"
  21#include "11ac.h"
  22#include "11n.h"
  23
  24/* This function parses security related parameters from cfg80211_ap_settings
  25 * and sets into FW understandable bss_config structure.
  26 */
  27int mwifiex_set_secure_params(struct mwifiex_private *priv,
  28                              struct mwifiex_uap_bss_param *bss_config,
  29                              struct cfg80211_ap_settings *params) {
  30        int i;
  31        struct mwifiex_wep_key wep_key;
  32
  33        if (!params->privacy) {
  34                bss_config->protocol = PROTOCOL_NO_SECURITY;
  35                bss_config->key_mgmt = KEY_MGMT_NONE;
  36                bss_config->wpa_cfg.length = 0;
  37                priv->sec_info.wep_enabled = 0;
  38                priv->sec_info.wpa_enabled = 0;
  39                priv->sec_info.wpa2_enabled = 0;
  40
  41                return 0;
  42        }
  43
  44        switch (params->auth_type) {
  45        case NL80211_AUTHTYPE_OPEN_SYSTEM:
  46                bss_config->auth_mode = WLAN_AUTH_OPEN;
  47                break;
  48        case NL80211_AUTHTYPE_SHARED_KEY:
  49                bss_config->auth_mode = WLAN_AUTH_SHARED_KEY;
  50                break;
  51        case NL80211_AUTHTYPE_NETWORK_EAP:
  52                bss_config->auth_mode = WLAN_AUTH_LEAP;
  53                break;
  54        default:
  55                bss_config->auth_mode = MWIFIEX_AUTH_MODE_AUTO;
  56                break;
  57        }
  58
  59        bss_config->key_mgmt_operation |= KEY_MGMT_ON_HOST;
  60
  61        for (i = 0; i < params->crypto.n_akm_suites; i++) {
  62                switch (params->crypto.akm_suites[i]) {
  63                case WLAN_AKM_SUITE_8021X:
  64                        if (params->crypto.wpa_versions &
  65                            NL80211_WPA_VERSION_1) {
  66                                bss_config->protocol = PROTOCOL_WPA;
  67                                bss_config->key_mgmt = KEY_MGMT_EAP;
  68                        }
  69                        if (params->crypto.wpa_versions &
  70                            NL80211_WPA_VERSION_2) {
  71                                bss_config->protocol |= PROTOCOL_WPA2;
  72                                bss_config->key_mgmt = KEY_MGMT_EAP;
  73                        }
  74                        break;
  75                case WLAN_AKM_SUITE_PSK:
  76                        if (params->crypto.wpa_versions &
  77                            NL80211_WPA_VERSION_1) {
  78                                bss_config->protocol = PROTOCOL_WPA;
  79                                bss_config->key_mgmt = KEY_MGMT_PSK;
  80                        }
  81                        if (params->crypto.wpa_versions &
  82                            NL80211_WPA_VERSION_2) {
  83                                bss_config->protocol |= PROTOCOL_WPA2;
  84                                bss_config->key_mgmt = KEY_MGMT_PSK;
  85                        }
  86                        break;
  87                default:
  88                        break;
  89                }
  90        }
  91        for (i = 0; i < params->crypto.n_ciphers_pairwise; i++) {
  92                switch (params->crypto.ciphers_pairwise[i]) {
  93                case WLAN_CIPHER_SUITE_WEP40:
  94                case WLAN_CIPHER_SUITE_WEP104:
  95                        break;
  96                case WLAN_CIPHER_SUITE_TKIP:
  97                        if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
  98                                bss_config->wpa_cfg.pairwise_cipher_wpa |=
  99                                                                CIPHER_TKIP;
 100                        if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
 101                                bss_config->wpa_cfg.pairwise_cipher_wpa2 |=
 102                                                                CIPHER_TKIP;
 103                        break;
 104                case WLAN_CIPHER_SUITE_CCMP:
 105                        if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1)
 106                                bss_config->wpa_cfg.pairwise_cipher_wpa |=
 107                                                                CIPHER_AES_CCMP;
 108                        if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)
 109                                bss_config->wpa_cfg.pairwise_cipher_wpa2 |=
 110                                                                CIPHER_AES_CCMP;
 111                        break;
 112                default:
 113                        break;
 114                }
 115        }
 116
 117        switch (params->crypto.cipher_group) {
 118        case WLAN_CIPHER_SUITE_WEP40:
 119        case WLAN_CIPHER_SUITE_WEP104:
 120                if (priv->sec_info.wep_enabled) {
 121                        bss_config->protocol = PROTOCOL_STATIC_WEP;
 122                        bss_config->key_mgmt = KEY_MGMT_NONE;
 123                        bss_config->wpa_cfg.length = 0;
 124
 125                        for (i = 0; i < NUM_WEP_KEYS; i++) {
 126                                wep_key = priv->wep_key[i];
 127                                bss_config->wep_cfg[i].key_index = i;
 128
 129                                if (priv->wep_key_curr_index == i)
 130                                        bss_config->wep_cfg[i].is_default = 1;
 131                                else
 132                                        bss_config->wep_cfg[i].is_default = 0;
 133
 134                                bss_config->wep_cfg[i].length =
 135                                                             wep_key.key_length;
 136                                memcpy(&bss_config->wep_cfg[i].key,
 137                                       &wep_key.key_material,
 138                                       wep_key.key_length);
 139                        }
 140                }
 141                break;
 142        case WLAN_CIPHER_SUITE_TKIP:
 143                bss_config->wpa_cfg.group_cipher = CIPHER_TKIP;
 144                break;
 145        case WLAN_CIPHER_SUITE_CCMP:
 146                bss_config->wpa_cfg.group_cipher = CIPHER_AES_CCMP;
 147                break;
 148        default:
 149                break;
 150        }
 151
 152        return 0;
 153}
 154
 155/* This function updates 11n related parameters from IE and sets them into
 156 * bss_config structure.
 157 */
 158void
 159mwifiex_set_ht_params(struct mwifiex_private *priv,
 160                      struct mwifiex_uap_bss_param *bss_cfg,
 161                      struct cfg80211_ap_settings *params)
 162{
 163        const u8 *ht_ie;
 164
 165        if (!ISSUPP_11NENABLED(priv->adapter->fw_cap_info))
 166                return;
 167
 168        ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, params->beacon.tail,
 169                                 params->beacon.tail_len);
 170        if (ht_ie) {
 171                memcpy(&bss_cfg->ht_cap, ht_ie + 2,
 172                       sizeof(struct ieee80211_ht_cap));
 173                priv->ap_11n_enabled = 1;
 174        } else {
 175                memset(&bss_cfg->ht_cap, 0, sizeof(struct ieee80211_ht_cap));
 176                bss_cfg->ht_cap.cap_info = cpu_to_le16(MWIFIEX_DEF_HT_CAP);
 177                bss_cfg->ht_cap.ampdu_params_info = MWIFIEX_DEF_AMPDU;
 178        }
 179
 180        return;
 181}
 182
 183/* This function updates 11ac related parameters from IE
 184 * and sets them into bss_config structure.
 185 */
 186void mwifiex_set_vht_params(struct mwifiex_private *priv,
 187                            struct mwifiex_uap_bss_param *bss_cfg,
 188                            struct cfg80211_ap_settings *params)
 189{
 190        const u8 *vht_ie;
 191
 192        vht_ie = cfg80211_find_ie(WLAN_EID_VHT_CAPABILITY, params->beacon.tail,
 193                                  params->beacon.tail_len);
 194        if (vht_ie) {
 195                memcpy(&bss_cfg->vht_cap, vht_ie + 2,
 196                       sizeof(struct ieee80211_vht_cap));
 197                priv->ap_11ac_enabled = 1;
 198        } else {
 199                priv->ap_11ac_enabled = 0;
 200        }
 201
 202        return;
 203}
 204
 205/* This function updates 11ac related parameters from IE
 206 * and sets them into bss_config structure.
 207 */
 208void mwifiex_set_tpc_params(struct mwifiex_private *priv,
 209                            struct mwifiex_uap_bss_param *bss_cfg,
 210                            struct cfg80211_ap_settings *params)
 211{
 212        const u8 *tpc_ie;
 213
 214        tpc_ie = cfg80211_find_ie(WLAN_EID_TPC_REQUEST, params->beacon.tail,
 215                                  params->beacon.tail_len);
 216        if (tpc_ie)
 217                bss_cfg->power_constraint = *(tpc_ie + 2);
 218        else
 219                bss_cfg->power_constraint = 0;
 220}
 221
 222/* Enable VHT only when cfg80211_ap_settings has VHT IE.
 223 * Otherwise disable VHT.
 224 */
 225void mwifiex_set_vht_width(struct mwifiex_private *priv,
 226                           enum nl80211_chan_width width,
 227                           bool ap_11ac_enable)
 228{
 229        struct mwifiex_adapter *adapter = priv->adapter;
 230        struct mwifiex_11ac_vht_cfg vht_cfg;
 231
 232        vht_cfg.band_config = VHT_CFG_5GHZ;
 233        vht_cfg.cap_info = adapter->hw_dot_11ac_dev_cap;
 234
 235        if (!ap_11ac_enable) {
 236                vht_cfg.mcs_tx_set = DISABLE_VHT_MCS_SET;
 237                vht_cfg.mcs_rx_set = DISABLE_VHT_MCS_SET;
 238        } else {
 239                vht_cfg.mcs_tx_set = DEFAULT_VHT_MCS_SET;
 240                vht_cfg.mcs_rx_set = DEFAULT_VHT_MCS_SET;
 241        }
 242
 243        vht_cfg.misc_config  = VHT_CAP_UAP_ONLY;
 244
 245        if (ap_11ac_enable && width >= NL80211_CHAN_WIDTH_80)
 246                vht_cfg.misc_config |= VHT_BW_80_160_80P80;
 247
 248        mwifiex_send_cmd(priv, HostCmd_CMD_11AC_CFG,
 249                         HostCmd_ACT_GEN_SET, 0, &vht_cfg, true);
 250
 251        return;
 252}
 253
 254/* This function finds supported rates IE from beacon parameter and sets
 255 * these rates into bss_config structure.
 256 */
 257void
 258mwifiex_set_uap_rates(struct mwifiex_uap_bss_param *bss_cfg,
 259                      struct cfg80211_ap_settings *params)
 260{
 261        struct ieee_types_header *rate_ie;
 262        int var_offset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
 263        const u8 *var_pos = params->beacon.head + var_offset;
 264        int len = params->beacon.head_len - var_offset;
 265        u8 rate_len = 0;
 266
 267        rate_ie = (void *)cfg80211_find_ie(WLAN_EID_SUPP_RATES, var_pos, len);
 268        if (rate_ie) {
 269                if (rate_ie->len > MWIFIEX_SUPPORTED_RATES)
 270                        return;
 271                memcpy(bss_cfg->rates, rate_ie + 1, rate_ie->len);
 272                rate_len = rate_ie->len;
 273        }
 274
 275        rate_ie = (void *)cfg80211_find_ie(WLAN_EID_EXT_SUPP_RATES,
 276                                           params->beacon.tail,
 277                                           params->beacon.tail_len);
 278        if (rate_ie) {
 279                if (rate_ie->len > MWIFIEX_SUPPORTED_RATES - rate_len)
 280                        return;
 281                memcpy(bss_cfg->rates + rate_len, rate_ie + 1, rate_ie->len);
 282        }
 283
 284        return;
 285}
 286
 287/* This function initializes some of mwifiex_uap_bss_param variables.
 288 * This helps FW in ignoring invalid values. These values may or may not
 289 * be get updated to valid ones at later stage.
 290 */
 291void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config)
 292{
 293        config->bcast_ssid_ctl = 0x7F;
 294        config->radio_ctl = 0x7F;
 295        config->dtim_period = 0x7F;
 296        config->beacon_period = 0x7FFF;
 297        config->auth_mode = 0x7F;
 298        config->rts_threshold = 0x7FFF;
 299        config->frag_threshold = 0x7FFF;
 300        config->retry_limit = 0x7F;
 301        config->qos_info = 0xFF;
 302}
 303
 304/* This function parses BSS related parameters from structure
 305 * and prepares TLVs specific to WPA/WPA2 security.
 306 * These TLVs are appended to command buffer.
 307 */
 308static void
 309mwifiex_uap_bss_wpa(u8 **tlv_buf, void *cmd_buf, u16 *param_size)
 310{
 311        struct host_cmd_tlv_pwk_cipher *pwk_cipher;
 312        struct host_cmd_tlv_gwk_cipher *gwk_cipher;
 313        struct host_cmd_tlv_passphrase *passphrase;
 314        struct host_cmd_tlv_akmp *tlv_akmp;
 315        struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
 316        u16 cmd_size = *param_size;
 317        u8 *tlv = *tlv_buf;
 318
 319        tlv_akmp = (struct host_cmd_tlv_akmp *)tlv;
 320        tlv_akmp->header.type = cpu_to_le16(TLV_TYPE_UAP_AKMP);
 321        tlv_akmp->header.len = cpu_to_le16(sizeof(struct host_cmd_tlv_akmp) -
 322                                        sizeof(struct mwifiex_ie_types_header));
 323        tlv_akmp->key_mgmt_operation = cpu_to_le16(bss_cfg->key_mgmt_operation);
 324        tlv_akmp->key_mgmt = cpu_to_le16(bss_cfg->key_mgmt);
 325        cmd_size += sizeof(struct host_cmd_tlv_akmp);
 326        tlv += sizeof(struct host_cmd_tlv_akmp);
 327
 328        if (bss_cfg->wpa_cfg.pairwise_cipher_wpa & VALID_CIPHER_BITMAP) {
 329                pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
 330                pwk_cipher->header.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER);
 331                pwk_cipher->header.len =
 332                        cpu_to_le16(sizeof(struct host_cmd_tlv_pwk_cipher) -
 333                                    sizeof(struct mwifiex_ie_types_header));
 334                pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA);
 335                pwk_cipher->cipher = bss_cfg->wpa_cfg.pairwise_cipher_wpa;
 336                cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
 337                tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
 338        }
 339
 340        if (bss_cfg->wpa_cfg.pairwise_cipher_wpa2 & VALID_CIPHER_BITMAP) {
 341                pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
 342                pwk_cipher->header.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER);
 343                pwk_cipher->header.len =
 344                        cpu_to_le16(sizeof(struct host_cmd_tlv_pwk_cipher) -
 345                                    sizeof(struct mwifiex_ie_types_header));
 346                pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA2);
 347                pwk_cipher->cipher = bss_cfg->wpa_cfg.pairwise_cipher_wpa2;
 348                cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
 349                tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
 350        }
 351
 352        if (bss_cfg->wpa_cfg.group_cipher & VALID_CIPHER_BITMAP) {
 353                gwk_cipher = (struct host_cmd_tlv_gwk_cipher *)tlv;
 354                gwk_cipher->header.type = cpu_to_le16(TLV_TYPE_GWK_CIPHER);
 355                gwk_cipher->header.len =
 356                        cpu_to_le16(sizeof(struct host_cmd_tlv_gwk_cipher) -
 357                                    sizeof(struct mwifiex_ie_types_header));
 358                gwk_cipher->cipher = bss_cfg->wpa_cfg.group_cipher;
 359                cmd_size += sizeof(struct host_cmd_tlv_gwk_cipher);
 360                tlv += sizeof(struct host_cmd_tlv_gwk_cipher);
 361        }
 362
 363        if (bss_cfg->wpa_cfg.length) {
 364                passphrase = (struct host_cmd_tlv_passphrase *)tlv;
 365                passphrase->header.type =
 366                                cpu_to_le16(TLV_TYPE_UAP_WPA_PASSPHRASE);
 367                passphrase->header.len = cpu_to_le16(bss_cfg->wpa_cfg.length);
 368                memcpy(passphrase->passphrase, bss_cfg->wpa_cfg.passphrase,
 369                       bss_cfg->wpa_cfg.length);
 370                cmd_size += sizeof(struct mwifiex_ie_types_header) +
 371                            bss_cfg->wpa_cfg.length;
 372                tlv += sizeof(struct mwifiex_ie_types_header) +
 373                                bss_cfg->wpa_cfg.length;
 374        }
 375
 376        *param_size = cmd_size;
 377        *tlv_buf = tlv;
 378
 379        return;
 380}
 381
 382/* This function parses WMM related parameters from cfg80211_ap_settings
 383 * structure and updates bss_config structure.
 384 */
 385void
 386mwifiex_set_wmm_params(struct mwifiex_private *priv,
 387                       struct mwifiex_uap_bss_param *bss_cfg,
 388                       struct cfg80211_ap_settings *params)
 389{
 390        const u8 *vendor_ie;
 391        const u8 *wmm_ie;
 392        u8 wmm_oui[] = {0x00, 0x50, 0xf2, 0x02};
 393
 394        vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
 395                                            WLAN_OUI_TYPE_MICROSOFT_WMM,
 396                                            params->beacon.tail,
 397                                            params->beacon.tail_len);
 398        if (vendor_ie) {
 399                wmm_ie = vendor_ie;
 400                if (*(wmm_ie + 1) > sizeof(struct mwifiex_types_wmm_info))
 401                        return;
 402                memcpy(&bss_cfg->wmm_info, wmm_ie +
 403                       sizeof(struct ieee_types_header), *(wmm_ie + 1));
 404                priv->wmm_enabled = 1;
 405        } else {
 406                memset(&bss_cfg->wmm_info, 0, sizeof(bss_cfg->wmm_info));
 407                memcpy(&bss_cfg->wmm_info.oui, wmm_oui, sizeof(wmm_oui));
 408                bss_cfg->wmm_info.subtype = MWIFIEX_WMM_SUBTYPE;
 409                bss_cfg->wmm_info.version = MWIFIEX_WMM_VERSION;
 410                priv->wmm_enabled = 0;
 411        }
 412
 413        bss_cfg->qos_info = 0x00;
 414        return;
 415}
 416/* This function parses BSS related parameters from structure
 417 * and prepares TLVs specific to WEP encryption.
 418 * These TLVs are appended to command buffer.
 419 */
 420static void
 421mwifiex_uap_bss_wep(u8 **tlv_buf, void *cmd_buf, u16 *param_size)
 422{
 423        struct host_cmd_tlv_wep_key *wep_key;
 424        u16 cmd_size = *param_size;
 425        int i;
 426        u8 *tlv = *tlv_buf;
 427        struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
 428
 429        for (i = 0; i < NUM_WEP_KEYS; i++) {
 430                if (bss_cfg->wep_cfg[i].length &&
 431                    (bss_cfg->wep_cfg[i].length == WLAN_KEY_LEN_WEP40 ||
 432                     bss_cfg->wep_cfg[i].length == WLAN_KEY_LEN_WEP104)) {
 433                        wep_key = (struct host_cmd_tlv_wep_key *)tlv;
 434                        wep_key->header.type =
 435                                cpu_to_le16(TLV_TYPE_UAP_WEP_KEY);
 436                        wep_key->header.len =
 437                                cpu_to_le16(bss_cfg->wep_cfg[i].length + 2);
 438                        wep_key->key_index = bss_cfg->wep_cfg[i].key_index;
 439                        wep_key->is_default = bss_cfg->wep_cfg[i].is_default;
 440                        memcpy(wep_key->key, bss_cfg->wep_cfg[i].key,
 441                               bss_cfg->wep_cfg[i].length);
 442                        cmd_size += sizeof(struct mwifiex_ie_types_header) + 2 +
 443                                    bss_cfg->wep_cfg[i].length;
 444                        tlv += sizeof(struct mwifiex_ie_types_header) + 2 +
 445                                    bss_cfg->wep_cfg[i].length;
 446                }
 447        }
 448
 449        *param_size = cmd_size;
 450        *tlv_buf = tlv;
 451
 452        return;
 453}
 454
 455/* This function enable 11D if userspace set the country IE.
 456 */
 457void mwifiex_config_uap_11d(struct mwifiex_private *priv,
 458                            struct cfg80211_beacon_data *beacon_data)
 459{
 460        enum state_11d_t state_11d;
 461        const u8 *country_ie;
 462
 463        country_ie = cfg80211_find_ie(WLAN_EID_COUNTRY, beacon_data->tail,
 464                                      beacon_data->tail_len);
 465        if (country_ie) {
 466                /* Send cmd to FW to enable 11D function */
 467                state_11d = ENABLE_11D;
 468                if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
 469                                     HostCmd_ACT_GEN_SET, DOT11D_I,
 470                                     &state_11d, true)) {
 471                        mwifiex_dbg(priv->adapter, ERROR,
 472                                    "11D: failed to enable 11D\n");
 473                }
 474        }
 475}
 476
 477/* This function parses BSS related parameters from structure
 478 * and prepares TLVs. These TLVs are appended to command buffer.
 479*/
 480static int
 481mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
 482{
 483        struct host_cmd_tlv_dtim_period *dtim_period;
 484        struct host_cmd_tlv_beacon_period *beacon_period;
 485        struct host_cmd_tlv_ssid *ssid;
 486        struct host_cmd_tlv_bcast_ssid *bcast_ssid;
 487        struct host_cmd_tlv_channel_band *chan_band;
 488        struct host_cmd_tlv_frag_threshold *frag_threshold;
 489        struct host_cmd_tlv_rts_threshold *rts_threshold;
 490        struct host_cmd_tlv_retry_limit *retry_limit;
 491        struct host_cmd_tlv_encrypt_protocol *encrypt_protocol;
 492        struct host_cmd_tlv_auth_type *auth_type;
 493        struct host_cmd_tlv_rates *tlv_rates;
 494        struct host_cmd_tlv_ageout_timer *ao_timer, *ps_ao_timer;
 495        struct host_cmd_tlv_power_constraint *pwr_ct;
 496        struct mwifiex_ie_types_htcap *htcap;
 497        struct mwifiex_ie_types_wmmcap *wmm_cap;
 498        struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
 499        int i;
 500        u16 cmd_size = *param_size;
 501
 502        if (bss_cfg->ssid.ssid_len) {
 503                ssid = (struct host_cmd_tlv_ssid *)tlv;
 504                ssid->header.type = cpu_to_le16(TLV_TYPE_UAP_SSID);
 505                ssid->header.len = cpu_to_le16((u16)bss_cfg->ssid.ssid_len);
 506                memcpy(ssid->ssid, bss_cfg->ssid.ssid, bss_cfg->ssid.ssid_len);
 507                cmd_size += sizeof(struct mwifiex_ie_types_header) +
 508                            bss_cfg->ssid.ssid_len;
 509                tlv += sizeof(struct mwifiex_ie_types_header) +
 510                                bss_cfg->ssid.ssid_len;
 511
 512                bcast_ssid = (struct host_cmd_tlv_bcast_ssid *)tlv;
 513                bcast_ssid->header.type = cpu_to_le16(TLV_TYPE_UAP_BCAST_SSID);
 514                bcast_ssid->header.len =
 515                                cpu_to_le16(sizeof(bcast_ssid->bcast_ctl));
 516                bcast_ssid->bcast_ctl = bss_cfg->bcast_ssid_ctl;
 517                cmd_size += sizeof(struct host_cmd_tlv_bcast_ssid);
 518                tlv += sizeof(struct host_cmd_tlv_bcast_ssid);
 519        }
 520        if (bss_cfg->rates[0]) {
 521                tlv_rates = (struct host_cmd_tlv_rates *)tlv;
 522                tlv_rates->header.type = cpu_to_le16(TLV_TYPE_UAP_RATES);
 523
 524                for (i = 0; i < MWIFIEX_SUPPORTED_RATES && bss_cfg->rates[i];
 525                     i++)
 526                        tlv_rates->rates[i] = bss_cfg->rates[i];
 527
 528                tlv_rates->header.len = cpu_to_le16(i);
 529                cmd_size += sizeof(struct host_cmd_tlv_rates) + i;
 530                tlv += sizeof(struct host_cmd_tlv_rates) + i;
 531        }
 532        if (bss_cfg->channel &&
 533            (((bss_cfg->band_cfg & BIT(0)) == BAND_CONFIG_BG &&
 534              bss_cfg->channel <= MAX_CHANNEL_BAND_BG) ||
 535            ((bss_cfg->band_cfg & BIT(0)) == BAND_CONFIG_A &&
 536             bss_cfg->channel <= MAX_CHANNEL_BAND_A))) {
 537                chan_band = (struct host_cmd_tlv_channel_band *)tlv;
 538                chan_band->header.type = cpu_to_le16(TLV_TYPE_CHANNELBANDLIST);
 539                chan_band->header.len =
 540                        cpu_to_le16(sizeof(struct host_cmd_tlv_channel_band) -
 541                                    sizeof(struct mwifiex_ie_types_header));
 542                chan_band->band_config = bss_cfg->band_cfg;
 543                chan_band->channel = bss_cfg->channel;
 544                cmd_size += sizeof(struct host_cmd_tlv_channel_band);
 545                tlv += sizeof(struct host_cmd_tlv_channel_band);
 546        }
 547        if (bss_cfg->beacon_period >= MIN_BEACON_PERIOD &&
 548            bss_cfg->beacon_period <= MAX_BEACON_PERIOD) {
 549                beacon_period = (struct host_cmd_tlv_beacon_period *)tlv;
 550                beacon_period->header.type =
 551                                        cpu_to_le16(TLV_TYPE_UAP_BEACON_PERIOD);
 552                beacon_period->header.len =
 553                        cpu_to_le16(sizeof(struct host_cmd_tlv_beacon_period) -
 554                                    sizeof(struct mwifiex_ie_types_header));
 555                beacon_period->period = cpu_to_le16(bss_cfg->beacon_period);
 556                cmd_size += sizeof(struct host_cmd_tlv_beacon_period);
 557                tlv += sizeof(struct host_cmd_tlv_beacon_period);
 558        }
 559        if (bss_cfg->dtim_period >= MIN_DTIM_PERIOD &&
 560            bss_cfg->dtim_period <= MAX_DTIM_PERIOD) {
 561                dtim_period = (struct host_cmd_tlv_dtim_period *)tlv;
 562                dtim_period->header.type =
 563                        cpu_to_le16(TLV_TYPE_UAP_DTIM_PERIOD);
 564                dtim_period->header.len =
 565                        cpu_to_le16(sizeof(struct host_cmd_tlv_dtim_period) -
 566                                    sizeof(struct mwifiex_ie_types_header));
 567                dtim_period->period = bss_cfg->dtim_period;
 568                cmd_size += sizeof(struct host_cmd_tlv_dtim_period);
 569                tlv += sizeof(struct host_cmd_tlv_dtim_period);
 570        }
 571        if (bss_cfg->rts_threshold <= MWIFIEX_RTS_MAX_VALUE) {
 572                rts_threshold = (struct host_cmd_tlv_rts_threshold *)tlv;
 573                rts_threshold->header.type =
 574                                        cpu_to_le16(TLV_TYPE_UAP_RTS_THRESHOLD);
 575                rts_threshold->header.len =
 576                        cpu_to_le16(sizeof(struct host_cmd_tlv_rts_threshold) -
 577                                    sizeof(struct mwifiex_ie_types_header));
 578                rts_threshold->rts_thr = cpu_to_le16(bss_cfg->rts_threshold);
 579                cmd_size += sizeof(struct host_cmd_tlv_frag_threshold);
 580                tlv += sizeof(struct host_cmd_tlv_frag_threshold);
 581        }
 582        if ((bss_cfg->frag_threshold >= MWIFIEX_FRAG_MIN_VALUE) &&
 583            (bss_cfg->frag_threshold <= MWIFIEX_FRAG_MAX_VALUE)) {
 584                frag_threshold = (struct host_cmd_tlv_frag_threshold *)tlv;
 585                frag_threshold->header.type =
 586                                cpu_to_le16(TLV_TYPE_UAP_FRAG_THRESHOLD);
 587                frag_threshold->header.len =
 588                        cpu_to_le16(sizeof(struct host_cmd_tlv_frag_threshold) -
 589                                    sizeof(struct mwifiex_ie_types_header));
 590                frag_threshold->frag_thr = cpu_to_le16(bss_cfg->frag_threshold);
 591                cmd_size += sizeof(struct host_cmd_tlv_frag_threshold);
 592                tlv += sizeof(struct host_cmd_tlv_frag_threshold);
 593        }
 594        if (bss_cfg->retry_limit <= MWIFIEX_RETRY_LIMIT) {
 595                retry_limit = (struct host_cmd_tlv_retry_limit *)tlv;
 596                retry_limit->header.type =
 597                        cpu_to_le16(TLV_TYPE_UAP_RETRY_LIMIT);
 598                retry_limit->header.len =
 599                        cpu_to_le16(sizeof(struct host_cmd_tlv_retry_limit) -
 600                                    sizeof(struct mwifiex_ie_types_header));
 601                retry_limit->limit = (u8)bss_cfg->retry_limit;
 602                cmd_size += sizeof(struct host_cmd_tlv_retry_limit);
 603                tlv += sizeof(struct host_cmd_tlv_retry_limit);
 604        }
 605        if ((bss_cfg->protocol & PROTOCOL_WPA) ||
 606            (bss_cfg->protocol & PROTOCOL_WPA2) ||
 607            (bss_cfg->protocol & PROTOCOL_EAP))
 608                mwifiex_uap_bss_wpa(&tlv, cmd_buf, &cmd_size);
 609        else
 610                mwifiex_uap_bss_wep(&tlv, cmd_buf, &cmd_size);
 611
 612        if ((bss_cfg->auth_mode <= WLAN_AUTH_SHARED_KEY) ||
 613            (bss_cfg->auth_mode == MWIFIEX_AUTH_MODE_AUTO)) {
 614                auth_type = (struct host_cmd_tlv_auth_type *)tlv;
 615                auth_type->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
 616                auth_type->header.len =
 617                        cpu_to_le16(sizeof(struct host_cmd_tlv_auth_type) -
 618                        sizeof(struct mwifiex_ie_types_header));
 619                auth_type->auth_type = (u8)bss_cfg->auth_mode;
 620                cmd_size += sizeof(struct host_cmd_tlv_auth_type);
 621                tlv += sizeof(struct host_cmd_tlv_auth_type);
 622        }
 623        if (bss_cfg->protocol) {
 624                encrypt_protocol = (struct host_cmd_tlv_encrypt_protocol *)tlv;
 625                encrypt_protocol->header.type =
 626                        cpu_to_le16(TLV_TYPE_UAP_ENCRY_PROTOCOL);
 627                encrypt_protocol->header.len =
 628                        cpu_to_le16(sizeof(struct host_cmd_tlv_encrypt_protocol)
 629                        - sizeof(struct mwifiex_ie_types_header));
 630                encrypt_protocol->proto = cpu_to_le16(bss_cfg->protocol);
 631                cmd_size += sizeof(struct host_cmd_tlv_encrypt_protocol);
 632                tlv += sizeof(struct host_cmd_tlv_encrypt_protocol);
 633        }
 634
 635        if (bss_cfg->ht_cap.cap_info) {
 636                htcap = (struct mwifiex_ie_types_htcap *)tlv;
 637                htcap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY);
 638                htcap->header.len =
 639                                cpu_to_le16(sizeof(struct ieee80211_ht_cap));
 640                htcap->ht_cap.cap_info = bss_cfg->ht_cap.cap_info;
 641                htcap->ht_cap.ampdu_params_info =
 642                                             bss_cfg->ht_cap.ampdu_params_info;
 643                memcpy(&htcap->ht_cap.mcs, &bss_cfg->ht_cap.mcs,
 644                       sizeof(struct ieee80211_mcs_info));
 645                htcap->ht_cap.extended_ht_cap_info =
 646                                        bss_cfg->ht_cap.extended_ht_cap_info;
 647                htcap->ht_cap.tx_BF_cap_info = bss_cfg->ht_cap.tx_BF_cap_info;
 648                htcap->ht_cap.antenna_selection_info =
 649                                        bss_cfg->ht_cap.antenna_selection_info;
 650                cmd_size += sizeof(struct mwifiex_ie_types_htcap);
 651                tlv += sizeof(struct mwifiex_ie_types_htcap);
 652        }
 653
 654        if (bss_cfg->wmm_info.qos_info != 0xFF) {
 655                wmm_cap = (struct mwifiex_ie_types_wmmcap *)tlv;
 656                wmm_cap->header.type = cpu_to_le16(WLAN_EID_VENDOR_SPECIFIC);
 657                wmm_cap->header.len = cpu_to_le16(sizeof(wmm_cap->wmm_info));
 658                memcpy(&wmm_cap->wmm_info, &bss_cfg->wmm_info,
 659                       sizeof(wmm_cap->wmm_info));
 660                cmd_size += sizeof(struct mwifiex_ie_types_wmmcap);
 661                tlv += sizeof(struct mwifiex_ie_types_wmmcap);
 662        }
 663
 664        if (bss_cfg->sta_ao_timer) {
 665                ao_timer = (struct host_cmd_tlv_ageout_timer *)tlv;
 666                ao_timer->header.type = cpu_to_le16(TLV_TYPE_UAP_AO_TIMER);
 667                ao_timer->header.len = cpu_to_le16(sizeof(*ao_timer) -
 668                                        sizeof(struct mwifiex_ie_types_header));
 669                ao_timer->sta_ao_timer = cpu_to_le32(bss_cfg->sta_ao_timer);
 670                cmd_size += sizeof(*ao_timer);
 671                tlv += sizeof(*ao_timer);
 672        }
 673
 674        if (bss_cfg->power_constraint) {
 675                pwr_ct = (void *)tlv;
 676                pwr_ct->header.type = cpu_to_le16(TLV_TYPE_PWR_CONSTRAINT);
 677                pwr_ct->header.len = cpu_to_le16(sizeof(u8));
 678                pwr_ct->constraint = bss_cfg->power_constraint;
 679                cmd_size += sizeof(*pwr_ct);
 680                tlv += sizeof(*pwr_ct);
 681        }
 682
 683        if (bss_cfg->ps_sta_ao_timer) {
 684                ps_ao_timer = (struct host_cmd_tlv_ageout_timer *)tlv;
 685                ps_ao_timer->header.type =
 686                                cpu_to_le16(TLV_TYPE_UAP_PS_AO_TIMER);
 687                ps_ao_timer->header.len = cpu_to_le16(sizeof(*ps_ao_timer) -
 688                                sizeof(struct mwifiex_ie_types_header));
 689                ps_ao_timer->sta_ao_timer =
 690                                        cpu_to_le32(bss_cfg->ps_sta_ao_timer);
 691                cmd_size += sizeof(*ps_ao_timer);
 692                tlv += sizeof(*ps_ao_timer);
 693        }
 694
 695        *param_size = cmd_size;
 696
 697        return 0;
 698}
 699
 700/* This function parses custom IEs from IE list and prepares command buffer */
 701static int mwifiex_uap_custom_ie_prepare(u8 *tlv, void *cmd_buf, u16 *ie_size)
 702{
 703        struct mwifiex_ie_list *ap_ie = cmd_buf;
 704        struct mwifiex_ie_types_header *tlv_ie = (void *)tlv;
 705
 706        if (!ap_ie || !ap_ie->len)
 707                return -1;
 708
 709        *ie_size += le16_to_cpu(ap_ie->len) +
 710                        sizeof(struct mwifiex_ie_types_header);
 711
 712        tlv_ie->type = cpu_to_le16(TLV_TYPE_MGMT_IE);
 713        tlv_ie->len = ap_ie->len;
 714        tlv += sizeof(struct mwifiex_ie_types_header);
 715
 716        memcpy(tlv, ap_ie->ie_list, le16_to_cpu(ap_ie->len));
 717
 718        return 0;
 719}
 720
 721/* Parse AP config structure and prepare TLV based command structure
 722 * to be sent to FW for uAP configuration
 723 */
 724static int
 725mwifiex_cmd_uap_sys_config(struct host_cmd_ds_command *cmd, u16 cmd_action,
 726                           u32 type, void *cmd_buf)
 727{
 728        u8 *tlv;
 729        u16 cmd_size, param_size, ie_size;
 730        struct host_cmd_ds_sys_config *sys_cfg;
 731
 732        cmd->command = cpu_to_le16(HostCmd_CMD_UAP_SYS_CONFIG);
 733        cmd_size = (u16)(sizeof(struct host_cmd_ds_sys_config) + S_DS_GEN);
 734        sys_cfg = (struct host_cmd_ds_sys_config *)&cmd->params.uap_sys_config;
 735        sys_cfg->action = cpu_to_le16(cmd_action);
 736        tlv = sys_cfg->tlv;
 737
 738        switch (type) {
 739        case UAP_BSS_PARAMS_I:
 740                param_size = cmd_size;
 741                if (mwifiex_uap_bss_param_prepare(tlv, cmd_buf, &param_size))
 742                        return -1;
 743                cmd->size = cpu_to_le16(param_size);
 744                break;
 745        case UAP_CUSTOM_IE_I:
 746                ie_size = cmd_size;
 747                if (mwifiex_uap_custom_ie_prepare(tlv, cmd_buf, &ie_size))
 748                        return -1;
 749                cmd->size = cpu_to_le16(ie_size);
 750                break;
 751        default:
 752                return -1;
 753        }
 754
 755        return 0;
 756}
 757
 758/* This function prepares AP specific deauth command with mac supplied in
 759 * function parameter.
 760 */
 761static int mwifiex_cmd_uap_sta_deauth(struct mwifiex_private *priv,
 762                                      struct host_cmd_ds_command *cmd, u8 *mac)
 763{
 764        struct host_cmd_ds_sta_deauth *sta_deauth = &cmd->params.sta_deauth;
 765
 766        cmd->command = cpu_to_le16(HostCmd_CMD_UAP_STA_DEAUTH);
 767        memcpy(sta_deauth->mac, mac, ETH_ALEN);
 768        sta_deauth->reason = cpu_to_le16(WLAN_REASON_DEAUTH_LEAVING);
 769
 770        cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_sta_deauth) +
 771                                S_DS_GEN);
 772        return 0;
 773}
 774
 775/* This function prepares the AP specific commands before sending them
 776 * to the firmware.
 777 * This is a generic function which calls specific command preparation
 778 * routines based upon the command number.
 779 */
 780int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no,
 781                            u16 cmd_action, u32 type,
 782                            void *data_buf, void *cmd_buf)
 783{
 784        struct host_cmd_ds_command *cmd = cmd_buf;
 785
 786        switch (cmd_no) {
 787        case HostCmd_CMD_UAP_SYS_CONFIG:
 788                if (mwifiex_cmd_uap_sys_config(cmd, cmd_action, type, data_buf))
 789                        return -1;
 790                break;
 791        case HostCmd_CMD_UAP_BSS_START:
 792        case HostCmd_CMD_UAP_BSS_STOP:
 793        case HOST_CMD_APCMD_SYS_RESET:
 794        case HOST_CMD_APCMD_STA_LIST:
 795                cmd->command = cpu_to_le16(cmd_no);
 796                cmd->size = cpu_to_le16(S_DS_GEN);
 797                break;
 798        case HostCmd_CMD_UAP_STA_DEAUTH:
 799                if (mwifiex_cmd_uap_sta_deauth(priv, cmd, data_buf))
 800                        return -1;
 801                break;
 802        case HostCmd_CMD_CHAN_REPORT_REQUEST:
 803                if (mwifiex_cmd_issue_chan_report_request(priv, cmd_buf,
 804                                                          data_buf))
 805                        return -1;
 806                break;
 807        default:
 808                mwifiex_dbg(priv->adapter, ERROR,
 809                            "PREP_CMD: unknown cmd %#x\n", cmd_no);
 810                return -1;
 811        }
 812
 813        return 0;
 814}
 815
 816void mwifiex_uap_set_channel(struct mwifiex_private *priv,
 817                             struct mwifiex_uap_bss_param *bss_cfg,
 818                             struct cfg80211_chan_def chandef)
 819{
 820        u8 config_bands = 0, old_bands = priv->adapter->config_bands;
 821
 822        priv->bss_chandef = chandef;
 823
 824        bss_cfg->channel = ieee80211_frequency_to_channel(
 825                                                     chandef.chan->center_freq);
 826
 827        /* Set appropriate bands */
 828        if (chandef.chan->band == NL80211_BAND_2GHZ) {
 829                bss_cfg->band_cfg = BAND_CONFIG_BG;
 830                config_bands = BAND_B | BAND_G;
 831
 832                if (chandef.width > NL80211_CHAN_WIDTH_20_NOHT)
 833                        config_bands |= BAND_GN;
 834        } else {
 835                bss_cfg->band_cfg = BAND_CONFIG_A;
 836                config_bands = BAND_A;
 837
 838                if (chandef.width > NL80211_CHAN_WIDTH_20_NOHT)
 839                        config_bands |= BAND_AN;
 840
 841                if (chandef.width > NL80211_CHAN_WIDTH_40)
 842                        config_bands |= BAND_AAC;
 843        }
 844
 845        switch (chandef.width) {
 846        case NL80211_CHAN_WIDTH_5:
 847        case NL80211_CHAN_WIDTH_10:
 848        case NL80211_CHAN_WIDTH_20_NOHT:
 849        case NL80211_CHAN_WIDTH_20:
 850                break;
 851        case NL80211_CHAN_WIDTH_40:
 852                if (chandef.center_freq1 < chandef.chan->center_freq)
 853                        bss_cfg->band_cfg |= MWIFIEX_SEC_CHAN_BELOW;
 854                else
 855                        bss_cfg->band_cfg |= MWIFIEX_SEC_CHAN_ABOVE;
 856                break;
 857        case NL80211_CHAN_WIDTH_80:
 858        case NL80211_CHAN_WIDTH_80P80:
 859        case NL80211_CHAN_WIDTH_160:
 860                bss_cfg->band_cfg |=
 861                    mwifiex_get_sec_chan_offset(bss_cfg->channel) << 4;
 862                break;
 863        default:
 864                mwifiex_dbg(priv->adapter,
 865                            WARN, "Unknown channel width: %d\n",
 866                            chandef.width);
 867                break;
 868        }
 869
 870        priv->adapter->config_bands = config_bands;
 871
 872        if (old_bands != config_bands) {
 873                mwifiex_send_domain_info_cmd_fw(priv->adapter->wiphy);
 874                mwifiex_dnld_txpwr_table(priv);
 875        }
 876}
 877
 878int mwifiex_config_start_uap(struct mwifiex_private *priv,
 879                             struct mwifiex_uap_bss_param *bss_cfg)
 880{
 881        if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG,
 882                             HostCmd_ACT_GEN_SET,
 883                             UAP_BSS_PARAMS_I, bss_cfg, true)) {
 884                mwifiex_dbg(priv->adapter, ERROR,
 885                            "Failed to set AP configuration\n");
 886                return -1;
 887        }
 888
 889        if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START,
 890                             HostCmd_ACT_GEN_SET, 0, NULL, true)) {
 891                mwifiex_dbg(priv->adapter, ERROR,
 892                            "Failed to start the BSS\n");
 893                return -1;
 894        }
 895
 896        if (priv->sec_info.wep_enabled)
 897                priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;
 898        else
 899                priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
 900
 901        if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
 902                             HostCmd_ACT_GEN_SET, 0,
 903                             &priv->curr_pkt_filter, true))
 904                return -1;
 905
 906        return 0;
 907}
 908