Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * NXP Wireless LAN device driver: association and ad-hoc start/join
0004  *
0005  * Copyright 2011-2020 NXP
0006  */
0007 
0008 #include "decl.h"
0009 #include "ioctl.h"
0010 #include "util.h"
0011 #include "fw.h"
0012 #include "main.h"
0013 #include "wmm.h"
0014 #include "11n.h"
0015 #include "11ac.h"
0016 
0017 #define CAPINFO_MASK    (~(BIT(15) | BIT(14) | BIT(12) | BIT(11) | BIT(9)))
0018 
0019 /*
0020  * Append a generic IE as a pass through TLV to a TLV buffer.
0021  *
0022  * This function is called from the network join command preparation routine.
0023  *
0024  * If the IE buffer has been setup by the application, this routine appends
0025  * the buffer as a pass through TLV type to the request.
0026  */
0027 static int
0028 mwifiex_cmd_append_generic_ie(struct mwifiex_private *priv, u8 **buffer)
0029 {
0030     int ret_len = 0;
0031     struct mwifiex_ie_types_header ie_header;
0032 
0033     /* Null Checks */
0034     if (!buffer)
0035         return 0;
0036     if (!(*buffer))
0037         return 0;
0038 
0039     /*
0040      * If there is a generic ie buffer setup, append it to the return
0041      *   parameter buffer pointer.
0042      */
0043     if (priv->gen_ie_buf_len) {
0044         mwifiex_dbg(priv->adapter, INFO,
0045                 "info: %s: append generic ie len %d to %p\n",
0046                 __func__, priv->gen_ie_buf_len, *buffer);
0047 
0048         /* Wrap the generic IE buffer with a pass through TLV type */
0049         ie_header.type = cpu_to_le16(TLV_TYPE_PASSTHROUGH);
0050         ie_header.len = cpu_to_le16(priv->gen_ie_buf_len);
0051         memcpy(*buffer, &ie_header, sizeof(ie_header));
0052 
0053         /* Increment the return size and the return buffer pointer
0054            param */
0055         *buffer += sizeof(ie_header);
0056         ret_len += sizeof(ie_header);
0057 
0058         /* Copy the generic IE buffer to the output buffer, advance
0059            pointer */
0060         memcpy(*buffer, priv->gen_ie_buf, priv->gen_ie_buf_len);
0061 
0062         /* Increment the return size and the return buffer pointer
0063            param */
0064         *buffer += priv->gen_ie_buf_len;
0065         ret_len += priv->gen_ie_buf_len;
0066 
0067         /* Reset the generic IE buffer */
0068         priv->gen_ie_buf_len = 0;
0069     }
0070 
0071     /* return the length appended to the buffer */
0072     return ret_len;
0073 }
0074 
0075 /*
0076  * Append TSF tracking info from the scan table for the target AP.
0077  *
0078  * This function is called from the network join command preparation routine.
0079  *
0080  * The TSF table TSF sent to the firmware contains two TSF values:
0081  *      - The TSF of the target AP from its previous beacon/probe response
0082  *      - The TSF timestamp of our local MAC at the time we observed the
0083  *        beacon/probe response.
0084  *
0085  * The firmware uses the timestamp values to set an initial TSF value
0086  * in the MAC for the new association after a reassociation attempt.
0087  */
0088 static int
0089 mwifiex_cmd_append_tsf_tlv(struct mwifiex_private *priv, u8 **buffer,
0090                struct mwifiex_bssdescriptor *bss_desc)
0091 {
0092     struct mwifiex_ie_types_tsf_timestamp tsf_tlv;
0093     __le64 tsf_val;
0094 
0095     /* Null Checks */
0096     if (buffer == NULL)
0097         return 0;
0098     if (*buffer == NULL)
0099         return 0;
0100 
0101     memset(&tsf_tlv, 0x00, sizeof(struct mwifiex_ie_types_tsf_timestamp));
0102 
0103     tsf_tlv.header.type = cpu_to_le16(TLV_TYPE_TSFTIMESTAMP);
0104     tsf_tlv.header.len = cpu_to_le16(2 * sizeof(tsf_val));
0105 
0106     memcpy(*buffer, &tsf_tlv, sizeof(tsf_tlv.header));
0107     *buffer += sizeof(tsf_tlv.header);
0108 
0109     /* TSF at the time when beacon/probe_response was received */
0110     tsf_val = cpu_to_le64(bss_desc->fw_tsf);
0111     memcpy(*buffer, &tsf_val, sizeof(tsf_val));
0112     *buffer += sizeof(tsf_val);
0113 
0114     tsf_val = cpu_to_le64(bss_desc->timestamp);
0115 
0116     mwifiex_dbg(priv->adapter, INFO,
0117             "info: %s: TSF offset calc: %016llx - %016llx\n",
0118             __func__, bss_desc->timestamp, bss_desc->fw_tsf);
0119 
0120     memcpy(*buffer, &tsf_val, sizeof(tsf_val));
0121     *buffer += sizeof(tsf_val);
0122 
0123     return sizeof(tsf_tlv.header) + (2 * sizeof(tsf_val));
0124 }
0125 
0126 /*
0127  * This function finds out the common rates between rate1 and rate2.
0128  *
0129  * It will fill common rates in rate1 as output if found.
0130  *
0131  * NOTE: Setting the MSB of the basic rates needs to be taken
0132  * care of, either before or after calling this function.
0133  */
0134 static int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1,
0135                     u32 rate1_size, u8 *rate2, u32 rate2_size)
0136 {
0137     int ret;
0138     u8 *ptr = rate1, *tmp;
0139     u32 i, j;
0140 
0141     tmp = kmemdup(rate1, rate1_size, GFP_KERNEL);
0142     if (!tmp) {
0143         mwifiex_dbg(priv->adapter, ERROR, "failed to alloc tmp buf\n");
0144         return -ENOMEM;
0145     }
0146 
0147     memset(rate1, 0, rate1_size);
0148 
0149     for (i = 0; i < rate2_size && rate2[i]; i++) {
0150         for (j = 0; j < rate1_size && tmp[j]; j++) {
0151             /* Check common rate, excluding the bit for
0152                basic rate */
0153             if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) {
0154                 *rate1++ = tmp[j];
0155                 break;
0156             }
0157         }
0158     }
0159 
0160     mwifiex_dbg(priv->adapter, INFO, "info: Tx data rate set to %#x\n",
0161             priv->data_rate);
0162 
0163     if (!priv->is_data_rate_auto) {
0164         while (*ptr) {
0165             if ((*ptr & 0x7f) == priv->data_rate) {
0166                 ret = 0;
0167                 goto done;
0168             }
0169             ptr++;
0170         }
0171         mwifiex_dbg(priv->adapter, ERROR,
0172                 "previously set fixed data rate %#x\t"
0173                 "is not compatible with the network\n",
0174                 priv->data_rate);
0175 
0176         ret = -1;
0177         goto done;
0178     }
0179 
0180     ret = 0;
0181 done:
0182     kfree(tmp);
0183     return ret;
0184 }
0185 
0186 /*
0187  * This function creates the intersection of the rates supported by a
0188  * target BSS and our adapter settings for use in an assoc/join command.
0189  */
0190 static int
0191 mwifiex_setup_rates_from_bssdesc(struct mwifiex_private *priv,
0192                  struct mwifiex_bssdescriptor *bss_desc,
0193                  u8 *out_rates, u32 *out_rates_size)
0194 {
0195     u8 card_rates[MWIFIEX_SUPPORTED_RATES];
0196     u32 card_rates_size;
0197 
0198     /* Copy AP supported rates */
0199     memcpy(out_rates, bss_desc->supported_rates, MWIFIEX_SUPPORTED_RATES);
0200     /* Get the STA supported rates */
0201     card_rates_size = mwifiex_get_active_data_rates(priv, card_rates);
0202     /* Get the common rates between AP and STA supported rates */
0203     if (mwifiex_get_common_rates(priv, out_rates, MWIFIEX_SUPPORTED_RATES,
0204                      card_rates, card_rates_size)) {
0205         *out_rates_size = 0;
0206         mwifiex_dbg(priv->adapter, ERROR,
0207                 "%s: cannot get common rates\n",
0208                 __func__);
0209         return -1;
0210     }
0211 
0212     *out_rates_size =
0213         min_t(size_t, strlen(out_rates), MWIFIEX_SUPPORTED_RATES);
0214 
0215     return 0;
0216 }
0217 
0218 /*
0219  * This function appends a WPS IE. It is called from the network join command
0220  * preparation routine.
0221  *
0222  * If the IE buffer has been setup by the application, this routine appends
0223  * the buffer as a WPS TLV type to the request.
0224  */
0225 static int
0226 mwifiex_cmd_append_wps_ie(struct mwifiex_private *priv, u8 **buffer)
0227 {
0228     int retLen = 0;
0229     struct mwifiex_ie_types_header ie_header;
0230 
0231     if (!buffer || !*buffer)
0232         return 0;
0233 
0234     /*
0235      * If there is a wps ie buffer setup, append it to the return
0236      * parameter buffer pointer.
0237      */
0238     if (priv->wps_ie_len) {
0239         mwifiex_dbg(priv->adapter, CMD,
0240                 "cmd: append wps ie %d to %p\n",
0241                 priv->wps_ie_len, *buffer);
0242 
0243         /* Wrap the generic IE buffer with a pass through TLV type */
0244         ie_header.type = cpu_to_le16(TLV_TYPE_PASSTHROUGH);
0245         ie_header.len = cpu_to_le16(priv->wps_ie_len);
0246         memcpy(*buffer, &ie_header, sizeof(ie_header));
0247         *buffer += sizeof(ie_header);
0248         retLen += sizeof(ie_header);
0249 
0250         memcpy(*buffer, priv->wps_ie, priv->wps_ie_len);
0251         *buffer += priv->wps_ie_len;
0252         retLen += priv->wps_ie_len;
0253 
0254     }
0255 
0256     kfree(priv->wps_ie);
0257     priv->wps_ie_len = 0;
0258     return retLen;
0259 }
0260 
0261 /*
0262  * This function appends a WAPI IE.
0263  *
0264  * This function is called from the network join command preparation routine.
0265  *
0266  * If the IE buffer has been setup by the application, this routine appends
0267  * the buffer as a WAPI TLV type to the request.
0268  */
0269 static int
0270 mwifiex_cmd_append_wapi_ie(struct mwifiex_private *priv, u8 **buffer)
0271 {
0272     int retLen = 0;
0273     struct mwifiex_ie_types_header ie_header;
0274 
0275     /* Null Checks */
0276     if (buffer == NULL)
0277         return 0;
0278     if (*buffer == NULL)
0279         return 0;
0280 
0281     /*
0282      * If there is a wapi ie buffer setup, append it to the return
0283      *   parameter buffer pointer.
0284      */
0285     if (priv->wapi_ie_len) {
0286         mwifiex_dbg(priv->adapter, CMD,
0287                 "cmd: append wapi ie %d to %p\n",
0288                 priv->wapi_ie_len, *buffer);
0289 
0290         /* Wrap the generic IE buffer with a pass through TLV type */
0291         ie_header.type = cpu_to_le16(TLV_TYPE_WAPI_IE);
0292         ie_header.len = cpu_to_le16(priv->wapi_ie_len);
0293         memcpy(*buffer, &ie_header, sizeof(ie_header));
0294 
0295         /* Increment the return size and the return buffer pointer
0296            param */
0297         *buffer += sizeof(ie_header);
0298         retLen += sizeof(ie_header);
0299 
0300         /* Copy the wapi IE buffer to the output buffer, advance
0301            pointer */
0302         memcpy(*buffer, priv->wapi_ie, priv->wapi_ie_len);
0303 
0304         /* Increment the return size and the return buffer pointer
0305            param */
0306         *buffer += priv->wapi_ie_len;
0307         retLen += priv->wapi_ie_len;
0308 
0309     }
0310     /* return the length appended to the buffer */
0311     return retLen;
0312 }
0313 
0314 /*
0315  * This function appends rsn ie tlv for wpa/wpa2 security modes.
0316  * It is called from the network join command preparation routine.
0317  */
0318 static int mwifiex_append_rsn_ie_wpa_wpa2(struct mwifiex_private *priv,
0319                       u8 **buffer)
0320 {
0321     struct mwifiex_ie_types_rsn_param_set *rsn_ie_tlv;
0322     int rsn_ie_len;
0323 
0324     if (!buffer || !(*buffer))
0325         return 0;
0326 
0327     rsn_ie_tlv = (struct mwifiex_ie_types_rsn_param_set *) (*buffer);
0328     rsn_ie_tlv->header.type = cpu_to_le16((u16) priv->wpa_ie[0]);
0329     rsn_ie_tlv->header.type = cpu_to_le16(
0330                  le16_to_cpu(rsn_ie_tlv->header.type) & 0x00FF);
0331     rsn_ie_tlv->header.len = cpu_to_le16((u16) priv->wpa_ie[1]);
0332     rsn_ie_tlv->header.len = cpu_to_le16(le16_to_cpu(rsn_ie_tlv->header.len)
0333                              & 0x00FF);
0334     if (le16_to_cpu(rsn_ie_tlv->header.len) <= (sizeof(priv->wpa_ie) - 2))
0335         memcpy(rsn_ie_tlv->rsn_ie, &priv->wpa_ie[2],
0336                le16_to_cpu(rsn_ie_tlv->header.len));
0337     else
0338         return -1;
0339 
0340     rsn_ie_len = sizeof(rsn_ie_tlv->header) +
0341                     le16_to_cpu(rsn_ie_tlv->header.len);
0342     *buffer += rsn_ie_len;
0343 
0344     return rsn_ie_len;
0345 }
0346 
0347 /*
0348  * This function prepares command for association.
0349  *
0350  * This sets the following parameters -
0351  *      - Peer MAC address
0352  *      - Listen interval
0353  *      - Beacon interval
0354  *      - Capability information
0355  *
0356  * ...and the following TLVs, as required -
0357  *      - SSID TLV
0358  *      - PHY TLV
0359  *      - SS TLV
0360  *      - Rates TLV
0361  *      - Authentication TLV
0362  *      - Channel TLV
0363  *      - WPA/WPA2 IE
0364  *      - 11n TLV
0365  *      - Vendor specific TLV
0366  *      - WMM TLV
0367  *      - WAPI IE
0368  *      - Generic IE
0369  *      - TSF TLV
0370  *
0371  * Preparation also includes -
0372  *      - Setting command ID and proper size
0373  *      - Ensuring correct endian-ness
0374  */
0375 int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv,
0376                  struct host_cmd_ds_command *cmd,
0377                  struct mwifiex_bssdescriptor *bss_desc)
0378 {
0379     struct host_cmd_ds_802_11_associate *assoc = &cmd->params.associate;
0380     struct mwifiex_ie_types_ssid_param_set *ssid_tlv;
0381     struct mwifiex_ie_types_phy_param_set *phy_tlv;
0382     struct mwifiex_ie_types_ss_param_set *ss_tlv;
0383     struct mwifiex_ie_types_rates_param_set *rates_tlv;
0384     struct mwifiex_ie_types_auth_type *auth_tlv;
0385     struct mwifiex_ie_types_chan_list_param_set *chan_tlv;
0386     u8 rates[MWIFIEX_SUPPORTED_RATES];
0387     u32 rates_size;
0388     u16 tmp_cap;
0389     u8 *pos;
0390     int rsn_ie_len = 0;
0391 
0392     pos = (u8 *) assoc;
0393 
0394     cmd->command = cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE);
0395 
0396     /* Save so we know which BSS Desc to use in the response handler */
0397     priv->attempted_bss_desc = bss_desc;
0398 
0399     memcpy(assoc->peer_sta_addr,
0400            bss_desc->mac_address, sizeof(assoc->peer_sta_addr));
0401     pos += sizeof(assoc->peer_sta_addr);
0402 
0403     /* Set the listen interval */
0404     assoc->listen_interval = cpu_to_le16(priv->listen_interval);
0405     /* Set the beacon period */
0406     assoc->beacon_period = cpu_to_le16(bss_desc->beacon_period);
0407 
0408     pos += sizeof(assoc->cap_info_bitmap);
0409     pos += sizeof(assoc->listen_interval);
0410     pos += sizeof(assoc->beacon_period);
0411     pos += sizeof(assoc->dtim_period);
0412 
0413     ssid_tlv = (struct mwifiex_ie_types_ssid_param_set *) pos;
0414     ssid_tlv->header.type = cpu_to_le16(WLAN_EID_SSID);
0415     ssid_tlv->header.len = cpu_to_le16((u16) bss_desc->ssid.ssid_len);
0416     memcpy(ssid_tlv->ssid, bss_desc->ssid.ssid,
0417            le16_to_cpu(ssid_tlv->header.len));
0418     pos += sizeof(ssid_tlv->header) + le16_to_cpu(ssid_tlv->header.len);
0419 
0420     phy_tlv = (struct mwifiex_ie_types_phy_param_set *) pos;
0421     phy_tlv->header.type = cpu_to_le16(WLAN_EID_DS_PARAMS);
0422     phy_tlv->header.len = cpu_to_le16(sizeof(phy_tlv->fh_ds.ds_param_set));
0423     memcpy(&phy_tlv->fh_ds.ds_param_set,
0424            &bss_desc->phy_param_set.ds_param_set.current_chan,
0425            sizeof(phy_tlv->fh_ds.ds_param_set));
0426     pos += sizeof(phy_tlv->header) + le16_to_cpu(phy_tlv->header.len);
0427 
0428     ss_tlv = (struct mwifiex_ie_types_ss_param_set *) pos;
0429     ss_tlv->header.type = cpu_to_le16(WLAN_EID_CF_PARAMS);
0430     ss_tlv->header.len = cpu_to_le16(sizeof(ss_tlv->cf_ibss.cf_param_set));
0431     pos += sizeof(ss_tlv->header) + le16_to_cpu(ss_tlv->header.len);
0432 
0433     /* Get the common rates supported between the driver and the BSS Desc */
0434     if (mwifiex_setup_rates_from_bssdesc
0435         (priv, bss_desc, rates, &rates_size))
0436         return -1;
0437 
0438     /* Save the data rates into Current BSS state structure */
0439     priv->curr_bss_params.num_of_rates = rates_size;
0440     memcpy(&priv->curr_bss_params.data_rates, rates, rates_size);
0441 
0442     /* Setup the Rates TLV in the association command */
0443     rates_tlv = (struct mwifiex_ie_types_rates_param_set *) pos;
0444     rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES);
0445     rates_tlv->header.len = cpu_to_le16((u16) rates_size);
0446     memcpy(rates_tlv->rates, rates, rates_size);
0447     pos += sizeof(rates_tlv->header) + rates_size;
0448     mwifiex_dbg(priv->adapter, INFO, "info: ASSOC_CMD: rates size = %d\n",
0449             rates_size);
0450 
0451     /* Add the Authentication type to be used for Auth frames */
0452     auth_tlv = (struct mwifiex_ie_types_auth_type *) pos;
0453     auth_tlv->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
0454     auth_tlv->header.len = cpu_to_le16(sizeof(auth_tlv->auth_type));
0455     if (priv->sec_info.wep_enabled)
0456         auth_tlv->auth_type = cpu_to_le16(
0457                 (u16) priv->sec_info.authentication_mode);
0458     else
0459         auth_tlv->auth_type = cpu_to_le16(NL80211_AUTHTYPE_OPEN_SYSTEM);
0460 
0461     pos += sizeof(auth_tlv->header) + le16_to_cpu(auth_tlv->header.len);
0462 
0463     if (IS_SUPPORT_MULTI_BANDS(priv->adapter) &&
0464         !(ISSUPP_11NENABLED(priv->adapter->fw_cap_info) &&
0465         (!bss_desc->disable_11n) &&
0466         (priv->adapter->config_bands & BAND_GN ||
0467          priv->adapter->config_bands & BAND_AN) &&
0468         (bss_desc->bcn_ht_cap)
0469         )
0470         ) {
0471         /* Append a channel TLV for the channel the attempted AP was
0472            found on */
0473         chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos;
0474         chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
0475         chan_tlv->header.len =
0476             cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set));
0477 
0478         memset(chan_tlv->chan_scan_param, 0x00,
0479                sizeof(struct mwifiex_chan_scan_param_set));
0480         chan_tlv->chan_scan_param[0].chan_number =
0481             (bss_desc->phy_param_set.ds_param_set.current_chan);
0482         mwifiex_dbg(priv->adapter, INFO, "info: Assoc: TLV Chan = %d\n",
0483                 chan_tlv->chan_scan_param[0].chan_number);
0484 
0485         chan_tlv->chan_scan_param[0].radio_type =
0486             mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
0487 
0488         mwifiex_dbg(priv->adapter, INFO, "info: Assoc: TLV Band = %d\n",
0489                 chan_tlv->chan_scan_param[0].radio_type);
0490         pos += sizeof(chan_tlv->header) +
0491             sizeof(struct mwifiex_chan_scan_param_set);
0492     }
0493 
0494     if (!priv->wps.session_enable) {
0495         if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled)
0496             rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos);
0497 
0498         if (rsn_ie_len == -1)
0499             return -1;
0500     }
0501 
0502     if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info) &&
0503         (!bss_desc->disable_11n) &&
0504         (priv->adapter->config_bands & BAND_GN ||
0505          priv->adapter->config_bands & BAND_AN))
0506         mwifiex_cmd_append_11n_tlv(priv, bss_desc, &pos);
0507 
0508     if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) &&
0509         !bss_desc->disable_11n && !bss_desc->disable_11ac &&
0510         priv->adapter->config_bands & BAND_AAC)
0511         mwifiex_cmd_append_11ac_tlv(priv, bss_desc, &pos);
0512 
0513     /* Append vendor specific IE TLV */
0514     mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_ASSOC, &pos);
0515 
0516     mwifiex_wmm_process_association_req(priv, &pos, &bss_desc->wmm_ie,
0517                         bss_desc->bcn_ht_cap);
0518     if (priv->sec_info.wapi_enabled && priv->wapi_ie_len)
0519         mwifiex_cmd_append_wapi_ie(priv, &pos);
0520 
0521     if (priv->wps.session_enable && priv->wps_ie_len)
0522         mwifiex_cmd_append_wps_ie(priv, &pos);
0523 
0524     mwifiex_cmd_append_generic_ie(priv, &pos);
0525 
0526     mwifiex_cmd_append_tsf_tlv(priv, &pos, bss_desc);
0527 
0528     mwifiex_11h_process_join(priv, &pos, bss_desc);
0529 
0530     cmd->size = cpu_to_le16((u16) (pos - (u8 *) assoc) + S_DS_GEN);
0531 
0532     /* Set the Capability info at last */
0533     tmp_cap = bss_desc->cap_info_bitmap;
0534 
0535     if (priv->adapter->config_bands == BAND_B)
0536         tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME;
0537 
0538     tmp_cap &= CAPINFO_MASK;
0539     mwifiex_dbg(priv->adapter, INFO,
0540             "info: ASSOC_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n",
0541             tmp_cap, CAPINFO_MASK);
0542     assoc->cap_info_bitmap = cpu_to_le16(tmp_cap);
0543 
0544     return 0;
0545 }
0546 
0547 static const char *assoc_failure_reason_to_str(u16 cap_info)
0548 {
0549     switch (cap_info) {
0550     case CONNECT_ERR_AUTH_ERR_STA_FAILURE:
0551         return "CONNECT_ERR_AUTH_ERR_STA_FAILURE";
0552     case CONNECT_ERR_AUTH_MSG_UNHANDLED:
0553         return "CONNECT_ERR_AUTH_MSG_UNHANDLED";
0554     case CONNECT_ERR_ASSOC_ERR_TIMEOUT:
0555         return "CONNECT_ERR_ASSOC_ERR_TIMEOUT";
0556     case CONNECT_ERR_ASSOC_ERR_AUTH_REFUSED:
0557         return "CONNECT_ERR_ASSOC_ERR_AUTH_REFUSED";
0558     case CONNECT_ERR_STA_FAILURE:
0559         return "CONNECT_ERR_STA_FAILURE";
0560     }
0561 
0562     return "Unknown connect failure";
0563 }
0564 /*
0565  * Association firmware command response handler
0566  *
0567  * The response buffer for the association command has the following
0568  * memory layout.
0569  *
0570  * For cases where an association response was not received (indicated
0571  * by the CapInfo and AId field):
0572  *
0573  *     .------------------------------------------------------------.
0574  *     |  Header(4 * sizeof(t_u16)):  Standard command response hdr |
0575  *     .------------------------------------------------------------.
0576  *     |  cap_info/Error Return(t_u16):                             |
0577  *     |           0xFFFF(-1): Internal error                       |
0578  *     |           0xFFFE(-2): Authentication unhandled message     |
0579  *     |           0xFFFD(-3): Authentication refused               |
0580  *     |           0xFFFC(-4): Timeout waiting for AP response      |
0581  *     .------------------------------------------------------------.
0582  *     |  status_code(t_u16):                                       |
0583  *     |        If cap_info is -1:                                  |
0584  *     |           An internal firmware failure prevented the       |
0585  *     |           command from being processed.  The status_code   |
0586  *     |           will be set to 1.                                |
0587  *     |                                                            |
0588  *     |        If cap_info is -2:                                  |
0589  *     |           An authentication frame was received but was     |
0590  *     |           not handled by the firmware.  IEEE Status        |
0591  *     |           code for the failure is returned.                |
0592  *     |                                                            |
0593  *     |        If cap_info is -3:                                  |
0594  *     |           An authentication frame was received and the     |
0595  *     |           status_code is the IEEE Status reported in the   |
0596  *     |           response.                                        |
0597  *     |                                                            |
0598  *     |        If cap_info is -4:                                  |
0599  *     |           (1) Association response timeout                 |
0600  *     |           (2) Authentication response timeout              |
0601  *     .------------------------------------------------------------.
0602  *     |  a_id(t_u16): 0xFFFF                                       |
0603  *     .------------------------------------------------------------.
0604  *
0605  *
0606  * For cases where an association response was received, the IEEE
0607  * standard association response frame is returned:
0608  *
0609  *     .------------------------------------------------------------.
0610  *     |  Header(4 * sizeof(t_u16)):  Standard command response hdr |
0611  *     .------------------------------------------------------------.
0612  *     |  cap_info(t_u16): IEEE Capability                          |
0613  *     .------------------------------------------------------------.
0614  *     |  status_code(t_u16): IEEE Status Code                      |
0615  *     .------------------------------------------------------------.
0616  *     |  a_id(t_u16): IEEE Association ID                          |
0617  *     .------------------------------------------------------------.
0618  *     |  IEEE IEs(variable): Any received IEs comprising the       |
0619  *     |                      remaining portion of a received       |
0620  *     |                      association response frame.           |
0621  *     .------------------------------------------------------------.
0622  *
0623  * For simplistic handling, the status_code field can be used to determine
0624  * an association success (0) or failure (non-zero).
0625  */
0626 int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
0627                  struct host_cmd_ds_command *resp)
0628 {
0629     struct mwifiex_adapter *adapter = priv->adapter;
0630     int ret = 0;
0631     struct ieee_types_assoc_rsp *assoc_rsp;
0632     struct mwifiex_bssdescriptor *bss_desc;
0633     bool enable_data = true;
0634     u16 cap_info, status_code, aid;
0635     const u8 *ie_ptr;
0636     struct ieee80211_ht_operation *assoc_resp_ht_oper;
0637 
0638     if (!priv->attempted_bss_desc) {
0639         mwifiex_dbg(priv->adapter, ERROR,
0640                 "ASSOC_RESP: failed, association terminated by host\n");
0641         goto done;
0642     }
0643 
0644     assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params;
0645 
0646     cap_info = le16_to_cpu(assoc_rsp->cap_info_bitmap);
0647     status_code = le16_to_cpu(assoc_rsp->status_code);
0648     aid = le16_to_cpu(assoc_rsp->a_id);
0649 
0650     if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
0651         dev_err(priv->adapter->dev,
0652             "invalid AID value 0x%x; bits 15:14 not set\n",
0653             aid);
0654 
0655     aid &= ~(BIT(15) | BIT(14));
0656 
0657     priv->assoc_rsp_size = min(le16_to_cpu(resp->size) - S_DS_GEN,
0658                    sizeof(priv->assoc_rsp_buf));
0659 
0660     assoc_rsp->a_id = cpu_to_le16(aid);
0661     memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size);
0662 
0663     if (status_code) {
0664         priv->adapter->dbg.num_cmd_assoc_failure++;
0665         mwifiex_dbg(priv->adapter, ERROR,
0666                 "ASSOC_RESP: failed,\t"
0667                 "status code=%d err=%#x a_id=%#x\n",
0668                 status_code, cap_info,
0669                 le16_to_cpu(assoc_rsp->a_id));
0670 
0671         mwifiex_dbg(priv->adapter, ERROR, "assoc failure: reason %s\n",
0672                 assoc_failure_reason_to_str(cap_info));
0673         if (cap_info == CONNECT_ERR_ASSOC_ERR_TIMEOUT) {
0674             if (status_code == MWIFIEX_ASSOC_CMD_FAILURE_AUTH) {
0675                 ret = WLAN_STATUS_AUTH_TIMEOUT;
0676                 mwifiex_dbg(priv->adapter, ERROR,
0677                         "ASSOC_RESP: AUTH timeout\n");
0678             } else {
0679                 ret = WLAN_STATUS_UNSPECIFIED_FAILURE;
0680                 mwifiex_dbg(priv->adapter, ERROR,
0681                         "ASSOC_RESP: UNSPECIFIED failure\n");
0682             }
0683         } else {
0684             ret = status_code;
0685         }
0686 
0687         goto done;
0688     }
0689 
0690     /* Send a Media Connected event, according to the Spec */
0691     priv->media_connected = true;
0692 
0693     priv->adapter->ps_state = PS_STATE_AWAKE;
0694     priv->adapter->pps_uapsd_mode = false;
0695     priv->adapter->tx_lock_flag = false;
0696 
0697     /* Set the attempted BSSID Index to current */
0698     bss_desc = priv->attempted_bss_desc;
0699 
0700     mwifiex_dbg(priv->adapter, INFO, "info: ASSOC_RESP: %s\n",
0701             bss_desc->ssid.ssid);
0702 
0703     /* Make a copy of current BSSID descriptor */
0704     memcpy(&priv->curr_bss_params.bss_descriptor,
0705            bss_desc, sizeof(struct mwifiex_bssdescriptor));
0706 
0707     /* Update curr_bss_params */
0708     priv->curr_bss_params.bss_descriptor.channel
0709         = bss_desc->phy_param_set.ds_param_set.current_chan;
0710 
0711     priv->curr_bss_params.band = (u8) bss_desc->bss_band;
0712 
0713     if (bss_desc->wmm_ie.vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC)
0714         priv->curr_bss_params.wmm_enabled = true;
0715     else
0716         priv->curr_bss_params.wmm_enabled = false;
0717 
0718     if ((priv->wmm_required || bss_desc->bcn_ht_cap) &&
0719         priv->curr_bss_params.wmm_enabled)
0720         priv->wmm_enabled = true;
0721     else
0722         priv->wmm_enabled = false;
0723 
0724     priv->curr_bss_params.wmm_uapsd_enabled = false;
0725 
0726     if (priv->wmm_enabled)
0727         priv->curr_bss_params.wmm_uapsd_enabled
0728             = ((bss_desc->wmm_ie.qos_info_bitmap &
0729                 IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) ? 1 : 0);
0730 
0731     /* Store the bandwidth information from assoc response */
0732     ie_ptr = cfg80211_find_ie(WLAN_EID_HT_OPERATION, assoc_rsp->ie_buffer,
0733                   priv->assoc_rsp_size
0734                   - sizeof(struct ieee_types_assoc_rsp));
0735     if (ie_ptr) {
0736         assoc_resp_ht_oper = (struct ieee80211_ht_operation *)(ie_ptr
0737                     + sizeof(struct ieee_types_header));
0738         priv->assoc_resp_ht_param = assoc_resp_ht_oper->ht_param;
0739         priv->ht_param_present = true;
0740     } else {
0741         priv->ht_param_present = false;
0742     }
0743 
0744     mwifiex_dbg(priv->adapter, INFO,
0745             "info: ASSOC_RESP: curr_pkt_filter is %#x\n",
0746             priv->curr_pkt_filter);
0747     if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled)
0748         priv->wpa_is_gtk_set = false;
0749 
0750     if (priv->wmm_enabled) {
0751         /* Don't re-enable carrier until we get the WMM_GET_STATUS
0752            event */
0753         enable_data = false;
0754     } else {
0755         /* Since WMM is not enabled, setup the queues with the
0756            defaults */
0757         mwifiex_wmm_setup_queue_priorities(priv, NULL);
0758         mwifiex_wmm_setup_ac_downgrade(priv);
0759     }
0760 
0761     if (enable_data)
0762         mwifiex_dbg(priv->adapter, INFO,
0763                 "info: post association, re-enabling data flow\n");
0764 
0765     /* Reset SNR/NF/RSSI values */
0766     priv->data_rssi_last = 0;
0767     priv->data_nf_last = 0;
0768     priv->data_rssi_avg = 0;
0769     priv->data_nf_avg = 0;
0770     priv->bcn_rssi_last = 0;
0771     priv->bcn_nf_last = 0;
0772     priv->bcn_rssi_avg = 0;
0773     priv->bcn_nf_avg = 0;
0774     priv->rxpd_rate = 0;
0775     priv->rxpd_htinfo = 0;
0776 
0777     mwifiex_save_curr_bcn(priv);
0778 
0779     priv->adapter->dbg.num_cmd_assoc_success++;
0780 
0781     mwifiex_dbg(priv->adapter, INFO, "info: ASSOC_RESP: associated\n");
0782 
0783     /* Add the ra_list here for infra mode as there will be only 1 ra
0784        always */
0785     mwifiex_ralist_add(priv,
0786                priv->curr_bss_params.bss_descriptor.mac_address);
0787 
0788     if (!netif_carrier_ok(priv->netdev))
0789         netif_carrier_on(priv->netdev);
0790     mwifiex_wake_up_net_dev_queue(priv->netdev, adapter);
0791 
0792     if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled)
0793         priv->scan_block = true;
0794     else
0795         priv->port_open = true;
0796 
0797 done:
0798     /* Need to indicate IOCTL complete */
0799     if (adapter->curr_cmd->wait_q_enabled) {
0800         if (ret)
0801             adapter->cmd_wait_q.status = -1;
0802         else
0803             adapter->cmd_wait_q.status = 0;
0804     }
0805 
0806     return ret;
0807 }
0808 
0809 /*
0810  * This function prepares command for ad-hoc start.
0811  *
0812  * Driver will fill up SSID, BSS mode, IBSS parameters, physical
0813  * parameters, probe delay, and capability information. Firmware
0814  * will fill up beacon period, basic rates and operational rates.
0815  *
0816  * In addition, the following TLVs are added -
0817  *      - Channel TLV
0818  *      - Vendor specific IE
0819  *      - WPA/WPA2 IE
0820  *      - HT Capabilities IE
0821  *      - HT Information IE
0822  *
0823  * Preparation also includes -
0824  *      - Setting command ID and proper size
0825  *      - Ensuring correct endian-ness
0826  */
0827 int
0828 mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
0829                 struct host_cmd_ds_command *cmd,
0830                 struct cfg80211_ssid *req_ssid)
0831 {
0832     int rsn_ie_len = 0;
0833     struct mwifiex_adapter *adapter = priv->adapter;
0834     struct host_cmd_ds_802_11_ad_hoc_start *adhoc_start =
0835         &cmd->params.adhoc_start;
0836     struct mwifiex_bssdescriptor *bss_desc;
0837     u32 cmd_append_size = 0;
0838     u32 i;
0839     u16 tmp_cap;
0840     struct mwifiex_ie_types_chan_list_param_set *chan_tlv;
0841     u8 radio_type;
0842 
0843     struct mwifiex_ie_types_htcap *ht_cap;
0844     struct mwifiex_ie_types_htinfo *ht_info;
0845     u8 *pos = (u8 *) adhoc_start +
0846             sizeof(struct host_cmd_ds_802_11_ad_hoc_start);
0847 
0848     if (!adapter)
0849         return -1;
0850 
0851     cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_START);
0852 
0853     bss_desc = &priv->curr_bss_params.bss_descriptor;
0854     priv->attempted_bss_desc = bss_desc;
0855 
0856     /*
0857      * Fill in the parameters for 2 data structures:
0858      *   1. struct host_cmd_ds_802_11_ad_hoc_start command
0859      *   2. bss_desc
0860      * Driver will fill up SSID, bss_mode,IBSS param, Physical Param,
0861      * probe delay, and Cap info.
0862      * Firmware will fill up beacon period, Basic rates
0863      * and operational rates.
0864      */
0865 
0866     memset(adhoc_start->ssid, 0, IEEE80211_MAX_SSID_LEN);
0867 
0868     if (req_ssid->ssid_len > IEEE80211_MAX_SSID_LEN)
0869         req_ssid->ssid_len = IEEE80211_MAX_SSID_LEN;
0870     memcpy(adhoc_start->ssid, req_ssid->ssid, req_ssid->ssid_len);
0871 
0872     mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: SSID = %s\n",
0873             adhoc_start->ssid);
0874 
0875     memset(bss_desc->ssid.ssid, 0, IEEE80211_MAX_SSID_LEN);
0876     memcpy(bss_desc->ssid.ssid, req_ssid->ssid, req_ssid->ssid_len);
0877 
0878     bss_desc->ssid.ssid_len = req_ssid->ssid_len;
0879 
0880     /* Set the BSS mode */
0881     adhoc_start->bss_mode = HostCmd_BSS_MODE_IBSS;
0882     bss_desc->bss_mode = NL80211_IFTYPE_ADHOC;
0883     adhoc_start->beacon_period = cpu_to_le16(priv->beacon_period);
0884     bss_desc->beacon_period = priv->beacon_period;
0885 
0886     /* Set Physical param set */
0887 /* Parameter IE Id */
0888 #define DS_PARA_IE_ID   3
0889 /* Parameter IE length */
0890 #define DS_PARA_IE_LEN  1
0891 
0892     adhoc_start->phy_param_set.ds_param_set.element_id = DS_PARA_IE_ID;
0893     adhoc_start->phy_param_set.ds_param_set.len = DS_PARA_IE_LEN;
0894 
0895     if (!mwifiex_get_cfp(priv, adapter->adhoc_start_band,
0896                  (u16) priv->adhoc_channel, 0)) {
0897         struct mwifiex_chan_freq_power *cfp;
0898         cfp = mwifiex_get_cfp(priv, adapter->adhoc_start_band,
0899                       FIRST_VALID_CHANNEL, 0);
0900         if (cfp)
0901             priv->adhoc_channel = (u8) cfp->channel;
0902     }
0903 
0904     if (!priv->adhoc_channel) {
0905         mwifiex_dbg(adapter, ERROR,
0906                 "ADHOC_S_CMD: adhoc_channel cannot be 0\n");
0907         return -1;
0908     }
0909 
0910     mwifiex_dbg(adapter, INFO,
0911             "info: ADHOC_S_CMD: creating ADHOC on channel %d\n",
0912             priv->adhoc_channel);
0913 
0914     priv->curr_bss_params.bss_descriptor.channel = priv->adhoc_channel;
0915     priv->curr_bss_params.band = adapter->adhoc_start_band;
0916 
0917     bss_desc->channel = priv->adhoc_channel;
0918     adhoc_start->phy_param_set.ds_param_set.current_chan =
0919         priv->adhoc_channel;
0920 
0921     memcpy(&bss_desc->phy_param_set, &adhoc_start->phy_param_set,
0922            sizeof(union ieee_types_phy_param_set));
0923 
0924     /* Set IBSS param set */
0925 /* IBSS parameter IE Id */
0926 #define IBSS_PARA_IE_ID   6
0927 /* IBSS parameter IE length */
0928 #define IBSS_PARA_IE_LEN  2
0929 
0930     adhoc_start->ss_param_set.ibss_param_set.element_id = IBSS_PARA_IE_ID;
0931     adhoc_start->ss_param_set.ibss_param_set.len = IBSS_PARA_IE_LEN;
0932     adhoc_start->ss_param_set.ibss_param_set.atim_window
0933                     = cpu_to_le16(priv->atim_window);
0934     memcpy(&bss_desc->ss_param_set, &adhoc_start->ss_param_set,
0935            sizeof(union ieee_types_ss_param_set));
0936 
0937     /* Set Capability info */
0938     bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_IBSS;
0939     tmp_cap = WLAN_CAPABILITY_IBSS;
0940 
0941     /* Set up privacy in bss_desc */
0942     if (priv->sec_info.encryption_mode) {
0943         /* Ad-Hoc capability privacy on */
0944         mwifiex_dbg(adapter, INFO,
0945                 "info: ADHOC_S_CMD: wep_status set privacy to WEP\n");
0946         bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
0947         tmp_cap |= WLAN_CAPABILITY_PRIVACY;
0948     } else {
0949         mwifiex_dbg(adapter, INFO,
0950                 "info: ADHOC_S_CMD: wep_status NOT set,\t"
0951                 "setting privacy to ACCEPT ALL\n");
0952         bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL;
0953     }
0954 
0955     memset(adhoc_start->data_rate, 0, sizeof(adhoc_start->data_rate));
0956     mwifiex_get_active_data_rates(priv, adhoc_start->data_rate);
0957     if ((adapter->adhoc_start_band & BAND_G) &&
0958         (priv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) {
0959         if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
0960                      HostCmd_ACT_GEN_SET, 0,
0961                      &priv->curr_pkt_filter, false)) {
0962             mwifiex_dbg(adapter, ERROR,
0963                     "ADHOC_S_CMD: G Protection config failed\n");
0964             return -1;
0965         }
0966     }
0967     /* Find the last non zero */
0968     for (i = 0; i < sizeof(adhoc_start->data_rate); i++)
0969         if (!adhoc_start->data_rate[i])
0970             break;
0971 
0972     priv->curr_bss_params.num_of_rates = i;
0973 
0974     /* Copy the ad-hoc creating rates into Current BSS rate structure */
0975     memcpy(&priv->curr_bss_params.data_rates,
0976            &adhoc_start->data_rate, priv->curr_bss_params.num_of_rates);
0977 
0978     mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: rates=%4ph\n",
0979             adhoc_start->data_rate);
0980 
0981     mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: AD-HOC Start command is ready\n");
0982 
0983     if (IS_SUPPORT_MULTI_BANDS(adapter)) {
0984         /* Append a channel TLV */
0985         chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos;
0986         chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
0987         chan_tlv->header.len =
0988             cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set));
0989 
0990         memset(chan_tlv->chan_scan_param, 0x00,
0991                sizeof(struct mwifiex_chan_scan_param_set));
0992         chan_tlv->chan_scan_param[0].chan_number =
0993             (u8) priv->curr_bss_params.bss_descriptor.channel;
0994 
0995         mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: TLV Chan = %d\n",
0996                 chan_tlv->chan_scan_param[0].chan_number);
0997 
0998         chan_tlv->chan_scan_param[0].radio_type
0999                = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
1000         if (adapter->adhoc_start_band & BAND_GN ||
1001             adapter->adhoc_start_band & BAND_AN) {
1002             if (adapter->sec_chan_offset ==
1003                         IEEE80211_HT_PARAM_CHA_SEC_ABOVE)
1004                 chan_tlv->chan_scan_param[0].radio_type |=
1005                     (IEEE80211_HT_PARAM_CHA_SEC_ABOVE << 4);
1006             else if (adapter->sec_chan_offset ==
1007                         IEEE80211_HT_PARAM_CHA_SEC_BELOW)
1008                 chan_tlv->chan_scan_param[0].radio_type |=
1009                     (IEEE80211_HT_PARAM_CHA_SEC_BELOW << 4);
1010         }
1011         mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: TLV Band = %d\n",
1012                 chan_tlv->chan_scan_param[0].radio_type);
1013         pos += sizeof(chan_tlv->header) +
1014             sizeof(struct mwifiex_chan_scan_param_set);
1015         cmd_append_size +=
1016             sizeof(chan_tlv->header) +
1017             sizeof(struct mwifiex_chan_scan_param_set);
1018     }
1019 
1020     /* Append vendor specific IE TLV */
1021     cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv,
1022                 MWIFIEX_VSIE_MASK_ADHOC, &pos);
1023 
1024     if (priv->sec_info.wpa_enabled) {
1025         rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos);
1026         if (rsn_ie_len == -1)
1027             return -1;
1028         cmd_append_size += rsn_ie_len;
1029     }
1030 
1031     if (adapter->adhoc_11n_enabled) {
1032         /* Fill HT CAPABILITY */
1033         ht_cap = (struct mwifiex_ie_types_htcap *) pos;
1034         memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap));
1035         ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY);
1036         ht_cap->header.len =
1037                cpu_to_le16(sizeof(struct ieee80211_ht_cap));
1038         radio_type = mwifiex_band_to_radio_type(
1039                     priv->adapter->config_bands);
1040         mwifiex_fill_cap_info(priv, radio_type, &ht_cap->ht_cap);
1041 
1042         if (adapter->sec_chan_offset ==
1043                     IEEE80211_HT_PARAM_CHA_SEC_NONE) {
1044             u16 tmp_ht_cap;
1045 
1046             tmp_ht_cap = le16_to_cpu(ht_cap->ht_cap.cap_info);
1047             tmp_ht_cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
1048             tmp_ht_cap &= ~IEEE80211_HT_CAP_SGI_40;
1049             ht_cap->ht_cap.cap_info = cpu_to_le16(tmp_ht_cap);
1050         }
1051 
1052         pos += sizeof(struct mwifiex_ie_types_htcap);
1053         cmd_append_size += sizeof(struct mwifiex_ie_types_htcap);
1054 
1055         /* Fill HT INFORMATION */
1056         ht_info = (struct mwifiex_ie_types_htinfo *) pos;
1057         memset(ht_info, 0, sizeof(struct mwifiex_ie_types_htinfo));
1058         ht_info->header.type = cpu_to_le16(WLAN_EID_HT_OPERATION);
1059         ht_info->header.len =
1060             cpu_to_le16(sizeof(struct ieee80211_ht_operation));
1061 
1062         ht_info->ht_oper.primary_chan =
1063             (u8) priv->curr_bss_params.bss_descriptor.channel;
1064         if (adapter->sec_chan_offset) {
1065             ht_info->ht_oper.ht_param = adapter->sec_chan_offset;
1066             ht_info->ht_oper.ht_param |=
1067                     IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
1068         }
1069         ht_info->ht_oper.operation_mode =
1070              cpu_to_le16(IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
1071         ht_info->ht_oper.basic_set[0] = 0xff;
1072         pos += sizeof(struct mwifiex_ie_types_htinfo);
1073         cmd_append_size +=
1074                 sizeof(struct mwifiex_ie_types_htinfo);
1075     }
1076 
1077     cmd->size =
1078         cpu_to_le16((u16)(sizeof(struct host_cmd_ds_802_11_ad_hoc_start)
1079                   + S_DS_GEN + cmd_append_size));
1080 
1081     if (adapter->adhoc_start_band == BAND_B)
1082         tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME;
1083     else
1084         tmp_cap |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
1085 
1086     adhoc_start->cap_info_bitmap = cpu_to_le16(tmp_cap);
1087 
1088     return 0;
1089 }
1090 
1091 /*
1092  * This function prepares command for ad-hoc join.
1093  *
1094  * Most of the parameters are set up by copying from the target BSS descriptor
1095  * from the scan response.
1096  *
1097  * In addition, the following TLVs are added -
1098  *      - Channel TLV
1099  *      - Vendor specific IE
1100  *      - WPA/WPA2 IE
1101  *      - 11n IE
1102  *
1103  * Preparation also includes -
1104  *      - Setting command ID and proper size
1105  *      - Ensuring correct endian-ness
1106  */
1107 int
1108 mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv,
1109                    struct host_cmd_ds_command *cmd,
1110                    struct mwifiex_bssdescriptor *bss_desc)
1111 {
1112     int rsn_ie_len = 0;
1113     struct host_cmd_ds_802_11_ad_hoc_join *adhoc_join =
1114         &cmd->params.adhoc_join;
1115     struct mwifiex_ie_types_chan_list_param_set *chan_tlv;
1116     u32 cmd_append_size = 0;
1117     u16 tmp_cap;
1118     u32 i, rates_size = 0;
1119     u16 curr_pkt_filter;
1120     u8 *pos =
1121         (u8 *) adhoc_join +
1122         sizeof(struct host_cmd_ds_802_11_ad_hoc_join);
1123 
1124 /* Use G protection */
1125 #define USE_G_PROTECTION        0x02
1126     if (bss_desc->erp_flags & USE_G_PROTECTION) {
1127         curr_pkt_filter =
1128             priv->
1129             curr_pkt_filter | HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON;
1130 
1131         if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
1132                      HostCmd_ACT_GEN_SET, 0,
1133                      &curr_pkt_filter, false)) {
1134             mwifiex_dbg(priv->adapter, ERROR,
1135                     "ADHOC_J_CMD: G Protection config failed\n");
1136             return -1;
1137         }
1138     }
1139 
1140     priv->attempted_bss_desc = bss_desc;
1141 
1142     cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_JOIN);
1143 
1144     adhoc_join->bss_descriptor.bss_mode = HostCmd_BSS_MODE_IBSS;
1145 
1146     adhoc_join->bss_descriptor.beacon_period
1147         = cpu_to_le16(bss_desc->beacon_period);
1148 
1149     memcpy(&adhoc_join->bss_descriptor.bssid,
1150            &bss_desc->mac_address, ETH_ALEN);
1151 
1152     memcpy(&adhoc_join->bss_descriptor.ssid,
1153            &bss_desc->ssid.ssid, bss_desc->ssid.ssid_len);
1154 
1155     memcpy(&adhoc_join->bss_descriptor.phy_param_set,
1156            &bss_desc->phy_param_set,
1157            sizeof(union ieee_types_phy_param_set));
1158 
1159     memcpy(&adhoc_join->bss_descriptor.ss_param_set,
1160            &bss_desc->ss_param_set, sizeof(union ieee_types_ss_param_set));
1161 
1162     tmp_cap = bss_desc->cap_info_bitmap;
1163 
1164     tmp_cap &= CAPINFO_MASK;
1165 
1166     mwifiex_dbg(priv->adapter, INFO,
1167             "info: ADHOC_J_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n",
1168             tmp_cap, CAPINFO_MASK);
1169 
1170     /* Information on BSSID descriptor passed to FW */
1171     mwifiex_dbg(priv->adapter, INFO,
1172             "info: ADHOC_J_CMD: BSSID=%pM, SSID='%s'\n",
1173             adhoc_join->bss_descriptor.bssid,
1174             adhoc_join->bss_descriptor.ssid);
1175 
1176     for (i = 0; i < MWIFIEX_SUPPORTED_RATES &&
1177             bss_desc->supported_rates[i]; i++)
1178         ;
1179     rates_size = i;
1180 
1181     /* Copy Data Rates from the Rates recorded in scan response */
1182     memset(adhoc_join->bss_descriptor.data_rates, 0,
1183            sizeof(adhoc_join->bss_descriptor.data_rates));
1184     memcpy(adhoc_join->bss_descriptor.data_rates,
1185            bss_desc->supported_rates, rates_size);
1186 
1187     /* Copy the adhoc join rates into Current BSS state structure */
1188     priv->curr_bss_params.num_of_rates = rates_size;
1189     memcpy(&priv->curr_bss_params.data_rates, bss_desc->supported_rates,
1190            rates_size);
1191 
1192     /* Copy the channel information */
1193     priv->curr_bss_params.bss_descriptor.channel = bss_desc->channel;
1194     priv->curr_bss_params.band = (u8) bss_desc->bss_band;
1195 
1196     if (priv->sec_info.wep_enabled || priv->sec_info.wpa_enabled)
1197         tmp_cap |= WLAN_CAPABILITY_PRIVACY;
1198 
1199     if (IS_SUPPORT_MULTI_BANDS(priv->adapter)) {
1200         /* Append a channel TLV */
1201         chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos;
1202         chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
1203         chan_tlv->header.len =
1204             cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set));
1205 
1206         memset(chan_tlv->chan_scan_param, 0x00,
1207                sizeof(struct mwifiex_chan_scan_param_set));
1208         chan_tlv->chan_scan_param[0].chan_number =
1209             (bss_desc->phy_param_set.ds_param_set.current_chan);
1210         mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_J_CMD: TLV Chan=%d\n",
1211                 chan_tlv->chan_scan_param[0].chan_number);
1212 
1213         chan_tlv->chan_scan_param[0].radio_type =
1214             mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
1215 
1216         mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_J_CMD: TLV Band=%d\n",
1217                 chan_tlv->chan_scan_param[0].radio_type);
1218         pos += sizeof(chan_tlv->header) +
1219                 sizeof(struct mwifiex_chan_scan_param_set);
1220         cmd_append_size += sizeof(chan_tlv->header) +
1221                 sizeof(struct mwifiex_chan_scan_param_set);
1222     }
1223 
1224     if (priv->sec_info.wpa_enabled)
1225         rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos);
1226     if (rsn_ie_len == -1)
1227         return -1;
1228     cmd_append_size += rsn_ie_len;
1229 
1230     if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info))
1231         cmd_append_size += mwifiex_cmd_append_11n_tlv(priv,
1232             bss_desc, &pos);
1233 
1234     /* Append vendor specific IE TLV */
1235     cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv,
1236             MWIFIEX_VSIE_MASK_ADHOC, &pos);
1237 
1238     cmd->size = cpu_to_le16
1239         ((u16) (sizeof(struct host_cmd_ds_802_11_ad_hoc_join)
1240             + S_DS_GEN + cmd_append_size));
1241 
1242     adhoc_join->bss_descriptor.cap_info_bitmap = cpu_to_le16(tmp_cap);
1243 
1244     return 0;
1245 }
1246 
1247 /*
1248  * This function handles the command response of ad-hoc start and
1249  * ad-hoc join.
1250  *
1251  * The function generates a device-connected event to notify
1252  * the applications, in case of successful ad-hoc start/join, and
1253  * saves the beacon buffer.
1254  */
1255 int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv,
1256                   struct host_cmd_ds_command *resp)
1257 {
1258     int ret = 0;
1259     struct mwifiex_adapter *adapter = priv->adapter;
1260     struct host_cmd_ds_802_11_ad_hoc_start_result *start_result =
1261                 &resp->params.start_result;
1262     struct host_cmd_ds_802_11_ad_hoc_join_result *join_result =
1263                 &resp->params.join_result;
1264     struct mwifiex_bssdescriptor *bss_desc;
1265     u16 cmd = le16_to_cpu(resp->command);
1266     u8 result;
1267 
1268     if (!priv->attempted_bss_desc) {
1269         mwifiex_dbg(priv->adapter, ERROR,
1270                 "ADHOC_RESP: failed, association terminated by host\n");
1271         goto done;
1272     }
1273 
1274     if (cmd == HostCmd_CMD_802_11_AD_HOC_START)
1275         result = start_result->result;
1276     else
1277         result = join_result->result;
1278 
1279     bss_desc = priv->attempted_bss_desc;
1280 
1281     /* Join result code 0 --> SUCCESS */
1282     if (result) {
1283         mwifiex_dbg(priv->adapter, ERROR, "ADHOC_RESP: failed\n");
1284         if (priv->media_connected)
1285             mwifiex_reset_connect_state(priv, result, true);
1286 
1287         memset(&priv->curr_bss_params.bss_descriptor,
1288                0x00, sizeof(struct mwifiex_bssdescriptor));
1289 
1290         ret = -1;
1291         goto done;
1292     }
1293 
1294     /* Send a Media Connected event, according to the Spec */
1295     priv->media_connected = true;
1296 
1297     if (le16_to_cpu(resp->command) == HostCmd_CMD_802_11_AD_HOC_START) {
1298         mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_S_RESP %s\n",
1299                 bss_desc->ssid.ssid);
1300 
1301         /* Update the created network descriptor with the new BSSID */
1302         memcpy(bss_desc->mac_address,
1303                start_result->bssid, ETH_ALEN);
1304 
1305         priv->adhoc_state = ADHOC_STARTED;
1306     } else {
1307         /*
1308          * Now the join cmd should be successful.
1309          * If BSSID has changed use SSID to compare instead of BSSID
1310          */
1311         mwifiex_dbg(priv->adapter, INFO,
1312                 "info: ADHOC_J_RESP %s\n",
1313                 bss_desc->ssid.ssid);
1314 
1315         /*
1316          * Make a copy of current BSSID descriptor, only needed for
1317          * join since the current descriptor is already being used
1318          * for adhoc start
1319          */
1320         memcpy(&priv->curr_bss_params.bss_descriptor,
1321                bss_desc, sizeof(struct mwifiex_bssdescriptor));
1322 
1323         priv->adhoc_state = ADHOC_JOINED;
1324     }
1325 
1326     mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_RESP: channel = %d\n",
1327             priv->adhoc_channel);
1328     mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_RESP: BSSID = %pM\n",
1329             priv->curr_bss_params.bss_descriptor.mac_address);
1330 
1331     if (!netif_carrier_ok(priv->netdev))
1332         netif_carrier_on(priv->netdev);
1333     mwifiex_wake_up_net_dev_queue(priv->netdev, adapter);
1334 
1335     mwifiex_save_curr_bcn(priv);
1336 
1337 done:
1338     /* Need to indicate IOCTL complete */
1339     if (adapter->curr_cmd->wait_q_enabled) {
1340         if (ret)
1341             adapter->cmd_wait_q.status = -1;
1342         else
1343             adapter->cmd_wait_q.status = 0;
1344 
1345     }
1346 
1347     return ret;
1348 }
1349 
1350 /*
1351  * This function associates to a specific BSS discovered in a scan.
1352  *
1353  * It clears any past association response stored for application
1354  * retrieval and calls the command preparation routine to send the
1355  * command to firmware.
1356  */
1357 int mwifiex_associate(struct mwifiex_private *priv,
1358               struct mwifiex_bssdescriptor *bss_desc)
1359 {
1360     /* Return error if the adapter is not STA role or table entry
1361      * is not marked as infra.
1362      */
1363     if ((GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) ||
1364         (bss_desc->bss_mode != NL80211_IFTYPE_STATION))
1365         return -1;
1366 
1367     if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) &&
1368         !bss_desc->disable_11n && !bss_desc->disable_11ac &&
1369         priv->adapter->config_bands & BAND_AAC)
1370         mwifiex_set_11ac_ba_params(priv);
1371     else
1372         mwifiex_set_ba_params(priv);
1373 
1374     /* Clear any past association response stored for application
1375        retrieval */
1376     priv->assoc_rsp_size = 0;
1377 
1378     return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_ASSOCIATE,
1379                 HostCmd_ACT_GEN_SET, 0, bss_desc, true);
1380 }
1381 
1382 /*
1383  * This function starts an ad-hoc network.
1384  *
1385  * It calls the command preparation routine to send the command to firmware.
1386  */
1387 int
1388 mwifiex_adhoc_start(struct mwifiex_private *priv,
1389             struct cfg80211_ssid *adhoc_ssid)
1390 {
1391     mwifiex_dbg(priv->adapter, INFO, "info: Adhoc Channel = %d\n",
1392             priv->adhoc_channel);
1393     mwifiex_dbg(priv->adapter, INFO, "info: curr_bss_params.channel = %d\n",
1394             priv->curr_bss_params.bss_descriptor.channel);
1395     mwifiex_dbg(priv->adapter, INFO, "info: curr_bss_params.band = %d\n",
1396             priv->curr_bss_params.band);
1397 
1398     if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) &&
1399         priv->adapter->config_bands & BAND_AAC)
1400         mwifiex_set_11ac_ba_params(priv);
1401     else
1402         mwifiex_set_ba_params(priv);
1403 
1404     return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_START,
1405                 HostCmd_ACT_GEN_SET, 0, adhoc_ssid, true);
1406 }
1407 
1408 /*
1409  * This function joins an ad-hoc network found in a previous scan.
1410  *
1411  * It calls the command preparation routine to send the command to firmware,
1412  * if already not connected to the requested SSID.
1413  */
1414 int mwifiex_adhoc_join(struct mwifiex_private *priv,
1415                struct mwifiex_bssdescriptor *bss_desc)
1416 {
1417     mwifiex_dbg(priv->adapter, INFO,
1418             "info: adhoc join: curr_bss ssid =%s\n",
1419             priv->curr_bss_params.bss_descriptor.ssid.ssid);
1420     mwifiex_dbg(priv->adapter, INFO,
1421             "info: adhoc join: curr_bss ssid_len =%u\n",
1422             priv->curr_bss_params.bss_descriptor.ssid.ssid_len);
1423     mwifiex_dbg(priv->adapter, INFO, "info: adhoc join: ssid =%s\n",
1424             bss_desc->ssid.ssid);
1425     mwifiex_dbg(priv->adapter, INFO, "info: adhoc join: ssid_len =%u\n",
1426             bss_desc->ssid.ssid_len);
1427 
1428     /* Check if the requested SSID is already joined */
1429     if (priv->curr_bss_params.bss_descriptor.ssid.ssid_len &&
1430         !mwifiex_ssid_cmp(&bss_desc->ssid,
1431                   &priv->curr_bss_params.bss_descriptor.ssid) &&
1432         (priv->curr_bss_params.bss_descriptor.bss_mode ==
1433                             NL80211_IFTYPE_ADHOC)) {
1434         mwifiex_dbg(priv->adapter, INFO,
1435                 "info: ADHOC_J_CMD: new ad-hoc SSID\t"
1436                 "is the same as current; not attempting to re-join\n");
1437         return -1;
1438     }
1439 
1440     if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) &&
1441         !bss_desc->disable_11n && !bss_desc->disable_11ac &&
1442         priv->adapter->config_bands & BAND_AAC)
1443         mwifiex_set_11ac_ba_params(priv);
1444     else
1445         mwifiex_set_ba_params(priv);
1446 
1447     mwifiex_dbg(priv->adapter, INFO,
1448             "info: curr_bss_params.channel = %d\n",
1449             priv->curr_bss_params.bss_descriptor.channel);
1450     mwifiex_dbg(priv->adapter, INFO,
1451             "info: curr_bss_params.band = %c\n",
1452             priv->curr_bss_params.band);
1453 
1454     return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_JOIN,
1455                 HostCmd_ACT_GEN_SET, 0, bss_desc, true);
1456 }
1457 
1458 /*
1459  * This function deauthenticates/disconnects from infra network by sending
1460  * deauthentication request.
1461  */
1462 static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, u8 *mac)
1463 {
1464     u8 mac_address[ETH_ALEN];
1465     int ret;
1466 
1467     if (!mac || is_zero_ether_addr(mac))
1468         memcpy(mac_address,
1469                priv->curr_bss_params.bss_descriptor.mac_address,
1470                ETH_ALEN);
1471     else
1472         memcpy(mac_address, mac, ETH_ALEN);
1473 
1474     ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_DEAUTHENTICATE,
1475                    HostCmd_ACT_GEN_SET, 0, mac_address, true);
1476 
1477     return ret;
1478 }
1479 
1480 /*
1481  * This function deauthenticates/disconnects from a BSS.
1482  *
1483  * In case of infra made, it sends deauthentication request, and
1484  * in case of ad-hoc mode, a stop network request is sent to the firmware.
1485  * In AP mode, a command to stop bss is sent to firmware.
1486  */
1487 int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac)
1488 {
1489     int ret = 0;
1490 
1491     if (!priv->media_connected)
1492         return 0;
1493 
1494     switch (priv->bss_mode) {
1495     case NL80211_IFTYPE_STATION:
1496     case NL80211_IFTYPE_P2P_CLIENT:
1497         ret = mwifiex_deauthenticate_infra(priv, mac);
1498         if (ret)
1499             cfg80211_disconnected(priv->netdev, 0, NULL, 0,
1500                           true, GFP_KERNEL);
1501         break;
1502     case NL80211_IFTYPE_ADHOC:
1503         return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_STOP,
1504                     HostCmd_ACT_GEN_SET, 0, NULL, true);
1505     case NL80211_IFTYPE_AP:
1506         return mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP,
1507                     HostCmd_ACT_GEN_SET, 0, NULL, true);
1508     default:
1509         break;
1510     }
1511 
1512     return ret;
1513 }
1514 
1515 /* This function deauthenticates/disconnects from all BSS. */
1516 void mwifiex_deauthenticate_all(struct mwifiex_adapter *adapter)
1517 {
1518     struct mwifiex_private *priv;
1519     int i;
1520 
1521     for (i = 0; i < adapter->priv_num; i++) {
1522         priv = adapter->priv[i];
1523         if (priv)
1524             mwifiex_deauthenticate(priv, NULL);
1525     }
1526 }
1527 EXPORT_SYMBOL_GPL(mwifiex_deauthenticate_all);
1528 
1529 /*
1530  * This function converts band to radio type used in channel TLV.
1531  */
1532 u8
1533 mwifiex_band_to_radio_type(u8 band)
1534 {
1535     switch (band) {
1536     case BAND_A:
1537     case BAND_AN:
1538     case BAND_A | BAND_AN:
1539     case BAND_A | BAND_AN | BAND_AAC:
1540         return HostCmd_SCAN_RADIO_TYPE_A;
1541     case BAND_B:
1542     case BAND_G:
1543     case BAND_B | BAND_G:
1544     default:
1545         return HostCmd_SCAN_RADIO_TYPE_BG;
1546     }
1547 }