162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * NXP Wireless LAN device driver: association and ad-hoc start/join 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2011-2020 NXP 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "decl.h" 962306a36Sopenharmony_ci#include "ioctl.h" 1062306a36Sopenharmony_ci#include "util.h" 1162306a36Sopenharmony_ci#include "fw.h" 1262306a36Sopenharmony_ci#include "main.h" 1362306a36Sopenharmony_ci#include "wmm.h" 1462306a36Sopenharmony_ci#include "11n.h" 1562306a36Sopenharmony_ci#include "11ac.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define CAPINFO_MASK (~(BIT(15) | BIT(14) | BIT(12) | BIT(11) | BIT(9))) 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/* 2062306a36Sopenharmony_ci * Append a generic IE as a pass through TLV to a TLV buffer. 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * This function is called from the network join command preparation routine. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * If the IE buffer has been setup by the application, this routine appends 2562306a36Sopenharmony_ci * the buffer as a pass through TLV type to the request. 2662306a36Sopenharmony_ci */ 2762306a36Sopenharmony_cistatic int 2862306a36Sopenharmony_cimwifiex_cmd_append_generic_ie(struct mwifiex_private *priv, u8 **buffer) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci int ret_len = 0; 3162306a36Sopenharmony_ci struct mwifiex_ie_types_header ie_header; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci /* Null Checks */ 3462306a36Sopenharmony_ci if (!buffer) 3562306a36Sopenharmony_ci return 0; 3662306a36Sopenharmony_ci if (!(*buffer)) 3762306a36Sopenharmony_ci return 0; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci /* 4062306a36Sopenharmony_ci * If there is a generic ie buffer setup, append it to the return 4162306a36Sopenharmony_ci * parameter buffer pointer. 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_ci if (priv->gen_ie_buf_len) { 4462306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 4562306a36Sopenharmony_ci "info: %s: append generic ie len %d to %p\n", 4662306a36Sopenharmony_ci __func__, priv->gen_ie_buf_len, *buffer); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci /* Wrap the generic IE buffer with a pass through TLV type */ 4962306a36Sopenharmony_ci ie_header.type = cpu_to_le16(TLV_TYPE_PASSTHROUGH); 5062306a36Sopenharmony_ci ie_header.len = cpu_to_le16(priv->gen_ie_buf_len); 5162306a36Sopenharmony_ci memcpy(*buffer, &ie_header, sizeof(ie_header)); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci /* Increment the return size and the return buffer pointer 5462306a36Sopenharmony_ci param */ 5562306a36Sopenharmony_ci *buffer += sizeof(ie_header); 5662306a36Sopenharmony_ci ret_len += sizeof(ie_header); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci /* Copy the generic IE buffer to the output buffer, advance 5962306a36Sopenharmony_ci pointer */ 6062306a36Sopenharmony_ci memcpy(*buffer, priv->gen_ie_buf, priv->gen_ie_buf_len); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci /* Increment the return size and the return buffer pointer 6362306a36Sopenharmony_ci param */ 6462306a36Sopenharmony_ci *buffer += priv->gen_ie_buf_len; 6562306a36Sopenharmony_ci ret_len += priv->gen_ie_buf_len; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci /* Reset the generic IE buffer */ 6862306a36Sopenharmony_ci priv->gen_ie_buf_len = 0; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci /* return the length appended to the buffer */ 7262306a36Sopenharmony_ci return ret_len; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* 7662306a36Sopenharmony_ci * Append TSF tracking info from the scan table for the target AP. 7762306a36Sopenharmony_ci * 7862306a36Sopenharmony_ci * This function is called from the network join command preparation routine. 7962306a36Sopenharmony_ci * 8062306a36Sopenharmony_ci * The TSF table TSF sent to the firmware contains two TSF values: 8162306a36Sopenharmony_ci * - The TSF of the target AP from its previous beacon/probe response 8262306a36Sopenharmony_ci * - The TSF timestamp of our local MAC at the time we observed the 8362306a36Sopenharmony_ci * beacon/probe response. 8462306a36Sopenharmony_ci * 8562306a36Sopenharmony_ci * The firmware uses the timestamp values to set an initial TSF value 8662306a36Sopenharmony_ci * in the MAC for the new association after a reassociation attempt. 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_cistatic int 8962306a36Sopenharmony_cimwifiex_cmd_append_tsf_tlv(struct mwifiex_private *priv, u8 **buffer, 9062306a36Sopenharmony_ci struct mwifiex_bssdescriptor *bss_desc) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci struct mwifiex_ie_types_tsf_timestamp tsf_tlv; 9362306a36Sopenharmony_ci __le64 tsf_val; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci /* Null Checks */ 9662306a36Sopenharmony_ci if (buffer == NULL) 9762306a36Sopenharmony_ci return 0; 9862306a36Sopenharmony_ci if (*buffer == NULL) 9962306a36Sopenharmony_ci return 0; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci memset(&tsf_tlv, 0x00, sizeof(struct mwifiex_ie_types_tsf_timestamp)); 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci tsf_tlv.header.type = cpu_to_le16(TLV_TYPE_TSFTIMESTAMP); 10462306a36Sopenharmony_ci tsf_tlv.header.len = cpu_to_le16(2 * sizeof(tsf_val)); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci memcpy(*buffer, &tsf_tlv, sizeof(tsf_tlv.header)); 10762306a36Sopenharmony_ci *buffer += sizeof(tsf_tlv.header); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* TSF at the time when beacon/probe_response was received */ 11062306a36Sopenharmony_ci tsf_val = cpu_to_le64(bss_desc->fw_tsf); 11162306a36Sopenharmony_ci memcpy(*buffer, &tsf_val, sizeof(tsf_val)); 11262306a36Sopenharmony_ci *buffer += sizeof(tsf_val); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci tsf_val = cpu_to_le64(bss_desc->timestamp); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 11762306a36Sopenharmony_ci "info: %s: TSF offset calc: %016llx - %016llx\n", 11862306a36Sopenharmony_ci __func__, bss_desc->timestamp, bss_desc->fw_tsf); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci memcpy(*buffer, &tsf_val, sizeof(tsf_val)); 12162306a36Sopenharmony_ci *buffer += sizeof(tsf_val); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci return sizeof(tsf_tlv.header) + (2 * sizeof(tsf_val)); 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci/* 12762306a36Sopenharmony_ci * This function finds out the common rates between rate1 and rate2. 12862306a36Sopenharmony_ci * 12962306a36Sopenharmony_ci * It will fill common rates in rate1 as output if found. 13062306a36Sopenharmony_ci * 13162306a36Sopenharmony_ci * NOTE: Setting the MSB of the basic rates needs to be taken 13262306a36Sopenharmony_ci * care of, either before or after calling this function. 13362306a36Sopenharmony_ci */ 13462306a36Sopenharmony_cistatic int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1, 13562306a36Sopenharmony_ci u32 rate1_size, u8 *rate2, u32 rate2_size) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci int ret; 13862306a36Sopenharmony_ci u8 *ptr = rate1, *tmp; 13962306a36Sopenharmony_ci u32 i, j; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci tmp = kmemdup(rate1, rate1_size, GFP_KERNEL); 14262306a36Sopenharmony_ci if (!tmp) { 14362306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, "failed to alloc tmp buf\n"); 14462306a36Sopenharmony_ci return -ENOMEM; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci memset(rate1, 0, rate1_size); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci for (i = 0; i < rate2_size && rate2[i]; i++) { 15062306a36Sopenharmony_ci for (j = 0; j < rate1_size && tmp[j]; j++) { 15162306a36Sopenharmony_ci /* Check common rate, excluding the bit for 15262306a36Sopenharmony_ci basic rate */ 15362306a36Sopenharmony_ci if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) { 15462306a36Sopenharmony_ci *rate1++ = tmp[j]; 15562306a36Sopenharmony_ci break; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, "info: Tx data rate set to %#x\n", 16162306a36Sopenharmony_ci priv->data_rate); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (!priv->is_data_rate_auto) { 16462306a36Sopenharmony_ci while (*ptr) { 16562306a36Sopenharmony_ci if ((*ptr & 0x7f) == priv->data_rate) { 16662306a36Sopenharmony_ci ret = 0; 16762306a36Sopenharmony_ci goto done; 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci ptr++; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 17262306a36Sopenharmony_ci "previously set fixed data rate %#x\t" 17362306a36Sopenharmony_ci "is not compatible with the network\n", 17462306a36Sopenharmony_ci priv->data_rate); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci ret = -1; 17762306a36Sopenharmony_ci goto done; 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci ret = 0; 18162306a36Sopenharmony_cidone: 18262306a36Sopenharmony_ci kfree(tmp); 18362306a36Sopenharmony_ci return ret; 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci/* 18762306a36Sopenharmony_ci * This function creates the intersection of the rates supported by a 18862306a36Sopenharmony_ci * target BSS and our adapter settings for use in an assoc/join command. 18962306a36Sopenharmony_ci */ 19062306a36Sopenharmony_cistatic int 19162306a36Sopenharmony_cimwifiex_setup_rates_from_bssdesc(struct mwifiex_private *priv, 19262306a36Sopenharmony_ci struct mwifiex_bssdescriptor *bss_desc, 19362306a36Sopenharmony_ci u8 *out_rates, u32 *out_rates_size) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci u8 card_rates[MWIFIEX_SUPPORTED_RATES]; 19662306a36Sopenharmony_ci u32 card_rates_size; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci /* Copy AP supported rates */ 19962306a36Sopenharmony_ci memcpy(out_rates, bss_desc->supported_rates, MWIFIEX_SUPPORTED_RATES); 20062306a36Sopenharmony_ci /* Get the STA supported rates */ 20162306a36Sopenharmony_ci card_rates_size = mwifiex_get_active_data_rates(priv, card_rates); 20262306a36Sopenharmony_ci /* Get the common rates between AP and STA supported rates */ 20362306a36Sopenharmony_ci if (mwifiex_get_common_rates(priv, out_rates, MWIFIEX_SUPPORTED_RATES, 20462306a36Sopenharmony_ci card_rates, card_rates_size)) { 20562306a36Sopenharmony_ci *out_rates_size = 0; 20662306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 20762306a36Sopenharmony_ci "%s: cannot get common rates\n", 20862306a36Sopenharmony_ci __func__); 20962306a36Sopenharmony_ci return -1; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci *out_rates_size = 21362306a36Sopenharmony_ci min_t(size_t, strlen(out_rates), MWIFIEX_SUPPORTED_RATES); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci return 0; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci/* 21962306a36Sopenharmony_ci * This function appends a WPS IE. It is called from the network join command 22062306a36Sopenharmony_ci * preparation routine. 22162306a36Sopenharmony_ci * 22262306a36Sopenharmony_ci * If the IE buffer has been setup by the application, this routine appends 22362306a36Sopenharmony_ci * the buffer as a WPS TLV type to the request. 22462306a36Sopenharmony_ci */ 22562306a36Sopenharmony_cistatic int 22662306a36Sopenharmony_cimwifiex_cmd_append_wps_ie(struct mwifiex_private *priv, u8 **buffer) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci int retLen = 0; 22962306a36Sopenharmony_ci struct mwifiex_ie_types_header ie_header; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci if (!buffer || !*buffer) 23262306a36Sopenharmony_ci return 0; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci /* 23562306a36Sopenharmony_ci * If there is a wps ie buffer setup, append it to the return 23662306a36Sopenharmony_ci * parameter buffer pointer. 23762306a36Sopenharmony_ci */ 23862306a36Sopenharmony_ci if (priv->wps_ie_len) { 23962306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, CMD, 24062306a36Sopenharmony_ci "cmd: append wps ie %d to %p\n", 24162306a36Sopenharmony_ci priv->wps_ie_len, *buffer); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci /* Wrap the generic IE buffer with a pass through TLV type */ 24462306a36Sopenharmony_ci ie_header.type = cpu_to_le16(TLV_TYPE_PASSTHROUGH); 24562306a36Sopenharmony_ci ie_header.len = cpu_to_le16(priv->wps_ie_len); 24662306a36Sopenharmony_ci memcpy(*buffer, &ie_header, sizeof(ie_header)); 24762306a36Sopenharmony_ci *buffer += sizeof(ie_header); 24862306a36Sopenharmony_ci retLen += sizeof(ie_header); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci memcpy(*buffer, priv->wps_ie, priv->wps_ie_len); 25162306a36Sopenharmony_ci *buffer += priv->wps_ie_len; 25262306a36Sopenharmony_ci retLen += priv->wps_ie_len; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci kfree(priv->wps_ie); 25762306a36Sopenharmony_ci priv->wps_ie_len = 0; 25862306a36Sopenharmony_ci return retLen; 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci/* 26262306a36Sopenharmony_ci * This function appends a WAPI IE. 26362306a36Sopenharmony_ci * 26462306a36Sopenharmony_ci * This function is called from the network join command preparation routine. 26562306a36Sopenharmony_ci * 26662306a36Sopenharmony_ci * If the IE buffer has been setup by the application, this routine appends 26762306a36Sopenharmony_ci * the buffer as a WAPI TLV type to the request. 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_cistatic int 27062306a36Sopenharmony_cimwifiex_cmd_append_wapi_ie(struct mwifiex_private *priv, u8 **buffer) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci int retLen = 0; 27362306a36Sopenharmony_ci struct mwifiex_ie_types_header ie_header; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci /* Null Checks */ 27662306a36Sopenharmony_ci if (buffer == NULL) 27762306a36Sopenharmony_ci return 0; 27862306a36Sopenharmony_ci if (*buffer == NULL) 27962306a36Sopenharmony_ci return 0; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* 28262306a36Sopenharmony_ci * If there is a wapi ie buffer setup, append it to the return 28362306a36Sopenharmony_ci * parameter buffer pointer. 28462306a36Sopenharmony_ci */ 28562306a36Sopenharmony_ci if (priv->wapi_ie_len) { 28662306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, CMD, 28762306a36Sopenharmony_ci "cmd: append wapi ie %d to %p\n", 28862306a36Sopenharmony_ci priv->wapi_ie_len, *buffer); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci /* Wrap the generic IE buffer with a pass through TLV type */ 29162306a36Sopenharmony_ci ie_header.type = cpu_to_le16(TLV_TYPE_WAPI_IE); 29262306a36Sopenharmony_ci ie_header.len = cpu_to_le16(priv->wapi_ie_len); 29362306a36Sopenharmony_ci memcpy(*buffer, &ie_header, sizeof(ie_header)); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* Increment the return size and the return buffer pointer 29662306a36Sopenharmony_ci param */ 29762306a36Sopenharmony_ci *buffer += sizeof(ie_header); 29862306a36Sopenharmony_ci retLen += sizeof(ie_header); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci /* Copy the wapi IE buffer to the output buffer, advance 30162306a36Sopenharmony_ci pointer */ 30262306a36Sopenharmony_ci memcpy(*buffer, priv->wapi_ie, priv->wapi_ie_len); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci /* Increment the return size and the return buffer pointer 30562306a36Sopenharmony_ci param */ 30662306a36Sopenharmony_ci *buffer += priv->wapi_ie_len; 30762306a36Sopenharmony_ci retLen += priv->wapi_ie_len; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci /* return the length appended to the buffer */ 31162306a36Sopenharmony_ci return retLen; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci/* 31562306a36Sopenharmony_ci * This function appends rsn ie tlv for wpa/wpa2 security modes. 31662306a36Sopenharmony_ci * It is called from the network join command preparation routine. 31762306a36Sopenharmony_ci */ 31862306a36Sopenharmony_cistatic int mwifiex_append_rsn_ie_wpa_wpa2(struct mwifiex_private *priv, 31962306a36Sopenharmony_ci u8 **buffer) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci struct mwifiex_ie_types_rsn_param_set *rsn_ie_tlv; 32262306a36Sopenharmony_ci int rsn_ie_len; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci if (!buffer || !(*buffer)) 32562306a36Sopenharmony_ci return 0; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci rsn_ie_tlv = (struct mwifiex_ie_types_rsn_param_set *) (*buffer); 32862306a36Sopenharmony_ci rsn_ie_tlv->header.type = cpu_to_le16((u16) priv->wpa_ie[0]); 32962306a36Sopenharmony_ci rsn_ie_tlv->header.type = cpu_to_le16( 33062306a36Sopenharmony_ci le16_to_cpu(rsn_ie_tlv->header.type) & 0x00FF); 33162306a36Sopenharmony_ci rsn_ie_tlv->header.len = cpu_to_le16((u16) priv->wpa_ie[1]); 33262306a36Sopenharmony_ci rsn_ie_tlv->header.len = cpu_to_le16(le16_to_cpu(rsn_ie_tlv->header.len) 33362306a36Sopenharmony_ci & 0x00FF); 33462306a36Sopenharmony_ci if (le16_to_cpu(rsn_ie_tlv->header.len) <= (sizeof(priv->wpa_ie) - 2)) 33562306a36Sopenharmony_ci memcpy(rsn_ie_tlv->rsn_ie, &priv->wpa_ie[2], 33662306a36Sopenharmony_ci le16_to_cpu(rsn_ie_tlv->header.len)); 33762306a36Sopenharmony_ci else 33862306a36Sopenharmony_ci return -1; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci rsn_ie_len = sizeof(rsn_ie_tlv->header) + 34162306a36Sopenharmony_ci le16_to_cpu(rsn_ie_tlv->header.len); 34262306a36Sopenharmony_ci *buffer += rsn_ie_len; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci return rsn_ie_len; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci/* 34862306a36Sopenharmony_ci * This function prepares command for association. 34962306a36Sopenharmony_ci * 35062306a36Sopenharmony_ci * This sets the following parameters - 35162306a36Sopenharmony_ci * - Peer MAC address 35262306a36Sopenharmony_ci * - Listen interval 35362306a36Sopenharmony_ci * - Beacon interval 35462306a36Sopenharmony_ci * - Capability information 35562306a36Sopenharmony_ci * 35662306a36Sopenharmony_ci * ...and the following TLVs, as required - 35762306a36Sopenharmony_ci * - SSID TLV 35862306a36Sopenharmony_ci * - PHY TLV 35962306a36Sopenharmony_ci * - SS TLV 36062306a36Sopenharmony_ci * - Rates TLV 36162306a36Sopenharmony_ci * - Authentication TLV 36262306a36Sopenharmony_ci * - Channel TLV 36362306a36Sopenharmony_ci * - WPA/WPA2 IE 36462306a36Sopenharmony_ci * - 11n TLV 36562306a36Sopenharmony_ci * - Vendor specific TLV 36662306a36Sopenharmony_ci * - WMM TLV 36762306a36Sopenharmony_ci * - WAPI IE 36862306a36Sopenharmony_ci * - Generic IE 36962306a36Sopenharmony_ci * - TSF TLV 37062306a36Sopenharmony_ci * 37162306a36Sopenharmony_ci * Preparation also includes - 37262306a36Sopenharmony_ci * - Setting command ID and proper size 37362306a36Sopenharmony_ci * - Ensuring correct endian-ness 37462306a36Sopenharmony_ci */ 37562306a36Sopenharmony_ciint mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, 37662306a36Sopenharmony_ci struct host_cmd_ds_command *cmd, 37762306a36Sopenharmony_ci struct mwifiex_bssdescriptor *bss_desc) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci struct host_cmd_ds_802_11_associate *assoc = &cmd->params.associate; 38062306a36Sopenharmony_ci struct mwifiex_ie_types_ssid_param_set *ssid_tlv; 38162306a36Sopenharmony_ci struct mwifiex_ie_types_phy_param_set *phy_tlv; 38262306a36Sopenharmony_ci struct mwifiex_ie_types_ss_param_set *ss_tlv; 38362306a36Sopenharmony_ci struct mwifiex_ie_types_rates_param_set *rates_tlv; 38462306a36Sopenharmony_ci struct mwifiex_ie_types_auth_type *auth_tlv; 38562306a36Sopenharmony_ci struct mwifiex_ie_types_chan_list_param_set *chan_tlv; 38662306a36Sopenharmony_ci u8 rates[MWIFIEX_SUPPORTED_RATES]; 38762306a36Sopenharmony_ci u32 rates_size; 38862306a36Sopenharmony_ci u16 tmp_cap; 38962306a36Sopenharmony_ci u8 *pos; 39062306a36Sopenharmony_ci int rsn_ie_len = 0; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci pos = (u8 *) assoc; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci cmd->command = cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* Save so we know which BSS Desc to use in the response handler */ 39762306a36Sopenharmony_ci priv->attempted_bss_desc = bss_desc; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci memcpy(assoc->peer_sta_addr, 40062306a36Sopenharmony_ci bss_desc->mac_address, sizeof(assoc->peer_sta_addr)); 40162306a36Sopenharmony_ci pos += sizeof(assoc->peer_sta_addr); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci /* Set the listen interval */ 40462306a36Sopenharmony_ci assoc->listen_interval = cpu_to_le16(priv->listen_interval); 40562306a36Sopenharmony_ci /* Set the beacon period */ 40662306a36Sopenharmony_ci assoc->beacon_period = cpu_to_le16(bss_desc->beacon_period); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci pos += sizeof(assoc->cap_info_bitmap); 40962306a36Sopenharmony_ci pos += sizeof(assoc->listen_interval); 41062306a36Sopenharmony_ci pos += sizeof(assoc->beacon_period); 41162306a36Sopenharmony_ci pos += sizeof(assoc->dtim_period); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci ssid_tlv = (struct mwifiex_ie_types_ssid_param_set *) pos; 41462306a36Sopenharmony_ci ssid_tlv->header.type = cpu_to_le16(WLAN_EID_SSID); 41562306a36Sopenharmony_ci ssid_tlv->header.len = cpu_to_le16((u16) bss_desc->ssid.ssid_len); 41662306a36Sopenharmony_ci memcpy(ssid_tlv->ssid, bss_desc->ssid.ssid, 41762306a36Sopenharmony_ci le16_to_cpu(ssid_tlv->header.len)); 41862306a36Sopenharmony_ci pos += sizeof(ssid_tlv->header) + le16_to_cpu(ssid_tlv->header.len); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci phy_tlv = (struct mwifiex_ie_types_phy_param_set *) pos; 42162306a36Sopenharmony_ci phy_tlv->header.type = cpu_to_le16(WLAN_EID_DS_PARAMS); 42262306a36Sopenharmony_ci phy_tlv->header.len = cpu_to_le16(sizeof(phy_tlv->fh_ds.ds_param_set)); 42362306a36Sopenharmony_ci memcpy(&phy_tlv->fh_ds.ds_param_set, 42462306a36Sopenharmony_ci &bss_desc->phy_param_set.ds_param_set.current_chan, 42562306a36Sopenharmony_ci sizeof(phy_tlv->fh_ds.ds_param_set)); 42662306a36Sopenharmony_ci pos += sizeof(phy_tlv->header) + le16_to_cpu(phy_tlv->header.len); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci ss_tlv = (struct mwifiex_ie_types_ss_param_set *) pos; 42962306a36Sopenharmony_ci ss_tlv->header.type = cpu_to_le16(WLAN_EID_CF_PARAMS); 43062306a36Sopenharmony_ci ss_tlv->header.len = cpu_to_le16(sizeof(ss_tlv->cf_ibss.cf_param_set)); 43162306a36Sopenharmony_ci pos += sizeof(ss_tlv->header) + le16_to_cpu(ss_tlv->header.len); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci /* Get the common rates supported between the driver and the BSS Desc */ 43462306a36Sopenharmony_ci if (mwifiex_setup_rates_from_bssdesc 43562306a36Sopenharmony_ci (priv, bss_desc, rates, &rates_size)) 43662306a36Sopenharmony_ci return -1; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* Save the data rates into Current BSS state structure */ 43962306a36Sopenharmony_ci priv->curr_bss_params.num_of_rates = rates_size; 44062306a36Sopenharmony_ci memcpy(&priv->curr_bss_params.data_rates, rates, rates_size); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci /* Setup the Rates TLV in the association command */ 44362306a36Sopenharmony_ci rates_tlv = (struct mwifiex_ie_types_rates_param_set *) pos; 44462306a36Sopenharmony_ci rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES); 44562306a36Sopenharmony_ci rates_tlv->header.len = cpu_to_le16((u16) rates_size); 44662306a36Sopenharmony_ci memcpy(rates_tlv->rates, rates, rates_size); 44762306a36Sopenharmony_ci pos += sizeof(rates_tlv->header) + rates_size; 44862306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, "info: ASSOC_CMD: rates size = %d\n", 44962306a36Sopenharmony_ci rates_size); 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci /* Add the Authentication type to be used for Auth frames */ 45262306a36Sopenharmony_ci auth_tlv = (struct mwifiex_ie_types_auth_type *) pos; 45362306a36Sopenharmony_ci auth_tlv->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); 45462306a36Sopenharmony_ci auth_tlv->header.len = cpu_to_le16(sizeof(auth_tlv->auth_type)); 45562306a36Sopenharmony_ci if (priv->sec_info.wep_enabled) 45662306a36Sopenharmony_ci auth_tlv->auth_type = cpu_to_le16( 45762306a36Sopenharmony_ci (u16) priv->sec_info.authentication_mode); 45862306a36Sopenharmony_ci else 45962306a36Sopenharmony_ci auth_tlv->auth_type = cpu_to_le16(NL80211_AUTHTYPE_OPEN_SYSTEM); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci pos += sizeof(auth_tlv->header) + le16_to_cpu(auth_tlv->header.len); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci if (IS_SUPPORT_MULTI_BANDS(priv->adapter) && 46462306a36Sopenharmony_ci !(ISSUPP_11NENABLED(priv->adapter->fw_cap_info) && 46562306a36Sopenharmony_ci (!bss_desc->disable_11n) && 46662306a36Sopenharmony_ci (priv->adapter->config_bands & BAND_GN || 46762306a36Sopenharmony_ci priv->adapter->config_bands & BAND_AN) && 46862306a36Sopenharmony_ci (bss_desc->bcn_ht_cap) 46962306a36Sopenharmony_ci ) 47062306a36Sopenharmony_ci ) { 47162306a36Sopenharmony_ci /* Append a channel TLV for the channel the attempted AP was 47262306a36Sopenharmony_ci found on */ 47362306a36Sopenharmony_ci chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; 47462306a36Sopenharmony_ci chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); 47562306a36Sopenharmony_ci chan_tlv->header.len = 47662306a36Sopenharmony_ci cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci memset(chan_tlv->chan_scan_param, 0x00, 47962306a36Sopenharmony_ci sizeof(struct mwifiex_chan_scan_param_set)); 48062306a36Sopenharmony_ci chan_tlv->chan_scan_param[0].chan_number = 48162306a36Sopenharmony_ci (bss_desc->phy_param_set.ds_param_set.current_chan); 48262306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, "info: Assoc: TLV Chan = %d\n", 48362306a36Sopenharmony_ci chan_tlv->chan_scan_param[0].chan_number); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci chan_tlv->chan_scan_param[0].radio_type = 48662306a36Sopenharmony_ci mwifiex_band_to_radio_type((u8) bss_desc->bss_band); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, "info: Assoc: TLV Band = %d\n", 48962306a36Sopenharmony_ci chan_tlv->chan_scan_param[0].radio_type); 49062306a36Sopenharmony_ci pos += sizeof(chan_tlv->header) + 49162306a36Sopenharmony_ci sizeof(struct mwifiex_chan_scan_param_set); 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (!priv->wps.session_enable) { 49562306a36Sopenharmony_ci if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) 49662306a36Sopenharmony_ci rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci if (rsn_ie_len == -1) 49962306a36Sopenharmony_ci return -1; 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info) && 50362306a36Sopenharmony_ci (!bss_desc->disable_11n) && 50462306a36Sopenharmony_ci (priv->adapter->config_bands & BAND_GN || 50562306a36Sopenharmony_ci priv->adapter->config_bands & BAND_AN)) 50662306a36Sopenharmony_ci mwifiex_cmd_append_11n_tlv(priv, bss_desc, &pos); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) && 50962306a36Sopenharmony_ci !bss_desc->disable_11n && !bss_desc->disable_11ac && 51062306a36Sopenharmony_ci priv->adapter->config_bands & BAND_AAC) 51162306a36Sopenharmony_ci mwifiex_cmd_append_11ac_tlv(priv, bss_desc, &pos); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci /* Append vendor specific IE TLV */ 51462306a36Sopenharmony_ci mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_ASSOC, &pos); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci mwifiex_wmm_process_association_req(priv, &pos, &bss_desc->wmm_ie, 51762306a36Sopenharmony_ci bss_desc->bcn_ht_cap); 51862306a36Sopenharmony_ci if (priv->sec_info.wapi_enabled && priv->wapi_ie_len) 51962306a36Sopenharmony_ci mwifiex_cmd_append_wapi_ie(priv, &pos); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci if (priv->wps.session_enable && priv->wps_ie_len) 52262306a36Sopenharmony_ci mwifiex_cmd_append_wps_ie(priv, &pos); 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci mwifiex_cmd_append_generic_ie(priv, &pos); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci mwifiex_cmd_append_tsf_tlv(priv, &pos, bss_desc); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci mwifiex_11h_process_join(priv, &pos, bss_desc); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci cmd->size = cpu_to_le16((u16) (pos - (u8 *) assoc) + S_DS_GEN); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci /* Set the Capability info at last */ 53362306a36Sopenharmony_ci tmp_cap = bss_desc->cap_info_bitmap; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci if (priv->adapter->config_bands == BAND_B) 53662306a36Sopenharmony_ci tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci tmp_cap &= CAPINFO_MASK; 53962306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 54062306a36Sopenharmony_ci "info: ASSOC_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n", 54162306a36Sopenharmony_ci tmp_cap, CAPINFO_MASK); 54262306a36Sopenharmony_ci assoc->cap_info_bitmap = cpu_to_le16(tmp_cap); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci return 0; 54562306a36Sopenharmony_ci} 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_cistatic const char *assoc_failure_reason_to_str(u16 cap_info) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci switch (cap_info) { 55062306a36Sopenharmony_ci case CONNECT_ERR_AUTH_ERR_STA_FAILURE: 55162306a36Sopenharmony_ci return "CONNECT_ERR_AUTH_ERR_STA_FAILURE"; 55262306a36Sopenharmony_ci case CONNECT_ERR_AUTH_MSG_UNHANDLED: 55362306a36Sopenharmony_ci return "CONNECT_ERR_AUTH_MSG_UNHANDLED"; 55462306a36Sopenharmony_ci case CONNECT_ERR_ASSOC_ERR_TIMEOUT: 55562306a36Sopenharmony_ci return "CONNECT_ERR_ASSOC_ERR_TIMEOUT"; 55662306a36Sopenharmony_ci case CONNECT_ERR_ASSOC_ERR_AUTH_REFUSED: 55762306a36Sopenharmony_ci return "CONNECT_ERR_ASSOC_ERR_AUTH_REFUSED"; 55862306a36Sopenharmony_ci case CONNECT_ERR_STA_FAILURE: 55962306a36Sopenharmony_ci return "CONNECT_ERR_STA_FAILURE"; 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci return "Unknown connect failure"; 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci/* 56562306a36Sopenharmony_ci * Association firmware command response handler 56662306a36Sopenharmony_ci * 56762306a36Sopenharmony_ci * The response buffer for the association command has the following 56862306a36Sopenharmony_ci * memory layout. 56962306a36Sopenharmony_ci * 57062306a36Sopenharmony_ci * For cases where an association response was not received (indicated 57162306a36Sopenharmony_ci * by the CapInfo and AId field): 57262306a36Sopenharmony_ci * 57362306a36Sopenharmony_ci * .------------------------------------------------------------. 57462306a36Sopenharmony_ci * | Header(4 * sizeof(t_u16)): Standard command response hdr | 57562306a36Sopenharmony_ci * .------------------------------------------------------------. 57662306a36Sopenharmony_ci * | cap_info/Error Return(t_u16): | 57762306a36Sopenharmony_ci * | 0xFFFF(-1): Internal error | 57862306a36Sopenharmony_ci * | 0xFFFE(-2): Authentication unhandled message | 57962306a36Sopenharmony_ci * | 0xFFFD(-3): Authentication refused | 58062306a36Sopenharmony_ci * | 0xFFFC(-4): Timeout waiting for AP response | 58162306a36Sopenharmony_ci * .------------------------------------------------------------. 58262306a36Sopenharmony_ci * | status_code(t_u16): | 58362306a36Sopenharmony_ci * | If cap_info is -1: | 58462306a36Sopenharmony_ci * | An internal firmware failure prevented the | 58562306a36Sopenharmony_ci * | command from being processed. The status_code | 58662306a36Sopenharmony_ci * | will be set to 1. | 58762306a36Sopenharmony_ci * | | 58862306a36Sopenharmony_ci * | If cap_info is -2: | 58962306a36Sopenharmony_ci * | An authentication frame was received but was | 59062306a36Sopenharmony_ci * | not handled by the firmware. IEEE Status | 59162306a36Sopenharmony_ci * | code for the failure is returned. | 59262306a36Sopenharmony_ci * | | 59362306a36Sopenharmony_ci * | If cap_info is -3: | 59462306a36Sopenharmony_ci * | An authentication frame was received and the | 59562306a36Sopenharmony_ci * | status_code is the IEEE Status reported in the | 59662306a36Sopenharmony_ci * | response. | 59762306a36Sopenharmony_ci * | | 59862306a36Sopenharmony_ci * | If cap_info is -4: | 59962306a36Sopenharmony_ci * | (1) Association response timeout | 60062306a36Sopenharmony_ci * | (2) Authentication response timeout | 60162306a36Sopenharmony_ci * .------------------------------------------------------------. 60262306a36Sopenharmony_ci * | a_id(t_u16): 0xFFFF | 60362306a36Sopenharmony_ci * .------------------------------------------------------------. 60462306a36Sopenharmony_ci * 60562306a36Sopenharmony_ci * 60662306a36Sopenharmony_ci * For cases where an association response was received, the IEEE 60762306a36Sopenharmony_ci * standard association response frame is returned: 60862306a36Sopenharmony_ci * 60962306a36Sopenharmony_ci * .------------------------------------------------------------. 61062306a36Sopenharmony_ci * | Header(4 * sizeof(t_u16)): Standard command response hdr | 61162306a36Sopenharmony_ci * .------------------------------------------------------------. 61262306a36Sopenharmony_ci * | cap_info(t_u16): IEEE Capability | 61362306a36Sopenharmony_ci * .------------------------------------------------------------. 61462306a36Sopenharmony_ci * | status_code(t_u16): IEEE Status Code | 61562306a36Sopenharmony_ci * .------------------------------------------------------------. 61662306a36Sopenharmony_ci * | a_id(t_u16): IEEE Association ID | 61762306a36Sopenharmony_ci * .------------------------------------------------------------. 61862306a36Sopenharmony_ci * | IEEE IEs(variable): Any received IEs comprising the | 61962306a36Sopenharmony_ci * | remaining portion of a received | 62062306a36Sopenharmony_ci * | association response frame. | 62162306a36Sopenharmony_ci * .------------------------------------------------------------. 62262306a36Sopenharmony_ci * 62362306a36Sopenharmony_ci * For simplistic handling, the status_code field can be used to determine 62462306a36Sopenharmony_ci * an association success (0) or failure (non-zero). 62562306a36Sopenharmony_ci */ 62662306a36Sopenharmony_ciint mwifiex_ret_802_11_associate(struct mwifiex_private *priv, 62762306a36Sopenharmony_ci struct host_cmd_ds_command *resp) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 63062306a36Sopenharmony_ci int ret = 0; 63162306a36Sopenharmony_ci struct ieee_types_assoc_rsp *assoc_rsp; 63262306a36Sopenharmony_ci struct mwifiex_bssdescriptor *bss_desc; 63362306a36Sopenharmony_ci bool enable_data = true; 63462306a36Sopenharmony_ci u16 cap_info, status_code, aid; 63562306a36Sopenharmony_ci const u8 *ie_ptr; 63662306a36Sopenharmony_ci struct ieee80211_ht_operation *assoc_resp_ht_oper; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci if (!priv->attempted_bss_desc) { 63962306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 64062306a36Sopenharmony_ci "ASSOC_RESP: failed, association terminated by host\n"); 64162306a36Sopenharmony_ci goto done; 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci cap_info = le16_to_cpu(assoc_rsp->cap_info_bitmap); 64762306a36Sopenharmony_ci status_code = le16_to_cpu(assoc_rsp->status_code); 64862306a36Sopenharmony_ci aid = le16_to_cpu(assoc_rsp->a_id); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) 65162306a36Sopenharmony_ci dev_err(priv->adapter->dev, 65262306a36Sopenharmony_ci "invalid AID value 0x%x; bits 15:14 not set\n", 65362306a36Sopenharmony_ci aid); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci aid &= ~(BIT(15) | BIT(14)); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci priv->assoc_rsp_size = min(le16_to_cpu(resp->size) - S_DS_GEN, 65862306a36Sopenharmony_ci sizeof(priv->assoc_rsp_buf)); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci assoc_rsp->a_id = cpu_to_le16(aid); 66162306a36Sopenharmony_ci memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci if (status_code) { 66462306a36Sopenharmony_ci priv->adapter->dbg.num_cmd_assoc_failure++; 66562306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 66662306a36Sopenharmony_ci "ASSOC_RESP: failed,\t" 66762306a36Sopenharmony_ci "status code=%d err=%#x a_id=%#x\n", 66862306a36Sopenharmony_ci status_code, cap_info, 66962306a36Sopenharmony_ci le16_to_cpu(assoc_rsp->a_id)); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, "assoc failure: reason %s\n", 67262306a36Sopenharmony_ci assoc_failure_reason_to_str(cap_info)); 67362306a36Sopenharmony_ci if (cap_info == CONNECT_ERR_ASSOC_ERR_TIMEOUT) { 67462306a36Sopenharmony_ci if (status_code == MWIFIEX_ASSOC_CMD_FAILURE_AUTH) { 67562306a36Sopenharmony_ci ret = WLAN_STATUS_AUTH_TIMEOUT; 67662306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 67762306a36Sopenharmony_ci "ASSOC_RESP: AUTH timeout\n"); 67862306a36Sopenharmony_ci } else { 67962306a36Sopenharmony_ci ret = WLAN_STATUS_UNSPECIFIED_FAILURE; 68062306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 68162306a36Sopenharmony_ci "ASSOC_RESP: UNSPECIFIED failure\n"); 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci } else { 68462306a36Sopenharmony_ci ret = status_code; 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci goto done; 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci /* Send a Media Connected event, according to the Spec */ 69162306a36Sopenharmony_ci priv->media_connected = true; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci priv->adapter->ps_state = PS_STATE_AWAKE; 69462306a36Sopenharmony_ci priv->adapter->pps_uapsd_mode = false; 69562306a36Sopenharmony_ci priv->adapter->tx_lock_flag = false; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci /* Set the attempted BSSID Index to current */ 69862306a36Sopenharmony_ci bss_desc = priv->attempted_bss_desc; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, "info: ASSOC_RESP: %s\n", 70162306a36Sopenharmony_ci bss_desc->ssid.ssid); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci /* Make a copy of current BSSID descriptor */ 70462306a36Sopenharmony_ci memcpy(&priv->curr_bss_params.bss_descriptor, 70562306a36Sopenharmony_ci bss_desc, sizeof(struct mwifiex_bssdescriptor)); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci /* Update curr_bss_params */ 70862306a36Sopenharmony_ci priv->curr_bss_params.bss_descriptor.channel 70962306a36Sopenharmony_ci = bss_desc->phy_param_set.ds_param_set.current_chan; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci priv->curr_bss_params.band = (u8) bss_desc->bss_band; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci if (bss_desc->wmm_ie.vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC) 71462306a36Sopenharmony_ci priv->curr_bss_params.wmm_enabled = true; 71562306a36Sopenharmony_ci else 71662306a36Sopenharmony_ci priv->curr_bss_params.wmm_enabled = false; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci if ((priv->wmm_required || bss_desc->bcn_ht_cap) && 71962306a36Sopenharmony_ci priv->curr_bss_params.wmm_enabled) 72062306a36Sopenharmony_ci priv->wmm_enabled = true; 72162306a36Sopenharmony_ci else 72262306a36Sopenharmony_ci priv->wmm_enabled = false; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci priv->curr_bss_params.wmm_uapsd_enabled = false; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci if (priv->wmm_enabled) 72762306a36Sopenharmony_ci priv->curr_bss_params.wmm_uapsd_enabled 72862306a36Sopenharmony_ci = ((bss_desc->wmm_ie.qos_info_bitmap & 72962306a36Sopenharmony_ci IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) ? 1 : 0); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci /* Store the bandwidth information from assoc response */ 73262306a36Sopenharmony_ci ie_ptr = cfg80211_find_ie(WLAN_EID_HT_OPERATION, assoc_rsp->ie_buffer, 73362306a36Sopenharmony_ci priv->assoc_rsp_size 73462306a36Sopenharmony_ci - sizeof(struct ieee_types_assoc_rsp)); 73562306a36Sopenharmony_ci if (ie_ptr) { 73662306a36Sopenharmony_ci assoc_resp_ht_oper = (struct ieee80211_ht_operation *)(ie_ptr 73762306a36Sopenharmony_ci + sizeof(struct ieee_types_header)); 73862306a36Sopenharmony_ci priv->assoc_resp_ht_param = assoc_resp_ht_oper->ht_param; 73962306a36Sopenharmony_ci priv->ht_param_present = true; 74062306a36Sopenharmony_ci } else { 74162306a36Sopenharmony_ci priv->ht_param_present = false; 74262306a36Sopenharmony_ci } 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 74562306a36Sopenharmony_ci "info: ASSOC_RESP: curr_pkt_filter is %#x\n", 74662306a36Sopenharmony_ci priv->curr_pkt_filter); 74762306a36Sopenharmony_ci if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) 74862306a36Sopenharmony_ci priv->wpa_is_gtk_set = false; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci if (priv->wmm_enabled) { 75162306a36Sopenharmony_ci /* Don't re-enable carrier until we get the WMM_GET_STATUS 75262306a36Sopenharmony_ci event */ 75362306a36Sopenharmony_ci enable_data = false; 75462306a36Sopenharmony_ci } else { 75562306a36Sopenharmony_ci /* Since WMM is not enabled, setup the queues with the 75662306a36Sopenharmony_ci defaults */ 75762306a36Sopenharmony_ci mwifiex_wmm_setup_queue_priorities(priv, NULL); 75862306a36Sopenharmony_ci mwifiex_wmm_setup_ac_downgrade(priv); 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci if (enable_data) 76262306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 76362306a36Sopenharmony_ci "info: post association, re-enabling data flow\n"); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci /* Reset SNR/NF/RSSI values */ 76662306a36Sopenharmony_ci priv->data_rssi_last = 0; 76762306a36Sopenharmony_ci priv->data_nf_last = 0; 76862306a36Sopenharmony_ci priv->data_rssi_avg = 0; 76962306a36Sopenharmony_ci priv->data_nf_avg = 0; 77062306a36Sopenharmony_ci priv->bcn_rssi_last = 0; 77162306a36Sopenharmony_ci priv->bcn_nf_last = 0; 77262306a36Sopenharmony_ci priv->bcn_rssi_avg = 0; 77362306a36Sopenharmony_ci priv->bcn_nf_avg = 0; 77462306a36Sopenharmony_ci priv->rxpd_rate = 0; 77562306a36Sopenharmony_ci priv->rxpd_htinfo = 0; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci mwifiex_save_curr_bcn(priv); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci priv->adapter->dbg.num_cmd_assoc_success++; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, "info: ASSOC_RESP: associated\n"); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci /* Add the ra_list here for infra mode as there will be only 1 ra 78462306a36Sopenharmony_ci always */ 78562306a36Sopenharmony_ci mwifiex_ralist_add(priv, 78662306a36Sopenharmony_ci priv->curr_bss_params.bss_descriptor.mac_address); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci if (!netif_carrier_ok(priv->netdev)) 78962306a36Sopenharmony_ci netif_carrier_on(priv->netdev); 79062306a36Sopenharmony_ci mwifiex_wake_up_net_dev_queue(priv->netdev, adapter); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) 79362306a36Sopenharmony_ci priv->scan_block = true; 79462306a36Sopenharmony_ci else 79562306a36Sopenharmony_ci priv->port_open = true; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_cidone: 79862306a36Sopenharmony_ci /* Need to indicate IOCTL complete */ 79962306a36Sopenharmony_ci if (adapter->curr_cmd->wait_q_enabled) { 80062306a36Sopenharmony_ci if (ret) 80162306a36Sopenharmony_ci adapter->cmd_wait_q.status = -1; 80262306a36Sopenharmony_ci else 80362306a36Sopenharmony_ci adapter->cmd_wait_q.status = 0; 80462306a36Sopenharmony_ci } 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci return ret; 80762306a36Sopenharmony_ci} 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci/* 81062306a36Sopenharmony_ci * This function prepares command for ad-hoc start. 81162306a36Sopenharmony_ci * 81262306a36Sopenharmony_ci * Driver will fill up SSID, BSS mode, IBSS parameters, physical 81362306a36Sopenharmony_ci * parameters, probe delay, and capability information. Firmware 81462306a36Sopenharmony_ci * will fill up beacon period, basic rates and operational rates. 81562306a36Sopenharmony_ci * 81662306a36Sopenharmony_ci * In addition, the following TLVs are added - 81762306a36Sopenharmony_ci * - Channel TLV 81862306a36Sopenharmony_ci * - Vendor specific IE 81962306a36Sopenharmony_ci * - WPA/WPA2 IE 82062306a36Sopenharmony_ci * - HT Capabilities IE 82162306a36Sopenharmony_ci * - HT Information IE 82262306a36Sopenharmony_ci * 82362306a36Sopenharmony_ci * Preparation also includes - 82462306a36Sopenharmony_ci * - Setting command ID and proper size 82562306a36Sopenharmony_ci * - Ensuring correct endian-ness 82662306a36Sopenharmony_ci */ 82762306a36Sopenharmony_ciint 82862306a36Sopenharmony_cimwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, 82962306a36Sopenharmony_ci struct host_cmd_ds_command *cmd, 83062306a36Sopenharmony_ci struct cfg80211_ssid *req_ssid) 83162306a36Sopenharmony_ci{ 83262306a36Sopenharmony_ci int rsn_ie_len = 0; 83362306a36Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 83462306a36Sopenharmony_ci struct host_cmd_ds_802_11_ad_hoc_start *adhoc_start = 83562306a36Sopenharmony_ci &cmd->params.adhoc_start; 83662306a36Sopenharmony_ci struct mwifiex_bssdescriptor *bss_desc; 83762306a36Sopenharmony_ci u32 cmd_append_size = 0; 83862306a36Sopenharmony_ci u32 i; 83962306a36Sopenharmony_ci u16 tmp_cap; 84062306a36Sopenharmony_ci struct mwifiex_ie_types_chan_list_param_set *chan_tlv; 84162306a36Sopenharmony_ci u8 radio_type; 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci struct mwifiex_ie_types_htcap *ht_cap; 84462306a36Sopenharmony_ci struct mwifiex_ie_types_htinfo *ht_info; 84562306a36Sopenharmony_ci u8 *pos = (u8 *) adhoc_start + 84662306a36Sopenharmony_ci sizeof(struct host_cmd_ds_802_11_ad_hoc_start); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci if (!adapter) 84962306a36Sopenharmony_ci return -1; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_START); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci bss_desc = &priv->curr_bss_params.bss_descriptor; 85462306a36Sopenharmony_ci priv->attempted_bss_desc = bss_desc; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci /* 85762306a36Sopenharmony_ci * Fill in the parameters for 2 data structures: 85862306a36Sopenharmony_ci * 1. struct host_cmd_ds_802_11_ad_hoc_start command 85962306a36Sopenharmony_ci * 2. bss_desc 86062306a36Sopenharmony_ci * Driver will fill up SSID, bss_mode,IBSS param, Physical Param, 86162306a36Sopenharmony_ci * probe delay, and Cap info. 86262306a36Sopenharmony_ci * Firmware will fill up beacon period, Basic rates 86362306a36Sopenharmony_ci * and operational rates. 86462306a36Sopenharmony_ci */ 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci memset(adhoc_start->ssid, 0, IEEE80211_MAX_SSID_LEN); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci if (req_ssid->ssid_len > IEEE80211_MAX_SSID_LEN) 86962306a36Sopenharmony_ci req_ssid->ssid_len = IEEE80211_MAX_SSID_LEN; 87062306a36Sopenharmony_ci memcpy(adhoc_start->ssid, req_ssid->ssid, req_ssid->ssid_len); 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: SSID = %s\n", 87362306a36Sopenharmony_ci adhoc_start->ssid); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci memset(bss_desc->ssid.ssid, 0, IEEE80211_MAX_SSID_LEN); 87662306a36Sopenharmony_ci memcpy(bss_desc->ssid.ssid, req_ssid->ssid, req_ssid->ssid_len); 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci bss_desc->ssid.ssid_len = req_ssid->ssid_len; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci /* Set the BSS mode */ 88162306a36Sopenharmony_ci adhoc_start->bss_mode = HostCmd_BSS_MODE_IBSS; 88262306a36Sopenharmony_ci bss_desc->bss_mode = NL80211_IFTYPE_ADHOC; 88362306a36Sopenharmony_ci adhoc_start->beacon_period = cpu_to_le16(priv->beacon_period); 88462306a36Sopenharmony_ci bss_desc->beacon_period = priv->beacon_period; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci /* Set Physical param set */ 88762306a36Sopenharmony_ci/* Parameter IE Id */ 88862306a36Sopenharmony_ci#define DS_PARA_IE_ID 3 88962306a36Sopenharmony_ci/* Parameter IE length */ 89062306a36Sopenharmony_ci#define DS_PARA_IE_LEN 1 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci adhoc_start->phy_param_set.ds_param_set.element_id = DS_PARA_IE_ID; 89362306a36Sopenharmony_ci adhoc_start->phy_param_set.ds_param_set.len = DS_PARA_IE_LEN; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci if (!mwifiex_get_cfp(priv, adapter->adhoc_start_band, 89662306a36Sopenharmony_ci (u16) priv->adhoc_channel, 0)) { 89762306a36Sopenharmony_ci struct mwifiex_chan_freq_power *cfp; 89862306a36Sopenharmony_ci cfp = mwifiex_get_cfp(priv, adapter->adhoc_start_band, 89962306a36Sopenharmony_ci FIRST_VALID_CHANNEL, 0); 90062306a36Sopenharmony_ci if (cfp) 90162306a36Sopenharmony_ci priv->adhoc_channel = (u8) cfp->channel; 90262306a36Sopenharmony_ci } 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci if (!priv->adhoc_channel) { 90562306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 90662306a36Sopenharmony_ci "ADHOC_S_CMD: adhoc_channel cannot be 0\n"); 90762306a36Sopenharmony_ci return -1; 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci mwifiex_dbg(adapter, INFO, 91162306a36Sopenharmony_ci "info: ADHOC_S_CMD: creating ADHOC on channel %d\n", 91262306a36Sopenharmony_ci priv->adhoc_channel); 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci priv->curr_bss_params.bss_descriptor.channel = priv->adhoc_channel; 91562306a36Sopenharmony_ci priv->curr_bss_params.band = adapter->adhoc_start_band; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci bss_desc->channel = priv->adhoc_channel; 91862306a36Sopenharmony_ci adhoc_start->phy_param_set.ds_param_set.current_chan = 91962306a36Sopenharmony_ci priv->adhoc_channel; 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci memcpy(&bss_desc->phy_param_set, &adhoc_start->phy_param_set, 92262306a36Sopenharmony_ci sizeof(union ieee_types_phy_param_set)); 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci /* Set IBSS param set */ 92562306a36Sopenharmony_ci/* IBSS parameter IE Id */ 92662306a36Sopenharmony_ci#define IBSS_PARA_IE_ID 6 92762306a36Sopenharmony_ci/* IBSS parameter IE length */ 92862306a36Sopenharmony_ci#define IBSS_PARA_IE_LEN 2 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci adhoc_start->ss_param_set.ibss_param_set.element_id = IBSS_PARA_IE_ID; 93162306a36Sopenharmony_ci adhoc_start->ss_param_set.ibss_param_set.len = IBSS_PARA_IE_LEN; 93262306a36Sopenharmony_ci adhoc_start->ss_param_set.ibss_param_set.atim_window 93362306a36Sopenharmony_ci = cpu_to_le16(priv->atim_window); 93462306a36Sopenharmony_ci memcpy(&bss_desc->ss_param_set, &adhoc_start->ss_param_set, 93562306a36Sopenharmony_ci sizeof(union ieee_types_ss_param_set)); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci /* Set Capability info */ 93862306a36Sopenharmony_ci bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_IBSS; 93962306a36Sopenharmony_ci tmp_cap = WLAN_CAPABILITY_IBSS; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci /* Set up privacy in bss_desc */ 94262306a36Sopenharmony_ci if (priv->sec_info.encryption_mode) { 94362306a36Sopenharmony_ci /* Ad-Hoc capability privacy on */ 94462306a36Sopenharmony_ci mwifiex_dbg(adapter, INFO, 94562306a36Sopenharmony_ci "info: ADHOC_S_CMD: wep_status set privacy to WEP\n"); 94662306a36Sopenharmony_ci bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; 94762306a36Sopenharmony_ci tmp_cap |= WLAN_CAPABILITY_PRIVACY; 94862306a36Sopenharmony_ci } else { 94962306a36Sopenharmony_ci mwifiex_dbg(adapter, INFO, 95062306a36Sopenharmony_ci "info: ADHOC_S_CMD: wep_status NOT set,\t" 95162306a36Sopenharmony_ci "setting privacy to ACCEPT ALL\n"); 95262306a36Sopenharmony_ci bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL; 95362306a36Sopenharmony_ci } 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci memset(adhoc_start->data_rate, 0, sizeof(adhoc_start->data_rate)); 95662306a36Sopenharmony_ci mwifiex_get_active_data_rates(priv, adhoc_start->data_rate); 95762306a36Sopenharmony_ci if ((adapter->adhoc_start_band & BAND_G) && 95862306a36Sopenharmony_ci (priv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) { 95962306a36Sopenharmony_ci if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL, 96062306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, 96162306a36Sopenharmony_ci &priv->curr_pkt_filter, false)) { 96262306a36Sopenharmony_ci mwifiex_dbg(adapter, ERROR, 96362306a36Sopenharmony_ci "ADHOC_S_CMD: G Protection config failed\n"); 96462306a36Sopenharmony_ci return -1; 96562306a36Sopenharmony_ci } 96662306a36Sopenharmony_ci } 96762306a36Sopenharmony_ci /* Find the last non zero */ 96862306a36Sopenharmony_ci for (i = 0; i < sizeof(adhoc_start->data_rate); i++) 96962306a36Sopenharmony_ci if (!adhoc_start->data_rate[i]) 97062306a36Sopenharmony_ci break; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci priv->curr_bss_params.num_of_rates = i; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci /* Copy the ad-hoc creating rates into Current BSS rate structure */ 97562306a36Sopenharmony_ci memcpy(&priv->curr_bss_params.data_rates, 97662306a36Sopenharmony_ci &adhoc_start->data_rate, priv->curr_bss_params.num_of_rates); 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: rates=%4ph\n", 97962306a36Sopenharmony_ci adhoc_start->data_rate); 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: AD-HOC Start command is ready\n"); 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci if (IS_SUPPORT_MULTI_BANDS(adapter)) { 98462306a36Sopenharmony_ci /* Append a channel TLV */ 98562306a36Sopenharmony_ci chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; 98662306a36Sopenharmony_ci chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); 98762306a36Sopenharmony_ci chan_tlv->header.len = 98862306a36Sopenharmony_ci cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci memset(chan_tlv->chan_scan_param, 0x00, 99162306a36Sopenharmony_ci sizeof(struct mwifiex_chan_scan_param_set)); 99262306a36Sopenharmony_ci chan_tlv->chan_scan_param[0].chan_number = 99362306a36Sopenharmony_ci (u8) priv->curr_bss_params.bss_descriptor.channel; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: TLV Chan = %d\n", 99662306a36Sopenharmony_ci chan_tlv->chan_scan_param[0].chan_number); 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci chan_tlv->chan_scan_param[0].radio_type 99962306a36Sopenharmony_ci = mwifiex_band_to_radio_type(priv->curr_bss_params.band); 100062306a36Sopenharmony_ci if (adapter->adhoc_start_band & BAND_GN || 100162306a36Sopenharmony_ci adapter->adhoc_start_band & BAND_AN) { 100262306a36Sopenharmony_ci if (adapter->sec_chan_offset == 100362306a36Sopenharmony_ci IEEE80211_HT_PARAM_CHA_SEC_ABOVE) 100462306a36Sopenharmony_ci chan_tlv->chan_scan_param[0].radio_type |= 100562306a36Sopenharmony_ci (IEEE80211_HT_PARAM_CHA_SEC_ABOVE << 4); 100662306a36Sopenharmony_ci else if (adapter->sec_chan_offset == 100762306a36Sopenharmony_ci IEEE80211_HT_PARAM_CHA_SEC_BELOW) 100862306a36Sopenharmony_ci chan_tlv->chan_scan_param[0].radio_type |= 100962306a36Sopenharmony_ci (IEEE80211_HT_PARAM_CHA_SEC_BELOW << 4); 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: TLV Band = %d\n", 101262306a36Sopenharmony_ci chan_tlv->chan_scan_param[0].radio_type); 101362306a36Sopenharmony_ci pos += sizeof(chan_tlv->header) + 101462306a36Sopenharmony_ci sizeof(struct mwifiex_chan_scan_param_set); 101562306a36Sopenharmony_ci cmd_append_size += 101662306a36Sopenharmony_ci sizeof(chan_tlv->header) + 101762306a36Sopenharmony_ci sizeof(struct mwifiex_chan_scan_param_set); 101862306a36Sopenharmony_ci } 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci /* Append vendor specific IE TLV */ 102162306a36Sopenharmony_ci cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv, 102262306a36Sopenharmony_ci MWIFIEX_VSIE_MASK_ADHOC, &pos); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci if (priv->sec_info.wpa_enabled) { 102562306a36Sopenharmony_ci rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); 102662306a36Sopenharmony_ci if (rsn_ie_len == -1) 102762306a36Sopenharmony_ci return -1; 102862306a36Sopenharmony_ci cmd_append_size += rsn_ie_len; 102962306a36Sopenharmony_ci } 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci if (adapter->adhoc_11n_enabled) { 103262306a36Sopenharmony_ci /* Fill HT CAPABILITY */ 103362306a36Sopenharmony_ci ht_cap = (struct mwifiex_ie_types_htcap *) pos; 103462306a36Sopenharmony_ci memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap)); 103562306a36Sopenharmony_ci ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); 103662306a36Sopenharmony_ci ht_cap->header.len = 103762306a36Sopenharmony_ci cpu_to_le16(sizeof(struct ieee80211_ht_cap)); 103862306a36Sopenharmony_ci radio_type = mwifiex_band_to_radio_type( 103962306a36Sopenharmony_ci priv->adapter->config_bands); 104062306a36Sopenharmony_ci mwifiex_fill_cap_info(priv, radio_type, &ht_cap->ht_cap); 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci if (adapter->sec_chan_offset == 104362306a36Sopenharmony_ci IEEE80211_HT_PARAM_CHA_SEC_NONE) { 104462306a36Sopenharmony_ci u16 tmp_ht_cap; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci tmp_ht_cap = le16_to_cpu(ht_cap->ht_cap.cap_info); 104762306a36Sopenharmony_ci tmp_ht_cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; 104862306a36Sopenharmony_ci tmp_ht_cap &= ~IEEE80211_HT_CAP_SGI_40; 104962306a36Sopenharmony_ci ht_cap->ht_cap.cap_info = cpu_to_le16(tmp_ht_cap); 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci pos += sizeof(struct mwifiex_ie_types_htcap); 105362306a36Sopenharmony_ci cmd_append_size += sizeof(struct mwifiex_ie_types_htcap); 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci /* Fill HT INFORMATION */ 105662306a36Sopenharmony_ci ht_info = (struct mwifiex_ie_types_htinfo *) pos; 105762306a36Sopenharmony_ci memset(ht_info, 0, sizeof(struct mwifiex_ie_types_htinfo)); 105862306a36Sopenharmony_ci ht_info->header.type = cpu_to_le16(WLAN_EID_HT_OPERATION); 105962306a36Sopenharmony_ci ht_info->header.len = 106062306a36Sopenharmony_ci cpu_to_le16(sizeof(struct ieee80211_ht_operation)); 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci ht_info->ht_oper.primary_chan = 106362306a36Sopenharmony_ci (u8) priv->curr_bss_params.bss_descriptor.channel; 106462306a36Sopenharmony_ci if (adapter->sec_chan_offset) { 106562306a36Sopenharmony_ci ht_info->ht_oper.ht_param = adapter->sec_chan_offset; 106662306a36Sopenharmony_ci ht_info->ht_oper.ht_param |= 106762306a36Sopenharmony_ci IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; 106862306a36Sopenharmony_ci } 106962306a36Sopenharmony_ci ht_info->ht_oper.operation_mode = 107062306a36Sopenharmony_ci cpu_to_le16(IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); 107162306a36Sopenharmony_ci ht_info->ht_oper.basic_set[0] = 0xff; 107262306a36Sopenharmony_ci pos += sizeof(struct mwifiex_ie_types_htinfo); 107362306a36Sopenharmony_ci cmd_append_size += 107462306a36Sopenharmony_ci sizeof(struct mwifiex_ie_types_htinfo); 107562306a36Sopenharmony_ci } 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci cmd->size = 107862306a36Sopenharmony_ci cpu_to_le16((u16)(sizeof(struct host_cmd_ds_802_11_ad_hoc_start) 107962306a36Sopenharmony_ci + S_DS_GEN + cmd_append_size)); 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci if (adapter->adhoc_start_band == BAND_B) 108262306a36Sopenharmony_ci tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME; 108362306a36Sopenharmony_ci else 108462306a36Sopenharmony_ci tmp_cap |= WLAN_CAPABILITY_SHORT_SLOT_TIME; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci adhoc_start->cap_info_bitmap = cpu_to_le16(tmp_cap); 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci return 0; 108962306a36Sopenharmony_ci} 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci/* 109262306a36Sopenharmony_ci * This function prepares command for ad-hoc join. 109362306a36Sopenharmony_ci * 109462306a36Sopenharmony_ci * Most of the parameters are set up by copying from the target BSS descriptor 109562306a36Sopenharmony_ci * from the scan response. 109662306a36Sopenharmony_ci * 109762306a36Sopenharmony_ci * In addition, the following TLVs are added - 109862306a36Sopenharmony_ci * - Channel TLV 109962306a36Sopenharmony_ci * - Vendor specific IE 110062306a36Sopenharmony_ci * - WPA/WPA2 IE 110162306a36Sopenharmony_ci * - 11n IE 110262306a36Sopenharmony_ci * 110362306a36Sopenharmony_ci * Preparation also includes - 110462306a36Sopenharmony_ci * - Setting command ID and proper size 110562306a36Sopenharmony_ci * - Ensuring correct endian-ness 110662306a36Sopenharmony_ci */ 110762306a36Sopenharmony_ciint 110862306a36Sopenharmony_cimwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv, 110962306a36Sopenharmony_ci struct host_cmd_ds_command *cmd, 111062306a36Sopenharmony_ci struct mwifiex_bssdescriptor *bss_desc) 111162306a36Sopenharmony_ci{ 111262306a36Sopenharmony_ci int rsn_ie_len = 0; 111362306a36Sopenharmony_ci struct host_cmd_ds_802_11_ad_hoc_join *adhoc_join = 111462306a36Sopenharmony_ci &cmd->params.adhoc_join; 111562306a36Sopenharmony_ci struct mwifiex_ie_types_chan_list_param_set *chan_tlv; 111662306a36Sopenharmony_ci u32 cmd_append_size = 0; 111762306a36Sopenharmony_ci u16 tmp_cap; 111862306a36Sopenharmony_ci u32 i, rates_size = 0; 111962306a36Sopenharmony_ci u16 curr_pkt_filter; 112062306a36Sopenharmony_ci u8 *pos = 112162306a36Sopenharmony_ci (u8 *) adhoc_join + 112262306a36Sopenharmony_ci sizeof(struct host_cmd_ds_802_11_ad_hoc_join); 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci/* Use G protection */ 112562306a36Sopenharmony_ci#define USE_G_PROTECTION 0x02 112662306a36Sopenharmony_ci if (bss_desc->erp_flags & USE_G_PROTECTION) { 112762306a36Sopenharmony_ci curr_pkt_filter = 112862306a36Sopenharmony_ci priv-> 112962306a36Sopenharmony_ci curr_pkt_filter | HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON; 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL, 113262306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, 113362306a36Sopenharmony_ci &curr_pkt_filter, false)) { 113462306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 113562306a36Sopenharmony_ci "ADHOC_J_CMD: G Protection config failed\n"); 113662306a36Sopenharmony_ci return -1; 113762306a36Sopenharmony_ci } 113862306a36Sopenharmony_ci } 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci priv->attempted_bss_desc = bss_desc; 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_JOIN); 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci adhoc_join->bss_descriptor.bss_mode = HostCmd_BSS_MODE_IBSS; 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci adhoc_join->bss_descriptor.beacon_period 114762306a36Sopenharmony_ci = cpu_to_le16(bss_desc->beacon_period); 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci memcpy(&adhoc_join->bss_descriptor.bssid, 115062306a36Sopenharmony_ci &bss_desc->mac_address, ETH_ALEN); 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci memcpy(&adhoc_join->bss_descriptor.ssid, 115362306a36Sopenharmony_ci &bss_desc->ssid.ssid, bss_desc->ssid.ssid_len); 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci memcpy(&adhoc_join->bss_descriptor.phy_param_set, 115662306a36Sopenharmony_ci &bss_desc->phy_param_set, 115762306a36Sopenharmony_ci sizeof(union ieee_types_phy_param_set)); 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci memcpy(&adhoc_join->bss_descriptor.ss_param_set, 116062306a36Sopenharmony_ci &bss_desc->ss_param_set, sizeof(union ieee_types_ss_param_set)); 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci tmp_cap = bss_desc->cap_info_bitmap; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci tmp_cap &= CAPINFO_MASK; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 116762306a36Sopenharmony_ci "info: ADHOC_J_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n", 116862306a36Sopenharmony_ci tmp_cap, CAPINFO_MASK); 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci /* Information on BSSID descriptor passed to FW */ 117162306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 117262306a36Sopenharmony_ci "info: ADHOC_J_CMD: BSSID=%pM, SSID='%s'\n", 117362306a36Sopenharmony_ci adhoc_join->bss_descriptor.bssid, 117462306a36Sopenharmony_ci adhoc_join->bss_descriptor.ssid); 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci for (i = 0; i < MWIFIEX_SUPPORTED_RATES && 117762306a36Sopenharmony_ci bss_desc->supported_rates[i]; i++) 117862306a36Sopenharmony_ci ; 117962306a36Sopenharmony_ci rates_size = i; 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci /* Copy Data Rates from the Rates recorded in scan response */ 118262306a36Sopenharmony_ci memset(adhoc_join->bss_descriptor.data_rates, 0, 118362306a36Sopenharmony_ci sizeof(adhoc_join->bss_descriptor.data_rates)); 118462306a36Sopenharmony_ci memcpy(adhoc_join->bss_descriptor.data_rates, 118562306a36Sopenharmony_ci bss_desc->supported_rates, rates_size); 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci /* Copy the adhoc join rates into Current BSS state structure */ 118862306a36Sopenharmony_ci priv->curr_bss_params.num_of_rates = rates_size; 118962306a36Sopenharmony_ci memcpy(&priv->curr_bss_params.data_rates, bss_desc->supported_rates, 119062306a36Sopenharmony_ci rates_size); 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci /* Copy the channel information */ 119362306a36Sopenharmony_ci priv->curr_bss_params.bss_descriptor.channel = bss_desc->channel; 119462306a36Sopenharmony_ci priv->curr_bss_params.band = (u8) bss_desc->bss_band; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci if (priv->sec_info.wep_enabled || priv->sec_info.wpa_enabled) 119762306a36Sopenharmony_ci tmp_cap |= WLAN_CAPABILITY_PRIVACY; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci if (IS_SUPPORT_MULTI_BANDS(priv->adapter)) { 120062306a36Sopenharmony_ci /* Append a channel TLV */ 120162306a36Sopenharmony_ci chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; 120262306a36Sopenharmony_ci chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); 120362306a36Sopenharmony_ci chan_tlv->header.len = 120462306a36Sopenharmony_ci cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci memset(chan_tlv->chan_scan_param, 0x00, 120762306a36Sopenharmony_ci sizeof(struct mwifiex_chan_scan_param_set)); 120862306a36Sopenharmony_ci chan_tlv->chan_scan_param[0].chan_number = 120962306a36Sopenharmony_ci (bss_desc->phy_param_set.ds_param_set.current_chan); 121062306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_J_CMD: TLV Chan=%d\n", 121162306a36Sopenharmony_ci chan_tlv->chan_scan_param[0].chan_number); 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci chan_tlv->chan_scan_param[0].radio_type = 121462306a36Sopenharmony_ci mwifiex_band_to_radio_type((u8) bss_desc->bss_band); 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_J_CMD: TLV Band=%d\n", 121762306a36Sopenharmony_ci chan_tlv->chan_scan_param[0].radio_type); 121862306a36Sopenharmony_ci pos += sizeof(chan_tlv->header) + 121962306a36Sopenharmony_ci sizeof(struct mwifiex_chan_scan_param_set); 122062306a36Sopenharmony_ci cmd_append_size += sizeof(chan_tlv->header) + 122162306a36Sopenharmony_ci sizeof(struct mwifiex_chan_scan_param_set); 122262306a36Sopenharmony_ci } 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci if (priv->sec_info.wpa_enabled) 122562306a36Sopenharmony_ci rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); 122662306a36Sopenharmony_ci if (rsn_ie_len == -1) 122762306a36Sopenharmony_ci return -1; 122862306a36Sopenharmony_ci cmd_append_size += rsn_ie_len; 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info)) 123162306a36Sopenharmony_ci cmd_append_size += mwifiex_cmd_append_11n_tlv(priv, 123262306a36Sopenharmony_ci bss_desc, &pos); 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci /* Append vendor specific IE TLV */ 123562306a36Sopenharmony_ci cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv, 123662306a36Sopenharmony_ci MWIFIEX_VSIE_MASK_ADHOC, &pos); 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci cmd->size = cpu_to_le16 123962306a36Sopenharmony_ci ((u16) (sizeof(struct host_cmd_ds_802_11_ad_hoc_join) 124062306a36Sopenharmony_ci + S_DS_GEN + cmd_append_size)); 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci adhoc_join->bss_descriptor.cap_info_bitmap = cpu_to_le16(tmp_cap); 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci return 0; 124562306a36Sopenharmony_ci} 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci/* 124862306a36Sopenharmony_ci * This function handles the command response of ad-hoc start and 124962306a36Sopenharmony_ci * ad-hoc join. 125062306a36Sopenharmony_ci * 125162306a36Sopenharmony_ci * The function generates a device-connected event to notify 125262306a36Sopenharmony_ci * the applications, in case of successful ad-hoc start/join, and 125362306a36Sopenharmony_ci * saves the beacon buffer. 125462306a36Sopenharmony_ci */ 125562306a36Sopenharmony_ciint mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv, 125662306a36Sopenharmony_ci struct host_cmd_ds_command *resp) 125762306a36Sopenharmony_ci{ 125862306a36Sopenharmony_ci int ret = 0; 125962306a36Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 126062306a36Sopenharmony_ci struct host_cmd_ds_802_11_ad_hoc_start_result *start_result = 126162306a36Sopenharmony_ci &resp->params.start_result; 126262306a36Sopenharmony_ci struct host_cmd_ds_802_11_ad_hoc_join_result *join_result = 126362306a36Sopenharmony_ci &resp->params.join_result; 126462306a36Sopenharmony_ci struct mwifiex_bssdescriptor *bss_desc; 126562306a36Sopenharmony_ci u16 cmd = le16_to_cpu(resp->command); 126662306a36Sopenharmony_ci u8 result; 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci if (!priv->attempted_bss_desc) { 126962306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 127062306a36Sopenharmony_ci "ADHOC_RESP: failed, association terminated by host\n"); 127162306a36Sopenharmony_ci goto done; 127262306a36Sopenharmony_ci } 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci if (cmd == HostCmd_CMD_802_11_AD_HOC_START) 127562306a36Sopenharmony_ci result = start_result->result; 127662306a36Sopenharmony_ci else 127762306a36Sopenharmony_ci result = join_result->result; 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci bss_desc = priv->attempted_bss_desc; 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci /* Join result code 0 --> SUCCESS */ 128262306a36Sopenharmony_ci if (result) { 128362306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, "ADHOC_RESP: failed\n"); 128462306a36Sopenharmony_ci if (priv->media_connected) 128562306a36Sopenharmony_ci mwifiex_reset_connect_state(priv, result, true); 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci memset(&priv->curr_bss_params.bss_descriptor, 128862306a36Sopenharmony_ci 0x00, sizeof(struct mwifiex_bssdescriptor)); 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci ret = -1; 129162306a36Sopenharmony_ci goto done; 129262306a36Sopenharmony_ci } 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci /* Send a Media Connected event, according to the Spec */ 129562306a36Sopenharmony_ci priv->media_connected = true; 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci if (le16_to_cpu(resp->command) == HostCmd_CMD_802_11_AD_HOC_START) { 129862306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_S_RESP %s\n", 129962306a36Sopenharmony_ci bss_desc->ssid.ssid); 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci /* Update the created network descriptor with the new BSSID */ 130262306a36Sopenharmony_ci memcpy(bss_desc->mac_address, 130362306a36Sopenharmony_ci start_result->bssid, ETH_ALEN); 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci priv->adhoc_state = ADHOC_STARTED; 130662306a36Sopenharmony_ci } else { 130762306a36Sopenharmony_ci /* 130862306a36Sopenharmony_ci * Now the join cmd should be successful. 130962306a36Sopenharmony_ci * If BSSID has changed use SSID to compare instead of BSSID 131062306a36Sopenharmony_ci */ 131162306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 131262306a36Sopenharmony_ci "info: ADHOC_J_RESP %s\n", 131362306a36Sopenharmony_ci bss_desc->ssid.ssid); 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci /* 131662306a36Sopenharmony_ci * Make a copy of current BSSID descriptor, only needed for 131762306a36Sopenharmony_ci * join since the current descriptor is already being used 131862306a36Sopenharmony_ci * for adhoc start 131962306a36Sopenharmony_ci */ 132062306a36Sopenharmony_ci memcpy(&priv->curr_bss_params.bss_descriptor, 132162306a36Sopenharmony_ci bss_desc, sizeof(struct mwifiex_bssdescriptor)); 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci priv->adhoc_state = ADHOC_JOINED; 132462306a36Sopenharmony_ci } 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_RESP: channel = %d\n", 132762306a36Sopenharmony_ci priv->adhoc_channel); 132862306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_RESP: BSSID = %pM\n", 132962306a36Sopenharmony_ci priv->curr_bss_params.bss_descriptor.mac_address); 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci if (!netif_carrier_ok(priv->netdev)) 133262306a36Sopenharmony_ci netif_carrier_on(priv->netdev); 133362306a36Sopenharmony_ci mwifiex_wake_up_net_dev_queue(priv->netdev, adapter); 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci mwifiex_save_curr_bcn(priv); 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_cidone: 133862306a36Sopenharmony_ci /* Need to indicate IOCTL complete */ 133962306a36Sopenharmony_ci if (adapter->curr_cmd->wait_q_enabled) { 134062306a36Sopenharmony_ci if (ret) 134162306a36Sopenharmony_ci adapter->cmd_wait_q.status = -1; 134262306a36Sopenharmony_ci else 134362306a36Sopenharmony_ci adapter->cmd_wait_q.status = 0; 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci } 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci return ret; 134862306a36Sopenharmony_ci} 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci/* 135162306a36Sopenharmony_ci * This function associates to a specific BSS discovered in a scan. 135262306a36Sopenharmony_ci * 135362306a36Sopenharmony_ci * It clears any past association response stored for application 135462306a36Sopenharmony_ci * retrieval and calls the command preparation routine to send the 135562306a36Sopenharmony_ci * command to firmware. 135662306a36Sopenharmony_ci */ 135762306a36Sopenharmony_ciint mwifiex_associate(struct mwifiex_private *priv, 135862306a36Sopenharmony_ci struct mwifiex_bssdescriptor *bss_desc) 135962306a36Sopenharmony_ci{ 136062306a36Sopenharmony_ci /* Return error if the adapter is not STA role or table entry 136162306a36Sopenharmony_ci * is not marked as infra. 136262306a36Sopenharmony_ci */ 136362306a36Sopenharmony_ci if ((GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) || 136462306a36Sopenharmony_ci (bss_desc->bss_mode != NL80211_IFTYPE_STATION)) 136562306a36Sopenharmony_ci return -1; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) && 136862306a36Sopenharmony_ci !bss_desc->disable_11n && !bss_desc->disable_11ac && 136962306a36Sopenharmony_ci priv->adapter->config_bands & BAND_AAC) 137062306a36Sopenharmony_ci mwifiex_set_11ac_ba_params(priv); 137162306a36Sopenharmony_ci else 137262306a36Sopenharmony_ci mwifiex_set_ba_params(priv); 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci /* Clear any past association response stored for application 137562306a36Sopenharmony_ci retrieval */ 137662306a36Sopenharmony_ci priv->assoc_rsp_size = 0; 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_ASSOCIATE, 137962306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, bss_desc, true); 138062306a36Sopenharmony_ci} 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci/* 138362306a36Sopenharmony_ci * This function starts an ad-hoc network. 138462306a36Sopenharmony_ci * 138562306a36Sopenharmony_ci * It calls the command preparation routine to send the command to firmware. 138662306a36Sopenharmony_ci */ 138762306a36Sopenharmony_ciint 138862306a36Sopenharmony_cimwifiex_adhoc_start(struct mwifiex_private *priv, 138962306a36Sopenharmony_ci struct cfg80211_ssid *adhoc_ssid) 139062306a36Sopenharmony_ci{ 139162306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, "info: Adhoc Channel = %d\n", 139262306a36Sopenharmony_ci priv->adhoc_channel); 139362306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, "info: curr_bss_params.channel = %d\n", 139462306a36Sopenharmony_ci priv->curr_bss_params.bss_descriptor.channel); 139562306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, "info: curr_bss_params.band = %d\n", 139662306a36Sopenharmony_ci priv->curr_bss_params.band); 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) && 139962306a36Sopenharmony_ci priv->adapter->config_bands & BAND_AAC) 140062306a36Sopenharmony_ci mwifiex_set_11ac_ba_params(priv); 140162306a36Sopenharmony_ci else 140262306a36Sopenharmony_ci mwifiex_set_ba_params(priv); 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_START, 140562306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, adhoc_ssid, true); 140662306a36Sopenharmony_ci} 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci/* 140962306a36Sopenharmony_ci * This function joins an ad-hoc network found in a previous scan. 141062306a36Sopenharmony_ci * 141162306a36Sopenharmony_ci * It calls the command preparation routine to send the command to firmware, 141262306a36Sopenharmony_ci * if already not connected to the requested SSID. 141362306a36Sopenharmony_ci */ 141462306a36Sopenharmony_ciint mwifiex_adhoc_join(struct mwifiex_private *priv, 141562306a36Sopenharmony_ci struct mwifiex_bssdescriptor *bss_desc) 141662306a36Sopenharmony_ci{ 141762306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 141862306a36Sopenharmony_ci "info: adhoc join: curr_bss ssid =%s\n", 141962306a36Sopenharmony_ci priv->curr_bss_params.bss_descriptor.ssid.ssid); 142062306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 142162306a36Sopenharmony_ci "info: adhoc join: curr_bss ssid_len =%u\n", 142262306a36Sopenharmony_ci priv->curr_bss_params.bss_descriptor.ssid.ssid_len); 142362306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, "info: adhoc join: ssid =%s\n", 142462306a36Sopenharmony_ci bss_desc->ssid.ssid); 142562306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, "info: adhoc join: ssid_len =%u\n", 142662306a36Sopenharmony_ci bss_desc->ssid.ssid_len); 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci /* Check if the requested SSID is already joined */ 142962306a36Sopenharmony_ci if (priv->curr_bss_params.bss_descriptor.ssid.ssid_len && 143062306a36Sopenharmony_ci !mwifiex_ssid_cmp(&bss_desc->ssid, 143162306a36Sopenharmony_ci &priv->curr_bss_params.bss_descriptor.ssid) && 143262306a36Sopenharmony_ci (priv->curr_bss_params.bss_descriptor.bss_mode == 143362306a36Sopenharmony_ci NL80211_IFTYPE_ADHOC)) { 143462306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 143562306a36Sopenharmony_ci "info: ADHOC_J_CMD: new ad-hoc SSID\t" 143662306a36Sopenharmony_ci "is the same as current; not attempting to re-join\n"); 143762306a36Sopenharmony_ci return -1; 143862306a36Sopenharmony_ci } 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) && 144162306a36Sopenharmony_ci !bss_desc->disable_11n && !bss_desc->disable_11ac && 144262306a36Sopenharmony_ci priv->adapter->config_bands & BAND_AAC) 144362306a36Sopenharmony_ci mwifiex_set_11ac_ba_params(priv); 144462306a36Sopenharmony_ci else 144562306a36Sopenharmony_ci mwifiex_set_ba_params(priv); 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 144862306a36Sopenharmony_ci "info: curr_bss_params.channel = %d\n", 144962306a36Sopenharmony_ci priv->curr_bss_params.bss_descriptor.channel); 145062306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, INFO, 145162306a36Sopenharmony_ci "info: curr_bss_params.band = %c\n", 145262306a36Sopenharmony_ci priv->curr_bss_params.band); 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_JOIN, 145562306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, bss_desc, true); 145662306a36Sopenharmony_ci} 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci/* 145962306a36Sopenharmony_ci * This function deauthenticates/disconnects from infra network by sending 146062306a36Sopenharmony_ci * deauthentication request. 146162306a36Sopenharmony_ci */ 146262306a36Sopenharmony_cistatic int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, u8 *mac) 146362306a36Sopenharmony_ci{ 146462306a36Sopenharmony_ci u8 mac_address[ETH_ALEN]; 146562306a36Sopenharmony_ci int ret; 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci if (!mac || is_zero_ether_addr(mac)) 146862306a36Sopenharmony_ci memcpy(mac_address, 146962306a36Sopenharmony_ci priv->curr_bss_params.bss_descriptor.mac_address, 147062306a36Sopenharmony_ci ETH_ALEN); 147162306a36Sopenharmony_ci else 147262306a36Sopenharmony_ci memcpy(mac_address, mac, ETH_ALEN); 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_DEAUTHENTICATE, 147562306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, mac_address, true); 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci return ret; 147862306a36Sopenharmony_ci} 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci/* 148162306a36Sopenharmony_ci * This function deauthenticates/disconnects from a BSS. 148262306a36Sopenharmony_ci * 148362306a36Sopenharmony_ci * In case of infra made, it sends deauthentication request, and 148462306a36Sopenharmony_ci * in case of ad-hoc mode, a stop network request is sent to the firmware. 148562306a36Sopenharmony_ci * In AP mode, a command to stop bss is sent to firmware. 148662306a36Sopenharmony_ci */ 148762306a36Sopenharmony_ciint mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac) 148862306a36Sopenharmony_ci{ 148962306a36Sopenharmony_ci int ret = 0; 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci if (!priv->media_connected) 149262306a36Sopenharmony_ci return 0; 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci switch (priv->bss_mode) { 149562306a36Sopenharmony_ci case NL80211_IFTYPE_STATION: 149662306a36Sopenharmony_ci case NL80211_IFTYPE_P2P_CLIENT: 149762306a36Sopenharmony_ci ret = mwifiex_deauthenticate_infra(priv, mac); 149862306a36Sopenharmony_ci if (ret) 149962306a36Sopenharmony_ci cfg80211_disconnected(priv->netdev, 0, NULL, 0, 150062306a36Sopenharmony_ci true, GFP_KERNEL); 150162306a36Sopenharmony_ci break; 150262306a36Sopenharmony_ci case NL80211_IFTYPE_ADHOC: 150362306a36Sopenharmony_ci return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_STOP, 150462306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, NULL, true); 150562306a36Sopenharmony_ci case NL80211_IFTYPE_AP: 150662306a36Sopenharmony_ci return mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, 150762306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, NULL, true); 150862306a36Sopenharmony_ci default: 150962306a36Sopenharmony_ci break; 151062306a36Sopenharmony_ci } 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci return ret; 151362306a36Sopenharmony_ci} 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci/* This function deauthenticates/disconnects from all BSS. */ 151662306a36Sopenharmony_civoid mwifiex_deauthenticate_all(struct mwifiex_adapter *adapter) 151762306a36Sopenharmony_ci{ 151862306a36Sopenharmony_ci struct mwifiex_private *priv; 151962306a36Sopenharmony_ci int i; 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci for (i = 0; i < adapter->priv_num; i++) { 152262306a36Sopenharmony_ci priv = adapter->priv[i]; 152362306a36Sopenharmony_ci if (priv) 152462306a36Sopenharmony_ci mwifiex_deauthenticate(priv, NULL); 152562306a36Sopenharmony_ci } 152662306a36Sopenharmony_ci} 152762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mwifiex_deauthenticate_all); 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci/* 153062306a36Sopenharmony_ci * This function converts band to radio type used in channel TLV. 153162306a36Sopenharmony_ci */ 153262306a36Sopenharmony_ciu8 153362306a36Sopenharmony_cimwifiex_band_to_radio_type(u8 band) 153462306a36Sopenharmony_ci{ 153562306a36Sopenharmony_ci switch (band) { 153662306a36Sopenharmony_ci case BAND_A: 153762306a36Sopenharmony_ci case BAND_AN: 153862306a36Sopenharmony_ci case BAND_A | BAND_AN: 153962306a36Sopenharmony_ci case BAND_A | BAND_AN | BAND_AAC: 154062306a36Sopenharmony_ci return HostCmd_SCAN_RADIO_TYPE_A; 154162306a36Sopenharmony_ci case BAND_B: 154262306a36Sopenharmony_ci case BAND_G: 154362306a36Sopenharmony_ci case BAND_B | BAND_G: 154462306a36Sopenharmony_ci default: 154562306a36Sopenharmony_ci return HostCmd_SCAN_RADIO_TYPE_BG; 154662306a36Sopenharmony_ci } 154762306a36Sopenharmony_ci} 1548