1277b024eSKalle Valo /* 2277b024eSKalle Valo * Marvell Wireless LAN device driver: association and ad-hoc start/join 3277b024eSKalle Valo * 4277b024eSKalle Valo * Copyright (C) 2011-2014, Marvell International Ltd. 5277b024eSKalle Valo * 6277b024eSKalle Valo * This software file (the "File") is distributed by Marvell International 7277b024eSKalle Valo * Ltd. under the terms of the GNU General Public License Version 2, June 1991 8277b024eSKalle Valo * (the "License"). You may use, redistribute and/or modify this File in 9277b024eSKalle Valo * accordance with the terms and conditions of the License, a copy of which 10277b024eSKalle Valo * is available by writing to the Free Software Foundation, Inc., 11277b024eSKalle Valo * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the 12277b024eSKalle Valo * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 13277b024eSKalle Valo * 14277b024eSKalle Valo * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 15277b024eSKalle Valo * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 16277b024eSKalle Valo * ARE EXPRESSLY DISCLAIMED. The License provides additional details about 17277b024eSKalle Valo * this warranty disclaimer. 18277b024eSKalle Valo */ 19277b024eSKalle Valo 20277b024eSKalle Valo #include "decl.h" 21277b024eSKalle Valo #include "ioctl.h" 22277b024eSKalle Valo #include "util.h" 23277b024eSKalle Valo #include "fw.h" 24277b024eSKalle Valo #include "main.h" 25277b024eSKalle Valo #include "wmm.h" 26277b024eSKalle Valo #include "11n.h" 27277b024eSKalle Valo #include "11ac.h" 28277b024eSKalle Valo 29277b024eSKalle Valo #define CAPINFO_MASK (~(BIT(15) | BIT(14) | BIT(12) | BIT(11) | BIT(9))) 30277b024eSKalle Valo 31277b024eSKalle Valo /* 32277b024eSKalle Valo * Append a generic IE as a pass through TLV to a TLV buffer. 33277b024eSKalle Valo * 34277b024eSKalle Valo * This function is called from the network join command preparation routine. 35277b024eSKalle Valo * 36277b024eSKalle Valo * If the IE buffer has been setup by the application, this routine appends 37277b024eSKalle Valo * the buffer as a pass through TLV type to the request. 38277b024eSKalle Valo */ 39277b024eSKalle Valo static int 40277b024eSKalle Valo mwifiex_cmd_append_generic_ie(struct mwifiex_private *priv, u8 **buffer) 41277b024eSKalle Valo { 42277b024eSKalle Valo int ret_len = 0; 43277b024eSKalle Valo struct mwifiex_ie_types_header ie_header; 44277b024eSKalle Valo 45277b024eSKalle Valo /* Null Checks */ 46277b024eSKalle Valo if (!buffer) 47277b024eSKalle Valo return 0; 48277b024eSKalle Valo if (!(*buffer)) 49277b024eSKalle Valo return 0; 50277b024eSKalle Valo 51277b024eSKalle Valo /* 52277b024eSKalle Valo * If there is a generic ie buffer setup, append it to the return 53277b024eSKalle Valo * parameter buffer pointer. 54277b024eSKalle Valo */ 55277b024eSKalle Valo if (priv->gen_ie_buf_len) { 56277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, 57277b024eSKalle Valo "info: %s: append generic ie len %d to %p\n", 58277b024eSKalle Valo __func__, priv->gen_ie_buf_len, *buffer); 59277b024eSKalle Valo 60277b024eSKalle Valo /* Wrap the generic IE buffer with a pass through TLV type */ 61277b024eSKalle Valo ie_header.type = cpu_to_le16(TLV_TYPE_PASSTHROUGH); 62277b024eSKalle Valo ie_header.len = cpu_to_le16(priv->gen_ie_buf_len); 63277b024eSKalle Valo memcpy(*buffer, &ie_header, sizeof(ie_header)); 64277b024eSKalle Valo 65277b024eSKalle Valo /* Increment the return size and the return buffer pointer 66277b024eSKalle Valo param */ 67277b024eSKalle Valo *buffer += sizeof(ie_header); 68277b024eSKalle Valo ret_len += sizeof(ie_header); 69277b024eSKalle Valo 70277b024eSKalle Valo /* Copy the generic IE buffer to the output buffer, advance 71277b024eSKalle Valo pointer */ 72277b024eSKalle Valo memcpy(*buffer, priv->gen_ie_buf, priv->gen_ie_buf_len); 73277b024eSKalle Valo 74277b024eSKalle Valo /* Increment the return size and the return buffer pointer 75277b024eSKalle Valo param */ 76277b024eSKalle Valo *buffer += priv->gen_ie_buf_len; 77277b024eSKalle Valo ret_len += priv->gen_ie_buf_len; 78277b024eSKalle Valo 79277b024eSKalle Valo /* Reset the generic IE buffer */ 80277b024eSKalle Valo priv->gen_ie_buf_len = 0; 81277b024eSKalle Valo } 82277b024eSKalle Valo 83277b024eSKalle Valo /* return the length appended to the buffer */ 84277b024eSKalle Valo return ret_len; 85277b024eSKalle Valo } 86277b024eSKalle Valo 87277b024eSKalle Valo /* 88277b024eSKalle Valo * Append TSF tracking info from the scan table for the target AP. 89277b024eSKalle Valo * 90277b024eSKalle Valo * This function is called from the network join command preparation routine. 91277b024eSKalle Valo * 92277b024eSKalle Valo * The TSF table TSF sent to the firmware contains two TSF values: 93277b024eSKalle Valo * - The TSF of the target AP from its previous beacon/probe response 94277b024eSKalle Valo * - The TSF timestamp of our local MAC at the time we observed the 95277b024eSKalle Valo * beacon/probe response. 96277b024eSKalle Valo * 97277b024eSKalle Valo * The firmware uses the timestamp values to set an initial TSF value 98277b024eSKalle Valo * in the MAC for the new association after a reassociation attempt. 99277b024eSKalle Valo */ 100277b024eSKalle Valo static int 101277b024eSKalle Valo mwifiex_cmd_append_tsf_tlv(struct mwifiex_private *priv, u8 **buffer, 102277b024eSKalle Valo struct mwifiex_bssdescriptor *bss_desc) 103277b024eSKalle Valo { 104277b024eSKalle Valo struct mwifiex_ie_types_tsf_timestamp tsf_tlv; 105277b024eSKalle Valo __le64 tsf_val; 106277b024eSKalle Valo 107277b024eSKalle Valo /* Null Checks */ 108277b024eSKalle Valo if (buffer == NULL) 109277b024eSKalle Valo return 0; 110277b024eSKalle Valo if (*buffer == NULL) 111277b024eSKalle Valo return 0; 112277b024eSKalle Valo 113277b024eSKalle Valo memset(&tsf_tlv, 0x00, sizeof(struct mwifiex_ie_types_tsf_timestamp)); 114277b024eSKalle Valo 115277b024eSKalle Valo tsf_tlv.header.type = cpu_to_le16(TLV_TYPE_TSFTIMESTAMP); 116277b024eSKalle Valo tsf_tlv.header.len = cpu_to_le16(2 * sizeof(tsf_val)); 117277b024eSKalle Valo 118277b024eSKalle Valo memcpy(*buffer, &tsf_tlv, sizeof(tsf_tlv.header)); 119277b024eSKalle Valo *buffer += sizeof(tsf_tlv.header); 120277b024eSKalle Valo 121277b024eSKalle Valo /* TSF at the time when beacon/probe_response was received */ 122277b024eSKalle Valo tsf_val = cpu_to_le64(bss_desc->fw_tsf); 123277b024eSKalle Valo memcpy(*buffer, &tsf_val, sizeof(tsf_val)); 124277b024eSKalle Valo *buffer += sizeof(tsf_val); 125277b024eSKalle Valo 126277b024eSKalle Valo tsf_val = cpu_to_le64(bss_desc->timestamp); 127277b024eSKalle Valo 128277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, 129277b024eSKalle Valo "info: %s: TSF offset calc: %016llx - %016llx\n", 130277b024eSKalle Valo __func__, bss_desc->timestamp, bss_desc->fw_tsf); 131277b024eSKalle Valo 132277b024eSKalle Valo memcpy(*buffer, &tsf_val, sizeof(tsf_val)); 133277b024eSKalle Valo *buffer += sizeof(tsf_val); 134277b024eSKalle Valo 135277b024eSKalle Valo return sizeof(tsf_tlv.header) + (2 * sizeof(tsf_val)); 136277b024eSKalle Valo } 137277b024eSKalle Valo 138277b024eSKalle Valo /* 139277b024eSKalle Valo * This function finds out the common rates between rate1 and rate2. 140277b024eSKalle Valo * 141277b024eSKalle Valo * It will fill common rates in rate1 as output if found. 142277b024eSKalle Valo * 143277b024eSKalle Valo * NOTE: Setting the MSB of the basic rates needs to be taken 144277b024eSKalle Valo * care of, either before or after calling this function. 145277b024eSKalle Valo */ 146277b024eSKalle Valo static int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1, 147277b024eSKalle Valo u32 rate1_size, u8 *rate2, u32 rate2_size) 148277b024eSKalle Valo { 149277b024eSKalle Valo int ret; 150277b024eSKalle Valo u8 *ptr = rate1, *tmp; 151277b024eSKalle Valo u32 i, j; 152277b024eSKalle Valo 153277b024eSKalle Valo tmp = kmemdup(rate1, rate1_size, GFP_KERNEL); 154277b024eSKalle Valo if (!tmp) { 155277b024eSKalle Valo mwifiex_dbg(priv->adapter, ERROR, "failed to alloc tmp buf\n"); 156277b024eSKalle Valo return -ENOMEM; 157277b024eSKalle Valo } 158277b024eSKalle Valo 159277b024eSKalle Valo memset(rate1, 0, rate1_size); 160277b024eSKalle Valo 161277b024eSKalle Valo for (i = 0; i < rate2_size && rate2[i]; i++) { 162277b024eSKalle Valo for (j = 0; j < rate1_size && tmp[j]; j++) { 163277b024eSKalle Valo /* Check common rate, excluding the bit for 164277b024eSKalle Valo basic rate */ 165277b024eSKalle Valo if ((rate2[i] & 0x7F) == (tmp[j] & 0x7F)) { 166277b024eSKalle Valo *rate1++ = tmp[j]; 167277b024eSKalle Valo break; 168277b024eSKalle Valo } 169277b024eSKalle Valo } 170277b024eSKalle Valo } 171277b024eSKalle Valo 172277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: Tx data rate set to %#x\n", 173277b024eSKalle Valo priv->data_rate); 174277b024eSKalle Valo 175277b024eSKalle Valo if (!priv->is_data_rate_auto) { 176277b024eSKalle Valo while (*ptr) { 177277b024eSKalle Valo if ((*ptr & 0x7f) == priv->data_rate) { 178277b024eSKalle Valo ret = 0; 179277b024eSKalle Valo goto done; 180277b024eSKalle Valo } 181277b024eSKalle Valo ptr++; 182277b024eSKalle Valo } 183277b024eSKalle Valo mwifiex_dbg(priv->adapter, ERROR, 184277b024eSKalle Valo "previously set fixed data rate %#x\t" 185277b024eSKalle Valo "is not compatible with the network\n", 186277b024eSKalle Valo priv->data_rate); 187277b024eSKalle Valo 188277b024eSKalle Valo ret = -1; 189277b024eSKalle Valo goto done; 190277b024eSKalle Valo } 191277b024eSKalle Valo 192277b024eSKalle Valo ret = 0; 193277b024eSKalle Valo done: 194277b024eSKalle Valo kfree(tmp); 195277b024eSKalle Valo return ret; 196277b024eSKalle Valo } 197277b024eSKalle Valo 198277b024eSKalle Valo /* 199277b024eSKalle Valo * This function creates the intersection of the rates supported by a 200277b024eSKalle Valo * target BSS and our adapter settings for use in an assoc/join command. 201277b024eSKalle Valo */ 202277b024eSKalle Valo static int 203277b024eSKalle Valo mwifiex_setup_rates_from_bssdesc(struct mwifiex_private *priv, 204277b024eSKalle Valo struct mwifiex_bssdescriptor *bss_desc, 205277b024eSKalle Valo u8 *out_rates, u32 *out_rates_size) 206277b024eSKalle Valo { 207277b024eSKalle Valo u8 card_rates[MWIFIEX_SUPPORTED_RATES]; 208277b024eSKalle Valo u32 card_rates_size; 209277b024eSKalle Valo 210277b024eSKalle Valo /* Copy AP supported rates */ 211277b024eSKalle Valo memcpy(out_rates, bss_desc->supported_rates, MWIFIEX_SUPPORTED_RATES); 212277b024eSKalle Valo /* Get the STA supported rates */ 213277b024eSKalle Valo card_rates_size = mwifiex_get_active_data_rates(priv, card_rates); 214277b024eSKalle Valo /* Get the common rates between AP and STA supported rates */ 215277b024eSKalle Valo if (mwifiex_get_common_rates(priv, out_rates, MWIFIEX_SUPPORTED_RATES, 216277b024eSKalle Valo card_rates, card_rates_size)) { 217277b024eSKalle Valo *out_rates_size = 0; 218277b024eSKalle Valo mwifiex_dbg(priv->adapter, ERROR, 219277b024eSKalle Valo "%s: cannot get common rates\n", 220277b024eSKalle Valo __func__); 221277b024eSKalle Valo return -1; 222277b024eSKalle Valo } 223277b024eSKalle Valo 224277b024eSKalle Valo *out_rates_size = 225277b024eSKalle Valo min_t(size_t, strlen(out_rates), MWIFIEX_SUPPORTED_RATES); 226277b024eSKalle Valo 227277b024eSKalle Valo return 0; 228277b024eSKalle Valo } 229277b024eSKalle Valo 230277b024eSKalle Valo /* 231277b024eSKalle Valo * This function appends a WPS IE. It is called from the network join command 232277b024eSKalle Valo * preparation routine. 233277b024eSKalle Valo * 234277b024eSKalle Valo * If the IE buffer has been setup by the application, this routine appends 235277b024eSKalle Valo * the buffer as a WPS TLV type to the request. 236277b024eSKalle Valo */ 237277b024eSKalle Valo static int 238277b024eSKalle Valo mwifiex_cmd_append_wps_ie(struct mwifiex_private *priv, u8 **buffer) 239277b024eSKalle Valo { 240277b024eSKalle Valo int retLen = 0; 241277b024eSKalle Valo struct mwifiex_ie_types_header ie_header; 242277b024eSKalle Valo 243277b024eSKalle Valo if (!buffer || !*buffer) 244277b024eSKalle Valo return 0; 245277b024eSKalle Valo 246277b024eSKalle Valo /* 247277b024eSKalle Valo * If there is a wps ie buffer setup, append it to the return 248277b024eSKalle Valo * parameter buffer pointer. 249277b024eSKalle Valo */ 250277b024eSKalle Valo if (priv->wps_ie_len) { 251277b024eSKalle Valo mwifiex_dbg(priv->adapter, CMD, 252277b024eSKalle Valo "cmd: append wps ie %d to %p\n", 253277b024eSKalle Valo priv->wps_ie_len, *buffer); 254277b024eSKalle Valo 255277b024eSKalle Valo /* Wrap the generic IE buffer with a pass through TLV type */ 25620e5476dSXinming Hu ie_header.type = cpu_to_le16(TLV_TYPE_PASSTHROUGH); 257277b024eSKalle Valo ie_header.len = cpu_to_le16(priv->wps_ie_len); 258277b024eSKalle Valo memcpy(*buffer, &ie_header, sizeof(ie_header)); 259277b024eSKalle Valo *buffer += sizeof(ie_header); 260277b024eSKalle Valo retLen += sizeof(ie_header); 261277b024eSKalle Valo 262277b024eSKalle Valo memcpy(*buffer, priv->wps_ie, priv->wps_ie_len); 263277b024eSKalle Valo *buffer += priv->wps_ie_len; 264277b024eSKalle Valo retLen += priv->wps_ie_len; 265277b024eSKalle Valo 266277b024eSKalle Valo } 267277b024eSKalle Valo 268277b024eSKalle Valo kfree(priv->wps_ie); 269277b024eSKalle Valo priv->wps_ie_len = 0; 270277b024eSKalle Valo return retLen; 271277b024eSKalle Valo } 272277b024eSKalle Valo 273277b024eSKalle Valo /* 274277b024eSKalle Valo * This function appends a WAPI IE. 275277b024eSKalle Valo * 276277b024eSKalle Valo * This function is called from the network join command preparation routine. 277277b024eSKalle Valo * 278277b024eSKalle Valo * If the IE buffer has been setup by the application, this routine appends 279277b024eSKalle Valo * the buffer as a WAPI TLV type to the request. 280277b024eSKalle Valo */ 281277b024eSKalle Valo static int 282277b024eSKalle Valo mwifiex_cmd_append_wapi_ie(struct mwifiex_private *priv, u8 **buffer) 283277b024eSKalle Valo { 284277b024eSKalle Valo int retLen = 0; 285277b024eSKalle Valo struct mwifiex_ie_types_header ie_header; 286277b024eSKalle Valo 287277b024eSKalle Valo /* Null Checks */ 288277b024eSKalle Valo if (buffer == NULL) 289277b024eSKalle Valo return 0; 290277b024eSKalle Valo if (*buffer == NULL) 291277b024eSKalle Valo return 0; 292277b024eSKalle Valo 293277b024eSKalle Valo /* 294277b024eSKalle Valo * If there is a wapi ie buffer setup, append it to the return 295277b024eSKalle Valo * parameter buffer pointer. 296277b024eSKalle Valo */ 297277b024eSKalle Valo if (priv->wapi_ie_len) { 298277b024eSKalle Valo mwifiex_dbg(priv->adapter, CMD, 299277b024eSKalle Valo "cmd: append wapi ie %d to %p\n", 300277b024eSKalle Valo priv->wapi_ie_len, *buffer); 301277b024eSKalle Valo 302277b024eSKalle Valo /* Wrap the generic IE buffer with a pass through TLV type */ 303277b024eSKalle Valo ie_header.type = cpu_to_le16(TLV_TYPE_WAPI_IE); 304277b024eSKalle Valo ie_header.len = cpu_to_le16(priv->wapi_ie_len); 305277b024eSKalle Valo memcpy(*buffer, &ie_header, sizeof(ie_header)); 306277b024eSKalle Valo 307277b024eSKalle Valo /* Increment the return size and the return buffer pointer 308277b024eSKalle Valo param */ 309277b024eSKalle Valo *buffer += sizeof(ie_header); 310277b024eSKalle Valo retLen += sizeof(ie_header); 311277b024eSKalle Valo 312277b024eSKalle Valo /* Copy the wapi IE buffer to the output buffer, advance 313277b024eSKalle Valo pointer */ 314277b024eSKalle Valo memcpy(*buffer, priv->wapi_ie, priv->wapi_ie_len); 315277b024eSKalle Valo 316277b024eSKalle Valo /* Increment the return size and the return buffer pointer 317277b024eSKalle Valo param */ 318277b024eSKalle Valo *buffer += priv->wapi_ie_len; 319277b024eSKalle Valo retLen += priv->wapi_ie_len; 320277b024eSKalle Valo 321277b024eSKalle Valo } 322277b024eSKalle Valo /* return the length appended to the buffer */ 323277b024eSKalle Valo return retLen; 324277b024eSKalle Valo } 325277b024eSKalle Valo 326277b024eSKalle Valo /* 327277b024eSKalle Valo * This function appends rsn ie tlv for wpa/wpa2 security modes. 328277b024eSKalle Valo * It is called from the network join command preparation routine. 329277b024eSKalle Valo */ 330277b024eSKalle Valo static int mwifiex_append_rsn_ie_wpa_wpa2(struct mwifiex_private *priv, 331277b024eSKalle Valo u8 **buffer) 332277b024eSKalle Valo { 333277b024eSKalle Valo struct mwifiex_ie_types_rsn_param_set *rsn_ie_tlv; 334277b024eSKalle Valo int rsn_ie_len; 335277b024eSKalle Valo 336277b024eSKalle Valo if (!buffer || !(*buffer)) 337277b024eSKalle Valo return 0; 338277b024eSKalle Valo 339277b024eSKalle Valo rsn_ie_tlv = (struct mwifiex_ie_types_rsn_param_set *) (*buffer); 340277b024eSKalle Valo rsn_ie_tlv->header.type = cpu_to_le16((u16) priv->wpa_ie[0]); 341277b024eSKalle Valo rsn_ie_tlv->header.type = cpu_to_le16( 342277b024eSKalle Valo le16_to_cpu(rsn_ie_tlv->header.type) & 0x00FF); 343277b024eSKalle Valo rsn_ie_tlv->header.len = cpu_to_le16((u16) priv->wpa_ie[1]); 344277b024eSKalle Valo rsn_ie_tlv->header.len = cpu_to_le16(le16_to_cpu(rsn_ie_tlv->header.len) 345277b024eSKalle Valo & 0x00FF); 346277b024eSKalle Valo if (le16_to_cpu(rsn_ie_tlv->header.len) <= (sizeof(priv->wpa_ie) - 2)) 347277b024eSKalle Valo memcpy(rsn_ie_tlv->rsn_ie, &priv->wpa_ie[2], 348277b024eSKalle Valo le16_to_cpu(rsn_ie_tlv->header.len)); 349277b024eSKalle Valo else 350277b024eSKalle Valo return -1; 351277b024eSKalle Valo 352277b024eSKalle Valo rsn_ie_len = sizeof(rsn_ie_tlv->header) + 353277b024eSKalle Valo le16_to_cpu(rsn_ie_tlv->header.len); 354277b024eSKalle Valo *buffer += rsn_ie_len; 355277b024eSKalle Valo 356277b024eSKalle Valo return rsn_ie_len; 357277b024eSKalle Valo } 358277b024eSKalle Valo 359277b024eSKalle Valo /* 360277b024eSKalle Valo * This function prepares command for association. 361277b024eSKalle Valo * 362277b024eSKalle Valo * This sets the following parameters - 363277b024eSKalle Valo * - Peer MAC address 364277b024eSKalle Valo * - Listen interval 365277b024eSKalle Valo * - Beacon interval 366277b024eSKalle Valo * - Capability information 367277b024eSKalle Valo * 368277b024eSKalle Valo * ...and the following TLVs, as required - 369277b024eSKalle Valo * - SSID TLV 370277b024eSKalle Valo * - PHY TLV 371277b024eSKalle Valo * - SS TLV 372277b024eSKalle Valo * - Rates TLV 373277b024eSKalle Valo * - Authentication TLV 374277b024eSKalle Valo * - Channel TLV 375277b024eSKalle Valo * - WPA/WPA2 IE 376277b024eSKalle Valo * - 11n TLV 377277b024eSKalle Valo * - Vendor specific TLV 378277b024eSKalle Valo * - WMM TLV 379277b024eSKalle Valo * - WAPI IE 380277b024eSKalle Valo * - Generic IE 381277b024eSKalle Valo * - TSF TLV 382277b024eSKalle Valo * 383277b024eSKalle Valo * Preparation also includes - 384277b024eSKalle Valo * - Setting command ID and proper size 385277b024eSKalle Valo * - Ensuring correct endian-ness 386277b024eSKalle Valo */ 387277b024eSKalle Valo int mwifiex_cmd_802_11_associate(struct mwifiex_private *priv, 388277b024eSKalle Valo struct host_cmd_ds_command *cmd, 389277b024eSKalle Valo struct mwifiex_bssdescriptor *bss_desc) 390277b024eSKalle Valo { 391277b024eSKalle Valo struct host_cmd_ds_802_11_associate *assoc = &cmd->params.associate; 392277b024eSKalle Valo struct mwifiex_ie_types_ssid_param_set *ssid_tlv; 393277b024eSKalle Valo struct mwifiex_ie_types_phy_param_set *phy_tlv; 394277b024eSKalle Valo struct mwifiex_ie_types_ss_param_set *ss_tlv; 395277b024eSKalle Valo struct mwifiex_ie_types_rates_param_set *rates_tlv; 396277b024eSKalle Valo struct mwifiex_ie_types_auth_type *auth_tlv; 397277b024eSKalle Valo struct mwifiex_ie_types_chan_list_param_set *chan_tlv; 398277b024eSKalle Valo u8 rates[MWIFIEX_SUPPORTED_RATES]; 399277b024eSKalle Valo u32 rates_size; 400277b024eSKalle Valo u16 tmp_cap; 401277b024eSKalle Valo u8 *pos; 402277b024eSKalle Valo int rsn_ie_len = 0; 403277b024eSKalle Valo 404277b024eSKalle Valo pos = (u8 *) assoc; 405277b024eSKalle Valo 406277b024eSKalle Valo cmd->command = cpu_to_le16(HostCmd_CMD_802_11_ASSOCIATE); 407277b024eSKalle Valo 408277b024eSKalle Valo /* Save so we know which BSS Desc to use in the response handler */ 409277b024eSKalle Valo priv->attempted_bss_desc = bss_desc; 410277b024eSKalle Valo 411277b024eSKalle Valo memcpy(assoc->peer_sta_addr, 412277b024eSKalle Valo bss_desc->mac_address, sizeof(assoc->peer_sta_addr)); 413277b024eSKalle Valo pos += sizeof(assoc->peer_sta_addr); 414277b024eSKalle Valo 415277b024eSKalle Valo /* Set the listen interval */ 416277b024eSKalle Valo assoc->listen_interval = cpu_to_le16(priv->listen_interval); 417277b024eSKalle Valo /* Set the beacon period */ 418277b024eSKalle Valo assoc->beacon_period = cpu_to_le16(bss_desc->beacon_period); 419277b024eSKalle Valo 420277b024eSKalle Valo pos += sizeof(assoc->cap_info_bitmap); 421277b024eSKalle Valo pos += sizeof(assoc->listen_interval); 422277b024eSKalle Valo pos += sizeof(assoc->beacon_period); 423277b024eSKalle Valo pos += sizeof(assoc->dtim_period); 424277b024eSKalle Valo 425277b024eSKalle Valo ssid_tlv = (struct mwifiex_ie_types_ssid_param_set *) pos; 426277b024eSKalle Valo ssid_tlv->header.type = cpu_to_le16(WLAN_EID_SSID); 427277b024eSKalle Valo ssid_tlv->header.len = cpu_to_le16((u16) bss_desc->ssid.ssid_len); 428277b024eSKalle Valo memcpy(ssid_tlv->ssid, bss_desc->ssid.ssid, 429277b024eSKalle Valo le16_to_cpu(ssid_tlv->header.len)); 430277b024eSKalle Valo pos += sizeof(ssid_tlv->header) + le16_to_cpu(ssid_tlv->header.len); 431277b024eSKalle Valo 432277b024eSKalle Valo phy_tlv = (struct mwifiex_ie_types_phy_param_set *) pos; 433277b024eSKalle Valo phy_tlv->header.type = cpu_to_le16(WLAN_EID_DS_PARAMS); 434277b024eSKalle Valo phy_tlv->header.len = cpu_to_le16(sizeof(phy_tlv->fh_ds.ds_param_set)); 435277b024eSKalle Valo memcpy(&phy_tlv->fh_ds.ds_param_set, 436277b024eSKalle Valo &bss_desc->phy_param_set.ds_param_set.current_chan, 437277b024eSKalle Valo sizeof(phy_tlv->fh_ds.ds_param_set)); 438277b024eSKalle Valo pos += sizeof(phy_tlv->header) + le16_to_cpu(phy_tlv->header.len); 439277b024eSKalle Valo 440277b024eSKalle Valo ss_tlv = (struct mwifiex_ie_types_ss_param_set *) pos; 441277b024eSKalle Valo ss_tlv->header.type = cpu_to_le16(WLAN_EID_CF_PARAMS); 442277b024eSKalle Valo ss_tlv->header.len = cpu_to_le16(sizeof(ss_tlv->cf_ibss.cf_param_set)); 443277b024eSKalle Valo pos += sizeof(ss_tlv->header) + le16_to_cpu(ss_tlv->header.len); 444277b024eSKalle Valo 445277b024eSKalle Valo /* Get the common rates supported between the driver and the BSS Desc */ 446277b024eSKalle Valo if (mwifiex_setup_rates_from_bssdesc 447277b024eSKalle Valo (priv, bss_desc, rates, &rates_size)) 448277b024eSKalle Valo return -1; 449277b024eSKalle Valo 450277b024eSKalle Valo /* Save the data rates into Current BSS state structure */ 451277b024eSKalle Valo priv->curr_bss_params.num_of_rates = rates_size; 452277b024eSKalle Valo memcpy(&priv->curr_bss_params.data_rates, rates, rates_size); 453277b024eSKalle Valo 454277b024eSKalle Valo /* Setup the Rates TLV in the association command */ 455277b024eSKalle Valo rates_tlv = (struct mwifiex_ie_types_rates_param_set *) pos; 456277b024eSKalle Valo rates_tlv->header.type = cpu_to_le16(WLAN_EID_SUPP_RATES); 457277b024eSKalle Valo rates_tlv->header.len = cpu_to_le16((u16) rates_size); 458277b024eSKalle Valo memcpy(rates_tlv->rates, rates, rates_size); 459277b024eSKalle Valo pos += sizeof(rates_tlv->header) + rates_size; 460277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: ASSOC_CMD: rates size = %d\n", 461277b024eSKalle Valo rates_size); 462277b024eSKalle Valo 463277b024eSKalle Valo /* Add the Authentication type to be used for Auth frames */ 464277b024eSKalle Valo auth_tlv = (struct mwifiex_ie_types_auth_type *) pos; 465277b024eSKalle Valo auth_tlv->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); 466277b024eSKalle Valo auth_tlv->header.len = cpu_to_le16(sizeof(auth_tlv->auth_type)); 467277b024eSKalle Valo if (priv->sec_info.wep_enabled) 468277b024eSKalle Valo auth_tlv->auth_type = cpu_to_le16( 469277b024eSKalle Valo (u16) priv->sec_info.authentication_mode); 470277b024eSKalle Valo else 471277b024eSKalle Valo auth_tlv->auth_type = cpu_to_le16(NL80211_AUTHTYPE_OPEN_SYSTEM); 472277b024eSKalle Valo 473277b024eSKalle Valo pos += sizeof(auth_tlv->header) + le16_to_cpu(auth_tlv->header.len); 474277b024eSKalle Valo 475277b024eSKalle Valo if (IS_SUPPORT_MULTI_BANDS(priv->adapter) && 476277b024eSKalle Valo !(ISSUPP_11NENABLED(priv->adapter->fw_cap_info) && 477277b024eSKalle Valo (!bss_desc->disable_11n) && 478277b024eSKalle Valo (priv->adapter->config_bands & BAND_GN || 479277b024eSKalle Valo priv->adapter->config_bands & BAND_AN) && 480277b024eSKalle Valo (bss_desc->bcn_ht_cap) 481277b024eSKalle Valo ) 482277b024eSKalle Valo ) { 483277b024eSKalle Valo /* Append a channel TLV for the channel the attempted AP was 484277b024eSKalle Valo found on */ 485277b024eSKalle Valo chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; 486277b024eSKalle Valo chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); 487277b024eSKalle Valo chan_tlv->header.len = 488277b024eSKalle Valo cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); 489277b024eSKalle Valo 490277b024eSKalle Valo memset(chan_tlv->chan_scan_param, 0x00, 491277b024eSKalle Valo sizeof(struct mwifiex_chan_scan_param_set)); 492277b024eSKalle Valo chan_tlv->chan_scan_param[0].chan_number = 493277b024eSKalle Valo (bss_desc->phy_param_set.ds_param_set.current_chan); 494277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: Assoc: TLV Chan = %d\n", 495277b024eSKalle Valo chan_tlv->chan_scan_param[0].chan_number); 496277b024eSKalle Valo 497277b024eSKalle Valo chan_tlv->chan_scan_param[0].radio_type = 498277b024eSKalle Valo mwifiex_band_to_radio_type((u8) bss_desc->bss_band); 499277b024eSKalle Valo 500277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: Assoc: TLV Band = %d\n", 501277b024eSKalle Valo chan_tlv->chan_scan_param[0].radio_type); 502277b024eSKalle Valo pos += sizeof(chan_tlv->header) + 503277b024eSKalle Valo sizeof(struct mwifiex_chan_scan_param_set); 504277b024eSKalle Valo } 505277b024eSKalle Valo 506277b024eSKalle Valo if (!priv->wps.session_enable) { 507277b024eSKalle Valo if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) 508277b024eSKalle Valo rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); 509277b024eSKalle Valo 510277b024eSKalle Valo if (rsn_ie_len == -1) 511277b024eSKalle Valo return -1; 512277b024eSKalle Valo } 513277b024eSKalle Valo 514277b024eSKalle Valo if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info) && 515277b024eSKalle Valo (!bss_desc->disable_11n) && 516277b024eSKalle Valo (priv->adapter->config_bands & BAND_GN || 517277b024eSKalle Valo priv->adapter->config_bands & BAND_AN)) 518277b024eSKalle Valo mwifiex_cmd_append_11n_tlv(priv, bss_desc, &pos); 519277b024eSKalle Valo 520277b024eSKalle Valo if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) && 521277b024eSKalle Valo !bss_desc->disable_11n && !bss_desc->disable_11ac && 522277b024eSKalle Valo priv->adapter->config_bands & BAND_AAC) 523277b024eSKalle Valo mwifiex_cmd_append_11ac_tlv(priv, bss_desc, &pos); 524277b024eSKalle Valo 525277b024eSKalle Valo /* Append vendor specific IE TLV */ 526277b024eSKalle Valo mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_ASSOC, &pos); 527277b024eSKalle Valo 528277b024eSKalle Valo mwifiex_wmm_process_association_req(priv, &pos, &bss_desc->wmm_ie, 529277b024eSKalle Valo bss_desc->bcn_ht_cap); 530277b024eSKalle Valo if (priv->sec_info.wapi_enabled && priv->wapi_ie_len) 531277b024eSKalle Valo mwifiex_cmd_append_wapi_ie(priv, &pos); 532277b024eSKalle Valo 533277b024eSKalle Valo if (priv->wps.session_enable && priv->wps_ie_len) 534277b024eSKalle Valo mwifiex_cmd_append_wps_ie(priv, &pos); 535277b024eSKalle Valo 536277b024eSKalle Valo mwifiex_cmd_append_generic_ie(priv, &pos); 537277b024eSKalle Valo 538277b024eSKalle Valo mwifiex_cmd_append_tsf_tlv(priv, &pos, bss_desc); 539277b024eSKalle Valo 540277b024eSKalle Valo mwifiex_11h_process_join(priv, &pos, bss_desc); 541277b024eSKalle Valo 542277b024eSKalle Valo cmd->size = cpu_to_le16((u16) (pos - (u8 *) assoc) + S_DS_GEN); 543277b024eSKalle Valo 544277b024eSKalle Valo /* Set the Capability info at last */ 545277b024eSKalle Valo tmp_cap = bss_desc->cap_info_bitmap; 546277b024eSKalle Valo 547277b024eSKalle Valo if (priv->adapter->config_bands == BAND_B) 548277b024eSKalle Valo tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME; 549277b024eSKalle Valo 550277b024eSKalle Valo tmp_cap &= CAPINFO_MASK; 551277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, 552277b024eSKalle Valo "info: ASSOC_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n", 553277b024eSKalle Valo tmp_cap, CAPINFO_MASK); 554277b024eSKalle Valo assoc->cap_info_bitmap = cpu_to_le16(tmp_cap); 555277b024eSKalle Valo 556277b024eSKalle Valo return 0; 557277b024eSKalle Valo } 558277b024eSKalle Valo 559277b024eSKalle Valo static const char *assoc_failure_reason_to_str(u16 cap_info) 560277b024eSKalle Valo { 561277b024eSKalle Valo switch (cap_info) { 562277b024eSKalle Valo case CONNECT_ERR_AUTH_ERR_STA_FAILURE: 563277b024eSKalle Valo return "CONNECT_ERR_AUTH_ERR_STA_FAILURE"; 564277b024eSKalle Valo case CONNECT_ERR_AUTH_MSG_UNHANDLED: 565277b024eSKalle Valo return "CONNECT_ERR_AUTH_MSG_UNHANDLED"; 566277b024eSKalle Valo case CONNECT_ERR_ASSOC_ERR_TIMEOUT: 567277b024eSKalle Valo return "CONNECT_ERR_ASSOC_ERR_TIMEOUT"; 568277b024eSKalle Valo case CONNECT_ERR_ASSOC_ERR_AUTH_REFUSED: 569277b024eSKalle Valo return "CONNECT_ERR_ASSOC_ERR_AUTH_REFUSED"; 570277b024eSKalle Valo case CONNECT_ERR_STA_FAILURE: 571277b024eSKalle Valo return "CONNECT_ERR_STA_FAILURE"; 572277b024eSKalle Valo } 573277b024eSKalle Valo 574277b024eSKalle Valo return "Unknown connect failure"; 575277b024eSKalle Valo } 576277b024eSKalle Valo /* 577277b024eSKalle Valo * Association firmware command response handler 578277b024eSKalle Valo * 579277b024eSKalle Valo * The response buffer for the association command has the following 580277b024eSKalle Valo * memory layout. 581277b024eSKalle Valo * 582277b024eSKalle Valo * For cases where an association response was not received (indicated 583277b024eSKalle Valo * by the CapInfo and AId field): 584277b024eSKalle Valo * 585277b024eSKalle Valo * .------------------------------------------------------------. 586277b024eSKalle Valo * | Header(4 * sizeof(t_u16)): Standard command response hdr | 587277b024eSKalle Valo * .------------------------------------------------------------. 588277b024eSKalle Valo * | cap_info/Error Return(t_u16): | 589277b024eSKalle Valo * | 0xFFFF(-1): Internal error | 590277b024eSKalle Valo * | 0xFFFE(-2): Authentication unhandled message | 591277b024eSKalle Valo * | 0xFFFD(-3): Authentication refused | 592277b024eSKalle Valo * | 0xFFFC(-4): Timeout waiting for AP response | 593277b024eSKalle Valo * .------------------------------------------------------------. 594277b024eSKalle Valo * | status_code(t_u16): | 595277b024eSKalle Valo * | If cap_info is -1: | 596277b024eSKalle Valo * | An internal firmware failure prevented the | 597277b024eSKalle Valo * | command from being processed. The status_code | 598277b024eSKalle Valo * | will be set to 1. | 599277b024eSKalle Valo * | | 600277b024eSKalle Valo * | If cap_info is -2: | 601277b024eSKalle Valo * | An authentication frame was received but was | 602277b024eSKalle Valo * | not handled by the firmware. IEEE Status | 603277b024eSKalle Valo * | code for the failure is returned. | 604277b024eSKalle Valo * | | 605277b024eSKalle Valo * | If cap_info is -3: | 606277b024eSKalle Valo * | An authentication frame was received and the | 607277b024eSKalle Valo * | status_code is the IEEE Status reported in the | 608277b024eSKalle Valo * | response. | 609277b024eSKalle Valo * | | 610277b024eSKalle Valo * | If cap_info is -4: | 611277b024eSKalle Valo * | (1) Association response timeout | 612277b024eSKalle Valo * | (2) Authentication response timeout | 613277b024eSKalle Valo * .------------------------------------------------------------. 614277b024eSKalle Valo * | a_id(t_u16): 0xFFFF | 615277b024eSKalle Valo * .------------------------------------------------------------. 616277b024eSKalle Valo * 617277b024eSKalle Valo * 618277b024eSKalle Valo * For cases where an association response was received, the IEEE 619277b024eSKalle Valo * standard association response frame is returned: 620277b024eSKalle Valo * 621277b024eSKalle Valo * .------------------------------------------------------------. 622277b024eSKalle Valo * | Header(4 * sizeof(t_u16)): Standard command response hdr | 623277b024eSKalle Valo * .------------------------------------------------------------. 624277b024eSKalle Valo * | cap_info(t_u16): IEEE Capability | 625277b024eSKalle Valo * .------------------------------------------------------------. 626277b024eSKalle Valo * | status_code(t_u16): IEEE Status Code | 627277b024eSKalle Valo * .------------------------------------------------------------. 628277b024eSKalle Valo * | a_id(t_u16): IEEE Association ID | 629277b024eSKalle Valo * .------------------------------------------------------------. 630277b024eSKalle Valo * | IEEE IEs(variable): Any received IEs comprising the | 631277b024eSKalle Valo * | remaining portion of a received | 632277b024eSKalle Valo * | association response frame. | 633277b024eSKalle Valo * .------------------------------------------------------------. 634277b024eSKalle Valo * 635277b024eSKalle Valo * For simplistic handling, the status_code field can be used to determine 636277b024eSKalle Valo * an association success (0) or failure (non-zero). 637277b024eSKalle Valo */ 638277b024eSKalle Valo int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, 639277b024eSKalle Valo struct host_cmd_ds_command *resp) 640277b024eSKalle Valo { 641277b024eSKalle Valo struct mwifiex_adapter *adapter = priv->adapter; 642277b024eSKalle Valo int ret = 0; 643277b024eSKalle Valo struct ieee_types_assoc_rsp *assoc_rsp; 644277b024eSKalle Valo struct mwifiex_bssdescriptor *bss_desc; 645277b024eSKalle Valo bool enable_data = true; 646277b024eSKalle Valo u16 cap_info, status_code, aid; 64744ca509cSNachiket Kukade const u8 *ie_ptr; 64844ca509cSNachiket Kukade struct ieee80211_ht_operation *assoc_resp_ht_oper; 649277b024eSKalle Valo 6504699fc3fSGanapathi Bhat if (!priv->attempted_bss_desc) { 6514699fc3fSGanapathi Bhat mwifiex_dbg(priv->adapter, ERROR, 6524699fc3fSGanapathi Bhat "ASSOC_RESP: failed, association terminated by host\n"); 6534699fc3fSGanapathi Bhat goto done; 6544699fc3fSGanapathi Bhat } 6554699fc3fSGanapathi Bhat 656277b024eSKalle Valo assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params; 657277b024eSKalle Valo 658277b024eSKalle Valo cap_info = le16_to_cpu(assoc_rsp->cap_info_bitmap); 659277b024eSKalle Valo status_code = le16_to_cpu(assoc_rsp->status_code); 660277b024eSKalle Valo aid = le16_to_cpu(assoc_rsp->a_id); 661277b024eSKalle Valo 662277b024eSKalle Valo if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) 663277b024eSKalle Valo dev_err(priv->adapter->dev, 664277b024eSKalle Valo "invalid AID value 0x%x; bits 15:14 not set\n", 665277b024eSKalle Valo aid); 666277b024eSKalle Valo 667277b024eSKalle Valo aid &= ~(BIT(15) | BIT(14)); 668277b024eSKalle Valo 669277b024eSKalle Valo priv->assoc_rsp_size = min(le16_to_cpu(resp->size) - S_DS_GEN, 670277b024eSKalle Valo sizeof(priv->assoc_rsp_buf)); 671277b024eSKalle Valo 672277b024eSKalle Valo assoc_rsp->a_id = cpu_to_le16(aid); 673b64db1b2SXinming Hu memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size); 674277b024eSKalle Valo 675277b024eSKalle Valo if (status_code) { 676277b024eSKalle Valo priv->adapter->dbg.num_cmd_assoc_failure++; 677277b024eSKalle Valo mwifiex_dbg(priv->adapter, ERROR, 678277b024eSKalle Valo "ASSOC_RESP: failed,\t" 679277b024eSKalle Valo "status code=%d err=%#x a_id=%#x\n", 680277b024eSKalle Valo status_code, cap_info, 681277b024eSKalle Valo le16_to_cpu(assoc_rsp->a_id)); 682277b024eSKalle Valo 683277b024eSKalle Valo mwifiex_dbg(priv->adapter, ERROR, "assoc failure: reason %s\n", 684277b024eSKalle Valo assoc_failure_reason_to_str(cap_info)); 685277b024eSKalle Valo if (cap_info == CONNECT_ERR_ASSOC_ERR_TIMEOUT) { 686277b024eSKalle Valo if (status_code == MWIFIEX_ASSOC_CMD_FAILURE_AUTH) { 687277b024eSKalle Valo ret = WLAN_STATUS_AUTH_TIMEOUT; 688277b024eSKalle Valo mwifiex_dbg(priv->adapter, ERROR, 689277b024eSKalle Valo "ASSOC_RESP: AUTH timeout\n"); 690277b024eSKalle Valo } else { 691277b024eSKalle Valo ret = WLAN_STATUS_UNSPECIFIED_FAILURE; 692277b024eSKalle Valo mwifiex_dbg(priv->adapter, ERROR, 693277b024eSKalle Valo "ASSOC_RESP: UNSPECIFIED failure\n"); 694277b024eSKalle Valo } 695277b024eSKalle Valo } else { 696277b024eSKalle Valo ret = status_code; 697277b024eSKalle Valo } 698277b024eSKalle Valo 699277b024eSKalle Valo goto done; 700277b024eSKalle Valo } 701277b024eSKalle Valo 702277b024eSKalle Valo /* Send a Media Connected event, according to the Spec */ 703277b024eSKalle Valo priv->media_connected = true; 704277b024eSKalle Valo 705277b024eSKalle Valo priv->adapter->ps_state = PS_STATE_AWAKE; 706277b024eSKalle Valo priv->adapter->pps_uapsd_mode = false; 707277b024eSKalle Valo priv->adapter->tx_lock_flag = false; 708277b024eSKalle Valo 709277b024eSKalle Valo /* Set the attempted BSSID Index to current */ 710277b024eSKalle Valo bss_desc = priv->attempted_bss_desc; 711277b024eSKalle Valo 712277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: ASSOC_RESP: %s\n", 713277b024eSKalle Valo bss_desc->ssid.ssid); 714277b024eSKalle Valo 715277b024eSKalle Valo /* Make a copy of current BSSID descriptor */ 716277b024eSKalle Valo memcpy(&priv->curr_bss_params.bss_descriptor, 717277b024eSKalle Valo bss_desc, sizeof(struct mwifiex_bssdescriptor)); 718277b024eSKalle Valo 719277b024eSKalle Valo /* Update curr_bss_params */ 720277b024eSKalle Valo priv->curr_bss_params.bss_descriptor.channel 721277b024eSKalle Valo = bss_desc->phy_param_set.ds_param_set.current_chan; 722277b024eSKalle Valo 723277b024eSKalle Valo priv->curr_bss_params.band = (u8) bss_desc->bss_band; 724277b024eSKalle Valo 725277b024eSKalle Valo if (bss_desc->wmm_ie.vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC) 726277b024eSKalle Valo priv->curr_bss_params.wmm_enabled = true; 727277b024eSKalle Valo else 728277b024eSKalle Valo priv->curr_bss_params.wmm_enabled = false; 729277b024eSKalle Valo 730277b024eSKalle Valo if ((priv->wmm_required || bss_desc->bcn_ht_cap) && 731277b024eSKalle Valo priv->curr_bss_params.wmm_enabled) 732277b024eSKalle Valo priv->wmm_enabled = true; 733277b024eSKalle Valo else 734277b024eSKalle Valo priv->wmm_enabled = false; 735277b024eSKalle Valo 736277b024eSKalle Valo priv->curr_bss_params.wmm_uapsd_enabled = false; 737277b024eSKalle Valo 738277b024eSKalle Valo if (priv->wmm_enabled) 739277b024eSKalle Valo priv->curr_bss_params.wmm_uapsd_enabled 740277b024eSKalle Valo = ((bss_desc->wmm_ie.qos_info_bitmap & 741277b024eSKalle Valo IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) ? 1 : 0); 742277b024eSKalle Valo 74344ca509cSNachiket Kukade /* Store the bandwidth information from assoc response */ 74444ca509cSNachiket Kukade ie_ptr = cfg80211_find_ie(WLAN_EID_HT_OPERATION, assoc_rsp->ie_buffer, 74544ca509cSNachiket Kukade priv->assoc_rsp_size 74644ca509cSNachiket Kukade - sizeof(struct ieee_types_assoc_rsp)); 74744ca509cSNachiket Kukade if (ie_ptr) { 74844ca509cSNachiket Kukade assoc_resp_ht_oper = (struct ieee80211_ht_operation *)(ie_ptr 74944ca509cSNachiket Kukade + sizeof(struct ieee_types_header)); 75044ca509cSNachiket Kukade priv->assoc_resp_ht_param = assoc_resp_ht_oper->ht_param; 75144ca509cSNachiket Kukade priv->ht_param_present = true; 75244ca509cSNachiket Kukade } else { 75344ca509cSNachiket Kukade priv->ht_param_present = false; 75444ca509cSNachiket Kukade } 75544ca509cSNachiket Kukade 756277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, 757277b024eSKalle Valo "info: ASSOC_RESP: curr_pkt_filter is %#x\n", 758277b024eSKalle Valo priv->curr_pkt_filter); 759277b024eSKalle Valo if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) 760277b024eSKalle Valo priv->wpa_is_gtk_set = false; 761277b024eSKalle Valo 762277b024eSKalle Valo if (priv->wmm_enabled) { 763277b024eSKalle Valo /* Don't re-enable carrier until we get the WMM_GET_STATUS 764277b024eSKalle Valo event */ 765277b024eSKalle Valo enable_data = false; 766277b024eSKalle Valo } else { 767277b024eSKalle Valo /* Since WMM is not enabled, setup the queues with the 768277b024eSKalle Valo defaults */ 769277b024eSKalle Valo mwifiex_wmm_setup_queue_priorities(priv, NULL); 770277b024eSKalle Valo mwifiex_wmm_setup_ac_downgrade(priv); 771277b024eSKalle Valo } 772277b024eSKalle Valo 773277b024eSKalle Valo if (enable_data) 774277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, 775277b024eSKalle Valo "info: post association, re-enabling data flow\n"); 776277b024eSKalle Valo 777277b024eSKalle Valo /* Reset SNR/NF/RSSI values */ 778277b024eSKalle Valo priv->data_rssi_last = 0; 779277b024eSKalle Valo priv->data_nf_last = 0; 780277b024eSKalle Valo priv->data_rssi_avg = 0; 781277b024eSKalle Valo priv->data_nf_avg = 0; 782277b024eSKalle Valo priv->bcn_rssi_last = 0; 783277b024eSKalle Valo priv->bcn_nf_last = 0; 784277b024eSKalle Valo priv->bcn_rssi_avg = 0; 785277b024eSKalle Valo priv->bcn_nf_avg = 0; 786277b024eSKalle Valo priv->rxpd_rate = 0; 787277b024eSKalle Valo priv->rxpd_htinfo = 0; 788277b024eSKalle Valo 789277b024eSKalle Valo mwifiex_save_curr_bcn(priv); 790277b024eSKalle Valo 791277b024eSKalle Valo priv->adapter->dbg.num_cmd_assoc_success++; 792277b024eSKalle Valo 793277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: ASSOC_RESP: associated\n"); 794277b024eSKalle Valo 795277b024eSKalle Valo /* Add the ra_list here for infra mode as there will be only 1 ra 796277b024eSKalle Valo always */ 797277b024eSKalle Valo mwifiex_ralist_add(priv, 798277b024eSKalle Valo priv->curr_bss_params.bss_descriptor.mac_address); 799277b024eSKalle Valo 800277b024eSKalle Valo if (!netif_carrier_ok(priv->netdev)) 801277b024eSKalle Valo netif_carrier_on(priv->netdev); 802277b024eSKalle Valo mwifiex_wake_up_net_dev_queue(priv->netdev, adapter); 803277b024eSKalle Valo 804277b024eSKalle Valo if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) 805277b024eSKalle Valo priv->scan_block = true; 806277b024eSKalle Valo else 807277b024eSKalle Valo priv->port_open = true; 808277b024eSKalle Valo 809277b024eSKalle Valo done: 810277b024eSKalle Valo /* Need to indicate IOCTL complete */ 811277b024eSKalle Valo if (adapter->curr_cmd->wait_q_enabled) { 812277b024eSKalle Valo if (ret) 813277b024eSKalle Valo adapter->cmd_wait_q.status = -1; 814277b024eSKalle Valo else 815277b024eSKalle Valo adapter->cmd_wait_q.status = 0; 816277b024eSKalle Valo } 817277b024eSKalle Valo 818277b024eSKalle Valo return ret; 819277b024eSKalle Valo } 820277b024eSKalle Valo 821277b024eSKalle Valo /* 822277b024eSKalle Valo * This function prepares command for ad-hoc start. 823277b024eSKalle Valo * 824277b024eSKalle Valo * Driver will fill up SSID, BSS mode, IBSS parameters, physical 825277b024eSKalle Valo * parameters, probe delay, and capability information. Firmware 826277b024eSKalle Valo * will fill up beacon period, basic rates and operational rates. 827277b024eSKalle Valo * 828277b024eSKalle Valo * In addition, the following TLVs are added - 829277b024eSKalle Valo * - Channel TLV 830277b024eSKalle Valo * - Vendor specific IE 831277b024eSKalle Valo * - WPA/WPA2 IE 832277b024eSKalle Valo * - HT Capabilities IE 833277b024eSKalle Valo * - HT Information IE 834277b024eSKalle Valo * 835277b024eSKalle Valo * Preparation also includes - 836277b024eSKalle Valo * - Setting command ID and proper size 837277b024eSKalle Valo * - Ensuring correct endian-ness 838277b024eSKalle Valo */ 839277b024eSKalle Valo int 840277b024eSKalle Valo mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, 841277b024eSKalle Valo struct host_cmd_ds_command *cmd, 842277b024eSKalle Valo struct cfg80211_ssid *req_ssid) 843277b024eSKalle Valo { 844277b024eSKalle Valo int rsn_ie_len = 0; 845277b024eSKalle Valo struct mwifiex_adapter *adapter = priv->adapter; 846277b024eSKalle Valo struct host_cmd_ds_802_11_ad_hoc_start *adhoc_start = 847277b024eSKalle Valo &cmd->params.adhoc_start; 848277b024eSKalle Valo struct mwifiex_bssdescriptor *bss_desc; 849277b024eSKalle Valo u32 cmd_append_size = 0; 850277b024eSKalle Valo u32 i; 851277b024eSKalle Valo u16 tmp_cap; 852277b024eSKalle Valo struct mwifiex_ie_types_chan_list_param_set *chan_tlv; 853277b024eSKalle Valo u8 radio_type; 854277b024eSKalle Valo 855277b024eSKalle Valo struct mwifiex_ie_types_htcap *ht_cap; 856277b024eSKalle Valo struct mwifiex_ie_types_htinfo *ht_info; 857277b024eSKalle Valo u8 *pos = (u8 *) adhoc_start + 858277b024eSKalle Valo sizeof(struct host_cmd_ds_802_11_ad_hoc_start); 859277b024eSKalle Valo 860277b024eSKalle Valo if (!adapter) 861277b024eSKalle Valo return -1; 862277b024eSKalle Valo 863277b024eSKalle Valo cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_START); 864277b024eSKalle Valo 865277b024eSKalle Valo bss_desc = &priv->curr_bss_params.bss_descriptor; 866277b024eSKalle Valo priv->attempted_bss_desc = bss_desc; 867277b024eSKalle Valo 868277b024eSKalle Valo /* 869277b024eSKalle Valo * Fill in the parameters for 2 data structures: 870277b024eSKalle Valo * 1. struct host_cmd_ds_802_11_ad_hoc_start command 871277b024eSKalle Valo * 2. bss_desc 872277b024eSKalle Valo * Driver will fill up SSID, bss_mode,IBSS param, Physical Param, 873277b024eSKalle Valo * probe delay, and Cap info. 874277b024eSKalle Valo * Firmware will fill up beacon period, Basic rates 875277b024eSKalle Valo * and operational rates. 876277b024eSKalle Valo */ 877277b024eSKalle Valo 878277b024eSKalle Valo memset(adhoc_start->ssid, 0, IEEE80211_MAX_SSID_LEN); 879277b024eSKalle Valo 880277b024eSKalle Valo memcpy(adhoc_start->ssid, req_ssid->ssid, req_ssid->ssid_len); 881277b024eSKalle Valo 882277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: SSID = %s\n", 883277b024eSKalle Valo adhoc_start->ssid); 884277b024eSKalle Valo 885277b024eSKalle Valo memset(bss_desc->ssid.ssid, 0, IEEE80211_MAX_SSID_LEN); 886277b024eSKalle Valo memcpy(bss_desc->ssid.ssid, req_ssid->ssid, req_ssid->ssid_len); 887277b024eSKalle Valo 888277b024eSKalle Valo bss_desc->ssid.ssid_len = req_ssid->ssid_len; 889277b024eSKalle Valo 890277b024eSKalle Valo /* Set the BSS mode */ 891277b024eSKalle Valo adhoc_start->bss_mode = HostCmd_BSS_MODE_IBSS; 892277b024eSKalle Valo bss_desc->bss_mode = NL80211_IFTYPE_ADHOC; 893277b024eSKalle Valo adhoc_start->beacon_period = cpu_to_le16(priv->beacon_period); 894277b024eSKalle Valo bss_desc->beacon_period = priv->beacon_period; 895277b024eSKalle Valo 896277b024eSKalle Valo /* Set Physical param set */ 897277b024eSKalle Valo /* Parameter IE Id */ 898277b024eSKalle Valo #define DS_PARA_IE_ID 3 899277b024eSKalle Valo /* Parameter IE length */ 900277b024eSKalle Valo #define DS_PARA_IE_LEN 1 901277b024eSKalle Valo 902277b024eSKalle Valo adhoc_start->phy_param_set.ds_param_set.element_id = DS_PARA_IE_ID; 903277b024eSKalle Valo adhoc_start->phy_param_set.ds_param_set.len = DS_PARA_IE_LEN; 904277b024eSKalle Valo 905277b024eSKalle Valo if (!mwifiex_get_cfp(priv, adapter->adhoc_start_band, 906277b024eSKalle Valo (u16) priv->adhoc_channel, 0)) { 907277b024eSKalle Valo struct mwifiex_chan_freq_power *cfp; 908277b024eSKalle Valo cfp = mwifiex_get_cfp(priv, adapter->adhoc_start_band, 909277b024eSKalle Valo FIRST_VALID_CHANNEL, 0); 910277b024eSKalle Valo if (cfp) 911277b024eSKalle Valo priv->adhoc_channel = (u8) cfp->channel; 912277b024eSKalle Valo } 913277b024eSKalle Valo 914277b024eSKalle Valo if (!priv->adhoc_channel) { 915277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 916277b024eSKalle Valo "ADHOC_S_CMD: adhoc_channel cannot be 0\n"); 917277b024eSKalle Valo return -1; 918277b024eSKalle Valo } 919277b024eSKalle Valo 920277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 921277b024eSKalle Valo "info: ADHOC_S_CMD: creating ADHOC on channel %d\n", 922277b024eSKalle Valo priv->adhoc_channel); 923277b024eSKalle Valo 924277b024eSKalle Valo priv->curr_bss_params.bss_descriptor.channel = priv->adhoc_channel; 925277b024eSKalle Valo priv->curr_bss_params.band = adapter->adhoc_start_band; 926277b024eSKalle Valo 927277b024eSKalle Valo bss_desc->channel = priv->adhoc_channel; 928277b024eSKalle Valo adhoc_start->phy_param_set.ds_param_set.current_chan = 929277b024eSKalle Valo priv->adhoc_channel; 930277b024eSKalle Valo 931277b024eSKalle Valo memcpy(&bss_desc->phy_param_set, &adhoc_start->phy_param_set, 932277b024eSKalle Valo sizeof(union ieee_types_phy_param_set)); 933277b024eSKalle Valo 934277b024eSKalle Valo /* Set IBSS param set */ 935277b024eSKalle Valo /* IBSS parameter IE Id */ 936277b024eSKalle Valo #define IBSS_PARA_IE_ID 6 937277b024eSKalle Valo /* IBSS parameter IE length */ 938277b024eSKalle Valo #define IBSS_PARA_IE_LEN 2 939277b024eSKalle Valo 940277b024eSKalle Valo adhoc_start->ss_param_set.ibss_param_set.element_id = IBSS_PARA_IE_ID; 941277b024eSKalle Valo adhoc_start->ss_param_set.ibss_param_set.len = IBSS_PARA_IE_LEN; 942277b024eSKalle Valo adhoc_start->ss_param_set.ibss_param_set.atim_window 943277b024eSKalle Valo = cpu_to_le16(priv->atim_window); 944277b024eSKalle Valo memcpy(&bss_desc->ss_param_set, &adhoc_start->ss_param_set, 945277b024eSKalle Valo sizeof(union ieee_types_ss_param_set)); 946277b024eSKalle Valo 947277b024eSKalle Valo /* Set Capability info */ 948277b024eSKalle Valo bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_IBSS; 949277b024eSKalle Valo tmp_cap = WLAN_CAPABILITY_IBSS; 950277b024eSKalle Valo 951277b024eSKalle Valo /* Set up privacy in bss_desc */ 952277b024eSKalle Valo if (priv->sec_info.encryption_mode) { 953277b024eSKalle Valo /* Ad-Hoc capability privacy on */ 954277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 955277b024eSKalle Valo "info: ADHOC_S_CMD: wep_status set privacy to WEP\n"); 956277b024eSKalle Valo bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; 957277b024eSKalle Valo tmp_cap |= WLAN_CAPABILITY_PRIVACY; 958277b024eSKalle Valo } else { 959277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 960277b024eSKalle Valo "info: ADHOC_S_CMD: wep_status NOT set,\t" 961277b024eSKalle Valo "setting privacy to ACCEPT ALL\n"); 962277b024eSKalle Valo bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL; 963277b024eSKalle Valo } 964277b024eSKalle Valo 965277b024eSKalle Valo memset(adhoc_start->data_rate, 0, sizeof(adhoc_start->data_rate)); 966277b024eSKalle Valo mwifiex_get_active_data_rates(priv, adhoc_start->data_rate); 967277b024eSKalle Valo if ((adapter->adhoc_start_band & BAND_G) && 968277b024eSKalle Valo (priv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) { 969277b024eSKalle Valo if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL, 970277b024eSKalle Valo HostCmd_ACT_GEN_SET, 0, 971277b024eSKalle Valo &priv->curr_pkt_filter, false)) { 972277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 973277b024eSKalle Valo "ADHOC_S_CMD: G Protection config failed\n"); 974277b024eSKalle Valo return -1; 975277b024eSKalle Valo } 976277b024eSKalle Valo } 977277b024eSKalle Valo /* Find the last non zero */ 978277b024eSKalle Valo for (i = 0; i < sizeof(adhoc_start->data_rate); i++) 979277b024eSKalle Valo if (!adhoc_start->data_rate[i]) 980277b024eSKalle Valo break; 981277b024eSKalle Valo 982277b024eSKalle Valo priv->curr_bss_params.num_of_rates = i; 983277b024eSKalle Valo 984277b024eSKalle Valo /* Copy the ad-hoc creating rates into Current BSS rate structure */ 985277b024eSKalle Valo memcpy(&priv->curr_bss_params.data_rates, 986277b024eSKalle Valo &adhoc_start->data_rate, priv->curr_bss_params.num_of_rates); 987277b024eSKalle Valo 988277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: rates=%4ph\n", 989277b024eSKalle Valo adhoc_start->data_rate); 990277b024eSKalle Valo 991277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: AD-HOC Start command is ready\n"); 992277b024eSKalle Valo 993277b024eSKalle Valo if (IS_SUPPORT_MULTI_BANDS(adapter)) { 994277b024eSKalle Valo /* Append a channel TLV */ 995277b024eSKalle Valo chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; 996277b024eSKalle Valo chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); 997277b024eSKalle Valo chan_tlv->header.len = 998277b024eSKalle Valo cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); 999277b024eSKalle Valo 1000277b024eSKalle Valo memset(chan_tlv->chan_scan_param, 0x00, 1001277b024eSKalle Valo sizeof(struct mwifiex_chan_scan_param_set)); 1002277b024eSKalle Valo chan_tlv->chan_scan_param[0].chan_number = 1003277b024eSKalle Valo (u8) priv->curr_bss_params.bss_descriptor.channel; 1004277b024eSKalle Valo 1005277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: TLV Chan = %d\n", 1006277b024eSKalle Valo chan_tlv->chan_scan_param[0].chan_number); 1007277b024eSKalle Valo 1008277b024eSKalle Valo chan_tlv->chan_scan_param[0].radio_type 1009277b024eSKalle Valo = mwifiex_band_to_radio_type(priv->curr_bss_params.band); 1010277b024eSKalle Valo if (adapter->adhoc_start_band & BAND_GN || 1011277b024eSKalle Valo adapter->adhoc_start_band & BAND_AN) { 1012277b024eSKalle Valo if (adapter->sec_chan_offset == 1013277b024eSKalle Valo IEEE80211_HT_PARAM_CHA_SEC_ABOVE) 1014277b024eSKalle Valo chan_tlv->chan_scan_param[0].radio_type |= 1015277b024eSKalle Valo (IEEE80211_HT_PARAM_CHA_SEC_ABOVE << 4); 1016277b024eSKalle Valo else if (adapter->sec_chan_offset == 1017277b024eSKalle Valo IEEE80211_HT_PARAM_CHA_SEC_BELOW) 1018277b024eSKalle Valo chan_tlv->chan_scan_param[0].radio_type |= 1019277b024eSKalle Valo (IEEE80211_HT_PARAM_CHA_SEC_BELOW << 4); 1020277b024eSKalle Valo } 1021277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: TLV Band = %d\n", 1022277b024eSKalle Valo chan_tlv->chan_scan_param[0].radio_type); 1023277b024eSKalle Valo pos += sizeof(chan_tlv->header) + 1024277b024eSKalle Valo sizeof(struct mwifiex_chan_scan_param_set); 1025277b024eSKalle Valo cmd_append_size += 1026277b024eSKalle Valo sizeof(chan_tlv->header) + 1027277b024eSKalle Valo sizeof(struct mwifiex_chan_scan_param_set); 1028277b024eSKalle Valo } 1029277b024eSKalle Valo 1030277b024eSKalle Valo /* Append vendor specific IE TLV */ 1031277b024eSKalle Valo cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv, 1032277b024eSKalle Valo MWIFIEX_VSIE_MASK_ADHOC, &pos); 1033277b024eSKalle Valo 1034277b024eSKalle Valo if (priv->sec_info.wpa_enabled) { 1035277b024eSKalle Valo rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); 1036277b024eSKalle Valo if (rsn_ie_len == -1) 1037277b024eSKalle Valo return -1; 1038277b024eSKalle Valo cmd_append_size += rsn_ie_len; 1039277b024eSKalle Valo } 1040277b024eSKalle Valo 1041277b024eSKalle Valo if (adapter->adhoc_11n_enabled) { 1042277b024eSKalle Valo /* Fill HT CAPABILITY */ 1043277b024eSKalle Valo ht_cap = (struct mwifiex_ie_types_htcap *) pos; 1044277b024eSKalle Valo memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap)); 1045277b024eSKalle Valo ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); 1046277b024eSKalle Valo ht_cap->header.len = 1047277b024eSKalle Valo cpu_to_le16(sizeof(struct ieee80211_ht_cap)); 1048277b024eSKalle Valo radio_type = mwifiex_band_to_radio_type( 1049277b024eSKalle Valo priv->adapter->config_bands); 1050277b024eSKalle Valo mwifiex_fill_cap_info(priv, radio_type, &ht_cap->ht_cap); 1051277b024eSKalle Valo 1052277b024eSKalle Valo if (adapter->sec_chan_offset == 1053277b024eSKalle Valo IEEE80211_HT_PARAM_CHA_SEC_NONE) { 1054277b024eSKalle Valo u16 tmp_ht_cap; 1055277b024eSKalle Valo 1056277b024eSKalle Valo tmp_ht_cap = le16_to_cpu(ht_cap->ht_cap.cap_info); 1057277b024eSKalle Valo tmp_ht_cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; 1058277b024eSKalle Valo tmp_ht_cap &= ~IEEE80211_HT_CAP_SGI_40; 1059277b024eSKalle Valo ht_cap->ht_cap.cap_info = cpu_to_le16(tmp_ht_cap); 1060277b024eSKalle Valo } 1061277b024eSKalle Valo 1062277b024eSKalle Valo pos += sizeof(struct mwifiex_ie_types_htcap); 1063277b024eSKalle Valo cmd_append_size += sizeof(struct mwifiex_ie_types_htcap); 1064277b024eSKalle Valo 1065277b024eSKalle Valo /* Fill HT INFORMATION */ 1066277b024eSKalle Valo ht_info = (struct mwifiex_ie_types_htinfo *) pos; 1067277b024eSKalle Valo memset(ht_info, 0, sizeof(struct mwifiex_ie_types_htinfo)); 1068277b024eSKalle Valo ht_info->header.type = cpu_to_le16(WLAN_EID_HT_OPERATION); 1069277b024eSKalle Valo ht_info->header.len = 1070277b024eSKalle Valo cpu_to_le16(sizeof(struct ieee80211_ht_operation)); 1071277b024eSKalle Valo 1072277b024eSKalle Valo ht_info->ht_oper.primary_chan = 1073277b024eSKalle Valo (u8) priv->curr_bss_params.bss_descriptor.channel; 1074277b024eSKalle Valo if (adapter->sec_chan_offset) { 1075277b024eSKalle Valo ht_info->ht_oper.ht_param = adapter->sec_chan_offset; 1076277b024eSKalle Valo ht_info->ht_oper.ht_param |= 1077277b024eSKalle Valo IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; 1078277b024eSKalle Valo } 1079277b024eSKalle Valo ht_info->ht_oper.operation_mode = 1080277b024eSKalle Valo cpu_to_le16(IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); 1081277b024eSKalle Valo ht_info->ht_oper.basic_set[0] = 0xff; 1082277b024eSKalle Valo pos += sizeof(struct mwifiex_ie_types_htinfo); 1083277b024eSKalle Valo cmd_append_size += 1084277b024eSKalle Valo sizeof(struct mwifiex_ie_types_htinfo); 1085277b024eSKalle Valo } 1086277b024eSKalle Valo 1087277b024eSKalle Valo cmd->size = 1088277b024eSKalle Valo cpu_to_le16((u16)(sizeof(struct host_cmd_ds_802_11_ad_hoc_start) 1089277b024eSKalle Valo + S_DS_GEN + cmd_append_size)); 1090277b024eSKalle Valo 1091277b024eSKalle Valo if (adapter->adhoc_start_band == BAND_B) 1092277b024eSKalle Valo tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME; 1093277b024eSKalle Valo else 1094277b024eSKalle Valo tmp_cap |= WLAN_CAPABILITY_SHORT_SLOT_TIME; 1095277b024eSKalle Valo 1096277b024eSKalle Valo adhoc_start->cap_info_bitmap = cpu_to_le16(tmp_cap); 1097277b024eSKalle Valo 1098277b024eSKalle Valo return 0; 1099277b024eSKalle Valo } 1100277b024eSKalle Valo 1101277b024eSKalle Valo /* 1102277b024eSKalle Valo * This function prepares command for ad-hoc join. 1103277b024eSKalle Valo * 1104277b024eSKalle Valo * Most of the parameters are set up by copying from the target BSS descriptor 1105277b024eSKalle Valo * from the scan response. 1106277b024eSKalle Valo * 1107277b024eSKalle Valo * In addition, the following TLVs are added - 1108277b024eSKalle Valo * - Channel TLV 1109277b024eSKalle Valo * - Vendor specific IE 1110277b024eSKalle Valo * - WPA/WPA2 IE 1111277b024eSKalle Valo * - 11n IE 1112277b024eSKalle Valo * 1113277b024eSKalle Valo * Preparation also includes - 1114277b024eSKalle Valo * - Setting command ID and proper size 1115277b024eSKalle Valo * - Ensuring correct endian-ness 1116277b024eSKalle Valo */ 1117277b024eSKalle Valo int 1118277b024eSKalle Valo mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv, 1119277b024eSKalle Valo struct host_cmd_ds_command *cmd, 1120277b024eSKalle Valo struct mwifiex_bssdescriptor *bss_desc) 1121277b024eSKalle Valo { 1122277b024eSKalle Valo int rsn_ie_len = 0; 1123277b024eSKalle Valo struct host_cmd_ds_802_11_ad_hoc_join *adhoc_join = 1124277b024eSKalle Valo &cmd->params.adhoc_join; 1125277b024eSKalle Valo struct mwifiex_ie_types_chan_list_param_set *chan_tlv; 1126277b024eSKalle Valo u32 cmd_append_size = 0; 1127277b024eSKalle Valo u16 tmp_cap; 1128277b024eSKalle Valo u32 i, rates_size = 0; 1129277b024eSKalle Valo u16 curr_pkt_filter; 1130277b024eSKalle Valo u8 *pos = 1131277b024eSKalle Valo (u8 *) adhoc_join + 1132277b024eSKalle Valo sizeof(struct host_cmd_ds_802_11_ad_hoc_join); 1133277b024eSKalle Valo 1134277b024eSKalle Valo /* Use G protection */ 1135277b024eSKalle Valo #define USE_G_PROTECTION 0x02 1136277b024eSKalle Valo if (bss_desc->erp_flags & USE_G_PROTECTION) { 1137277b024eSKalle Valo curr_pkt_filter = 1138277b024eSKalle Valo priv-> 1139277b024eSKalle Valo curr_pkt_filter | HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON; 1140277b024eSKalle Valo 1141277b024eSKalle Valo if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL, 1142277b024eSKalle Valo HostCmd_ACT_GEN_SET, 0, 1143277b024eSKalle Valo &curr_pkt_filter, false)) { 1144277b024eSKalle Valo mwifiex_dbg(priv->adapter, ERROR, 1145277b024eSKalle Valo "ADHOC_J_CMD: G Protection config failed\n"); 1146277b024eSKalle Valo return -1; 1147277b024eSKalle Valo } 1148277b024eSKalle Valo } 1149277b024eSKalle Valo 1150277b024eSKalle Valo priv->attempted_bss_desc = bss_desc; 1151277b024eSKalle Valo 1152277b024eSKalle Valo cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_JOIN); 1153277b024eSKalle Valo 1154277b024eSKalle Valo adhoc_join->bss_descriptor.bss_mode = HostCmd_BSS_MODE_IBSS; 1155277b024eSKalle Valo 1156277b024eSKalle Valo adhoc_join->bss_descriptor.beacon_period 1157277b024eSKalle Valo = cpu_to_le16(bss_desc->beacon_period); 1158277b024eSKalle Valo 1159277b024eSKalle Valo memcpy(&adhoc_join->bss_descriptor.bssid, 1160277b024eSKalle Valo &bss_desc->mac_address, ETH_ALEN); 1161277b024eSKalle Valo 1162277b024eSKalle Valo memcpy(&adhoc_join->bss_descriptor.ssid, 1163277b024eSKalle Valo &bss_desc->ssid.ssid, bss_desc->ssid.ssid_len); 1164277b024eSKalle Valo 1165277b024eSKalle Valo memcpy(&adhoc_join->bss_descriptor.phy_param_set, 1166277b024eSKalle Valo &bss_desc->phy_param_set, 1167277b024eSKalle Valo sizeof(union ieee_types_phy_param_set)); 1168277b024eSKalle Valo 1169277b024eSKalle Valo memcpy(&adhoc_join->bss_descriptor.ss_param_set, 1170277b024eSKalle Valo &bss_desc->ss_param_set, sizeof(union ieee_types_ss_param_set)); 1171277b024eSKalle Valo 1172277b024eSKalle Valo tmp_cap = bss_desc->cap_info_bitmap; 1173277b024eSKalle Valo 1174277b024eSKalle Valo tmp_cap &= CAPINFO_MASK; 1175277b024eSKalle Valo 1176277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, 1177277b024eSKalle Valo "info: ADHOC_J_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n", 1178277b024eSKalle Valo tmp_cap, CAPINFO_MASK); 1179277b024eSKalle Valo 1180277b024eSKalle Valo /* Information on BSSID descriptor passed to FW */ 1181277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, 1182277b024eSKalle Valo "info: ADHOC_J_CMD: BSSID=%pM, SSID='%s'\n", 1183277b024eSKalle Valo adhoc_join->bss_descriptor.bssid, 1184277b024eSKalle Valo adhoc_join->bss_descriptor.ssid); 1185277b024eSKalle Valo 1186277b024eSKalle Valo for (i = 0; i < MWIFIEX_SUPPORTED_RATES && 1187277b024eSKalle Valo bss_desc->supported_rates[i]; i++) 1188277b024eSKalle Valo ; 1189277b024eSKalle Valo rates_size = i; 1190277b024eSKalle Valo 1191277b024eSKalle Valo /* Copy Data Rates from the Rates recorded in scan response */ 1192277b024eSKalle Valo memset(adhoc_join->bss_descriptor.data_rates, 0, 1193277b024eSKalle Valo sizeof(adhoc_join->bss_descriptor.data_rates)); 1194277b024eSKalle Valo memcpy(adhoc_join->bss_descriptor.data_rates, 1195277b024eSKalle Valo bss_desc->supported_rates, rates_size); 1196277b024eSKalle Valo 1197277b024eSKalle Valo /* Copy the adhoc join rates into Current BSS state structure */ 1198277b024eSKalle Valo priv->curr_bss_params.num_of_rates = rates_size; 1199277b024eSKalle Valo memcpy(&priv->curr_bss_params.data_rates, bss_desc->supported_rates, 1200277b024eSKalle Valo rates_size); 1201277b024eSKalle Valo 1202277b024eSKalle Valo /* Copy the channel information */ 1203277b024eSKalle Valo priv->curr_bss_params.bss_descriptor.channel = bss_desc->channel; 1204277b024eSKalle Valo priv->curr_bss_params.band = (u8) bss_desc->bss_band; 1205277b024eSKalle Valo 1206277b024eSKalle Valo if (priv->sec_info.wep_enabled || priv->sec_info.wpa_enabled) 1207277b024eSKalle Valo tmp_cap |= WLAN_CAPABILITY_PRIVACY; 1208277b024eSKalle Valo 1209277b024eSKalle Valo if (IS_SUPPORT_MULTI_BANDS(priv->adapter)) { 1210277b024eSKalle Valo /* Append a channel TLV */ 1211277b024eSKalle Valo chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; 1212277b024eSKalle Valo chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); 1213277b024eSKalle Valo chan_tlv->header.len = 1214277b024eSKalle Valo cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); 1215277b024eSKalle Valo 1216277b024eSKalle Valo memset(chan_tlv->chan_scan_param, 0x00, 1217277b024eSKalle Valo sizeof(struct mwifiex_chan_scan_param_set)); 1218277b024eSKalle Valo chan_tlv->chan_scan_param[0].chan_number = 1219277b024eSKalle Valo (bss_desc->phy_param_set.ds_param_set.current_chan); 1220277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_J_CMD: TLV Chan=%d\n", 1221277b024eSKalle Valo chan_tlv->chan_scan_param[0].chan_number); 1222277b024eSKalle Valo 1223277b024eSKalle Valo chan_tlv->chan_scan_param[0].radio_type = 1224277b024eSKalle Valo mwifiex_band_to_radio_type((u8) bss_desc->bss_band); 1225277b024eSKalle Valo 1226277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_J_CMD: TLV Band=%d\n", 1227277b024eSKalle Valo chan_tlv->chan_scan_param[0].radio_type); 1228277b024eSKalle Valo pos += sizeof(chan_tlv->header) + 1229277b024eSKalle Valo sizeof(struct mwifiex_chan_scan_param_set); 1230277b024eSKalle Valo cmd_append_size += sizeof(chan_tlv->header) + 1231277b024eSKalle Valo sizeof(struct mwifiex_chan_scan_param_set); 1232277b024eSKalle Valo } 1233277b024eSKalle Valo 1234277b024eSKalle Valo if (priv->sec_info.wpa_enabled) 1235277b024eSKalle Valo rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); 1236277b024eSKalle Valo if (rsn_ie_len == -1) 1237277b024eSKalle Valo return -1; 1238277b024eSKalle Valo cmd_append_size += rsn_ie_len; 1239277b024eSKalle Valo 1240277b024eSKalle Valo if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info)) 1241277b024eSKalle Valo cmd_append_size += mwifiex_cmd_append_11n_tlv(priv, 1242277b024eSKalle Valo bss_desc, &pos); 1243277b024eSKalle Valo 1244277b024eSKalle Valo /* Append vendor specific IE TLV */ 1245277b024eSKalle Valo cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv, 1246277b024eSKalle Valo MWIFIEX_VSIE_MASK_ADHOC, &pos); 1247277b024eSKalle Valo 1248277b024eSKalle Valo cmd->size = cpu_to_le16 1249277b024eSKalle Valo ((u16) (sizeof(struct host_cmd_ds_802_11_ad_hoc_join) 1250277b024eSKalle Valo + S_DS_GEN + cmd_append_size)); 1251277b024eSKalle Valo 1252277b024eSKalle Valo adhoc_join->bss_descriptor.cap_info_bitmap = cpu_to_le16(tmp_cap); 1253277b024eSKalle Valo 1254277b024eSKalle Valo return 0; 1255277b024eSKalle Valo } 1256277b024eSKalle Valo 1257277b024eSKalle Valo /* 1258277b024eSKalle Valo * This function handles the command response of ad-hoc start and 1259277b024eSKalle Valo * ad-hoc join. 1260277b024eSKalle Valo * 1261277b024eSKalle Valo * The function generates a device-connected event to notify 1262277b024eSKalle Valo * the applications, in case of successful ad-hoc start/join, and 1263277b024eSKalle Valo * saves the beacon buffer. 1264277b024eSKalle Valo */ 1265277b024eSKalle Valo int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv, 1266277b024eSKalle Valo struct host_cmd_ds_command *resp) 1267277b024eSKalle Valo { 1268277b024eSKalle Valo int ret = 0; 1269277b024eSKalle Valo struct mwifiex_adapter *adapter = priv->adapter; 1270d5556e87SAmitkumar Karwar struct host_cmd_ds_802_11_ad_hoc_start_result *start_result = 1271d5556e87SAmitkumar Karwar &resp->params.start_result; 1272d5556e87SAmitkumar Karwar struct host_cmd_ds_802_11_ad_hoc_join_result *join_result = 1273d5556e87SAmitkumar Karwar &resp->params.join_result; 1274277b024eSKalle Valo struct mwifiex_bssdescriptor *bss_desc; 1275d5556e87SAmitkumar Karwar u16 cmd = le16_to_cpu(resp->command); 1276d5556e87SAmitkumar Karwar u8 result; 1277277b024eSKalle Valo 12784699fc3fSGanapathi Bhat if (!priv->attempted_bss_desc) { 12794699fc3fSGanapathi Bhat mwifiex_dbg(priv->adapter, ERROR, 12804699fc3fSGanapathi Bhat "ADHOC_RESP: failed, association terminated by host\n"); 12814699fc3fSGanapathi Bhat goto done; 12824699fc3fSGanapathi Bhat } 12834699fc3fSGanapathi Bhat 1284d5556e87SAmitkumar Karwar if (cmd == HostCmd_CMD_802_11_AD_HOC_START) 1285d5556e87SAmitkumar Karwar result = start_result->result; 1286d5556e87SAmitkumar Karwar else 1287d5556e87SAmitkumar Karwar result = join_result->result; 1288277b024eSKalle Valo 1289277b024eSKalle Valo bss_desc = priv->attempted_bss_desc; 1290277b024eSKalle Valo 1291277b024eSKalle Valo /* Join result code 0 --> SUCCESS */ 1292d5556e87SAmitkumar Karwar if (result) { 1293277b024eSKalle Valo mwifiex_dbg(priv->adapter, ERROR, "ADHOC_RESP: failed\n"); 1294277b024eSKalle Valo if (priv->media_connected) 1295c62d50a4SAmitkumar Karwar mwifiex_reset_connect_state(priv, result, true); 1296277b024eSKalle Valo 1297277b024eSKalle Valo memset(&priv->curr_bss_params.bss_descriptor, 1298277b024eSKalle Valo 0x00, sizeof(struct mwifiex_bssdescriptor)); 1299277b024eSKalle Valo 1300277b024eSKalle Valo ret = -1; 1301277b024eSKalle Valo goto done; 1302277b024eSKalle Valo } 1303277b024eSKalle Valo 1304277b024eSKalle Valo /* Send a Media Connected event, according to the Spec */ 1305277b024eSKalle Valo priv->media_connected = true; 1306277b024eSKalle Valo 1307277b024eSKalle Valo if (le16_to_cpu(resp->command) == HostCmd_CMD_802_11_AD_HOC_START) { 1308277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_S_RESP %s\n", 1309277b024eSKalle Valo bss_desc->ssid.ssid); 1310277b024eSKalle Valo 1311277b024eSKalle Valo /* Update the created network descriptor with the new BSSID */ 1312277b024eSKalle Valo memcpy(bss_desc->mac_address, 1313d5556e87SAmitkumar Karwar start_result->bssid, ETH_ALEN); 1314277b024eSKalle Valo 1315277b024eSKalle Valo priv->adhoc_state = ADHOC_STARTED; 1316277b024eSKalle Valo } else { 1317277b024eSKalle Valo /* 1318277b024eSKalle Valo * Now the join cmd should be successful. 1319277b024eSKalle Valo * If BSSID has changed use SSID to compare instead of BSSID 1320277b024eSKalle Valo */ 1321277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, 1322277b024eSKalle Valo "info: ADHOC_J_RESP %s\n", 1323277b024eSKalle Valo bss_desc->ssid.ssid); 1324277b024eSKalle Valo 1325277b024eSKalle Valo /* 1326277b024eSKalle Valo * Make a copy of current BSSID descriptor, only needed for 1327277b024eSKalle Valo * join since the current descriptor is already being used 1328277b024eSKalle Valo * for adhoc start 1329277b024eSKalle Valo */ 1330277b024eSKalle Valo memcpy(&priv->curr_bss_params.bss_descriptor, 1331277b024eSKalle Valo bss_desc, sizeof(struct mwifiex_bssdescriptor)); 1332277b024eSKalle Valo 1333277b024eSKalle Valo priv->adhoc_state = ADHOC_JOINED; 1334277b024eSKalle Valo } 1335277b024eSKalle Valo 1336277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_RESP: channel = %d\n", 1337277b024eSKalle Valo priv->adhoc_channel); 1338277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_RESP: BSSID = %pM\n", 1339277b024eSKalle Valo priv->curr_bss_params.bss_descriptor.mac_address); 1340277b024eSKalle Valo 1341277b024eSKalle Valo if (!netif_carrier_ok(priv->netdev)) 1342277b024eSKalle Valo netif_carrier_on(priv->netdev); 1343277b024eSKalle Valo mwifiex_wake_up_net_dev_queue(priv->netdev, adapter); 1344277b024eSKalle Valo 1345277b024eSKalle Valo mwifiex_save_curr_bcn(priv); 1346277b024eSKalle Valo 1347277b024eSKalle Valo done: 1348277b024eSKalle Valo /* Need to indicate IOCTL complete */ 1349277b024eSKalle Valo if (adapter->curr_cmd->wait_q_enabled) { 1350277b024eSKalle Valo if (ret) 1351277b024eSKalle Valo adapter->cmd_wait_q.status = -1; 1352277b024eSKalle Valo else 1353277b024eSKalle Valo adapter->cmd_wait_q.status = 0; 1354277b024eSKalle Valo 1355277b024eSKalle Valo } 1356277b024eSKalle Valo 1357277b024eSKalle Valo return ret; 1358277b024eSKalle Valo } 1359277b024eSKalle Valo 1360277b024eSKalle Valo /* 1361277b024eSKalle Valo * This function associates to a specific BSS discovered in a scan. 1362277b024eSKalle Valo * 1363277b024eSKalle Valo * It clears any past association response stored for application 1364277b024eSKalle Valo * retrieval and calls the command preparation routine to send the 1365277b024eSKalle Valo * command to firmware. 1366277b024eSKalle Valo */ 1367277b024eSKalle Valo int mwifiex_associate(struct mwifiex_private *priv, 1368277b024eSKalle Valo struct mwifiex_bssdescriptor *bss_desc) 1369277b024eSKalle Valo { 1370277b024eSKalle Valo /* Return error if the adapter is not STA role or table entry 1371277b024eSKalle Valo * is not marked as infra. 1372277b024eSKalle Valo */ 1373277b024eSKalle Valo if ((GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) || 1374277b024eSKalle Valo (bss_desc->bss_mode != NL80211_IFTYPE_STATION)) 1375277b024eSKalle Valo return -1; 1376277b024eSKalle Valo 1377277b024eSKalle Valo if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) && 1378277b024eSKalle Valo !bss_desc->disable_11n && !bss_desc->disable_11ac && 1379277b024eSKalle Valo priv->adapter->config_bands & BAND_AAC) 1380277b024eSKalle Valo mwifiex_set_11ac_ba_params(priv); 1381277b024eSKalle Valo else 1382277b024eSKalle Valo mwifiex_set_ba_params(priv); 1383277b024eSKalle Valo 1384277b024eSKalle Valo /* Clear any past association response stored for application 1385277b024eSKalle Valo retrieval */ 1386277b024eSKalle Valo priv->assoc_rsp_size = 0; 1387277b024eSKalle Valo 1388277b024eSKalle Valo return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_ASSOCIATE, 1389277b024eSKalle Valo HostCmd_ACT_GEN_SET, 0, bss_desc, true); 1390277b024eSKalle Valo } 1391277b024eSKalle Valo 1392277b024eSKalle Valo /* 1393277b024eSKalle Valo * This function starts an ad-hoc network. 1394277b024eSKalle Valo * 1395277b024eSKalle Valo * It calls the command preparation routine to send the command to firmware. 1396277b024eSKalle Valo */ 1397277b024eSKalle Valo int 1398277b024eSKalle Valo mwifiex_adhoc_start(struct mwifiex_private *priv, 1399277b024eSKalle Valo struct cfg80211_ssid *adhoc_ssid) 1400277b024eSKalle Valo { 1401277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: Adhoc Channel = %d\n", 1402277b024eSKalle Valo priv->adhoc_channel); 1403277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: curr_bss_params.channel = %d\n", 1404277b024eSKalle Valo priv->curr_bss_params.bss_descriptor.channel); 1405277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: curr_bss_params.band = %d\n", 1406277b024eSKalle Valo priv->curr_bss_params.band); 1407277b024eSKalle Valo 1408277b024eSKalle Valo if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) && 1409277b024eSKalle Valo priv->adapter->config_bands & BAND_AAC) 1410277b024eSKalle Valo mwifiex_set_11ac_ba_params(priv); 1411277b024eSKalle Valo else 1412277b024eSKalle Valo mwifiex_set_ba_params(priv); 1413277b024eSKalle Valo 1414277b024eSKalle Valo return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_START, 1415277b024eSKalle Valo HostCmd_ACT_GEN_SET, 0, adhoc_ssid, true); 1416277b024eSKalle Valo } 1417277b024eSKalle Valo 1418277b024eSKalle Valo /* 1419277b024eSKalle Valo * This function joins an ad-hoc network found in a previous scan. 1420277b024eSKalle Valo * 1421277b024eSKalle Valo * It calls the command preparation routine to send the command to firmware, 1422277b024eSKalle Valo * if already not connected to the requested SSID. 1423277b024eSKalle Valo */ 1424277b024eSKalle Valo int mwifiex_adhoc_join(struct mwifiex_private *priv, 1425277b024eSKalle Valo struct mwifiex_bssdescriptor *bss_desc) 1426277b024eSKalle Valo { 1427277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, 1428277b024eSKalle Valo "info: adhoc join: curr_bss ssid =%s\n", 1429277b024eSKalle Valo priv->curr_bss_params.bss_descriptor.ssid.ssid); 1430277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, 1431277b024eSKalle Valo "info: adhoc join: curr_bss ssid_len =%u\n", 1432277b024eSKalle Valo priv->curr_bss_params.bss_descriptor.ssid.ssid_len); 1433277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: adhoc join: ssid =%s\n", 1434277b024eSKalle Valo bss_desc->ssid.ssid); 1435277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: adhoc join: ssid_len =%u\n", 1436277b024eSKalle Valo bss_desc->ssid.ssid_len); 1437277b024eSKalle Valo 1438277b024eSKalle Valo /* Check if the requested SSID is already joined */ 1439277b024eSKalle Valo if (priv->curr_bss_params.bss_descriptor.ssid.ssid_len && 1440277b024eSKalle Valo !mwifiex_ssid_cmp(&bss_desc->ssid, 1441277b024eSKalle Valo &priv->curr_bss_params.bss_descriptor.ssid) && 1442277b024eSKalle Valo (priv->curr_bss_params.bss_descriptor.bss_mode == 1443277b024eSKalle Valo NL80211_IFTYPE_ADHOC)) { 1444277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, 1445277b024eSKalle Valo "info: ADHOC_J_CMD: new ad-hoc SSID\t" 1446277b024eSKalle Valo "is the same as current; not attempting to re-join\n"); 1447277b024eSKalle Valo return -1; 1448277b024eSKalle Valo } 1449277b024eSKalle Valo 1450277b024eSKalle Valo if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) && 1451277b024eSKalle Valo !bss_desc->disable_11n && !bss_desc->disable_11ac && 1452277b024eSKalle Valo priv->adapter->config_bands & BAND_AAC) 1453277b024eSKalle Valo mwifiex_set_11ac_ba_params(priv); 1454277b024eSKalle Valo else 1455277b024eSKalle Valo mwifiex_set_ba_params(priv); 1456277b024eSKalle Valo 1457277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, 1458277b024eSKalle Valo "info: curr_bss_params.channel = %d\n", 1459277b024eSKalle Valo priv->curr_bss_params.bss_descriptor.channel); 1460277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, 1461277b024eSKalle Valo "info: curr_bss_params.band = %c\n", 1462277b024eSKalle Valo priv->curr_bss_params.band); 1463277b024eSKalle Valo 1464277b024eSKalle Valo return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_JOIN, 1465277b024eSKalle Valo HostCmd_ACT_GEN_SET, 0, bss_desc, true); 1466277b024eSKalle Valo } 1467277b024eSKalle Valo 1468277b024eSKalle Valo /* 1469277b024eSKalle Valo * This function deauthenticates/disconnects from infra network by sending 1470277b024eSKalle Valo * deauthentication request. 1471277b024eSKalle Valo */ 1472277b024eSKalle Valo static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, u8 *mac) 1473277b024eSKalle Valo { 1474277b024eSKalle Valo u8 mac_address[ETH_ALEN]; 1475277b024eSKalle Valo int ret; 1476277b024eSKalle Valo 1477277b024eSKalle Valo if (!mac || is_zero_ether_addr(mac)) 1478277b024eSKalle Valo memcpy(mac_address, 1479277b024eSKalle Valo priv->curr_bss_params.bss_descriptor.mac_address, 1480277b024eSKalle Valo ETH_ALEN); 1481277b024eSKalle Valo else 1482277b024eSKalle Valo memcpy(mac_address, mac, ETH_ALEN); 1483277b024eSKalle Valo 1484277b024eSKalle Valo ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_DEAUTHENTICATE, 1485277b024eSKalle Valo HostCmd_ACT_GEN_SET, 0, mac_address, true); 1486277b024eSKalle Valo 1487277b024eSKalle Valo return ret; 1488277b024eSKalle Valo } 1489277b024eSKalle Valo 1490277b024eSKalle Valo /* 1491277b024eSKalle Valo * This function deauthenticates/disconnects from a BSS. 1492277b024eSKalle Valo * 1493277b024eSKalle Valo * In case of infra made, it sends deauthentication request, and 1494277b024eSKalle Valo * in case of ad-hoc mode, a stop network request is sent to the firmware. 1495277b024eSKalle Valo * In AP mode, a command to stop bss is sent to firmware. 1496277b024eSKalle Valo */ 1497277b024eSKalle Valo int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac) 1498277b024eSKalle Valo { 1499277b024eSKalle Valo int ret = 0; 1500277b024eSKalle Valo 1501277b024eSKalle Valo if (!priv->media_connected) 1502277b024eSKalle Valo return 0; 1503277b024eSKalle Valo 1504277b024eSKalle Valo switch (priv->bss_mode) { 1505277b024eSKalle Valo case NL80211_IFTYPE_STATION: 1506277b024eSKalle Valo case NL80211_IFTYPE_P2P_CLIENT: 1507277b024eSKalle Valo ret = mwifiex_deauthenticate_infra(priv, mac); 1508277b024eSKalle Valo if (ret) 1509277b024eSKalle Valo cfg80211_disconnected(priv->netdev, 0, NULL, 0, 1510277b024eSKalle Valo true, GFP_KERNEL); 1511277b024eSKalle Valo break; 1512277b024eSKalle Valo case NL80211_IFTYPE_ADHOC: 1513277b024eSKalle Valo return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_STOP, 1514277b024eSKalle Valo HostCmd_ACT_GEN_SET, 0, NULL, true); 1515277b024eSKalle Valo case NL80211_IFTYPE_AP: 1516277b024eSKalle Valo return mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, 1517277b024eSKalle Valo HostCmd_ACT_GEN_SET, 0, NULL, true); 1518277b024eSKalle Valo default: 1519277b024eSKalle Valo break; 1520277b024eSKalle Valo } 1521277b024eSKalle Valo 1522277b024eSKalle Valo return ret; 1523277b024eSKalle Valo } 1524277b024eSKalle Valo 1525277b024eSKalle Valo /* This function deauthenticates/disconnects from all BSS. */ 1526277b024eSKalle Valo void mwifiex_deauthenticate_all(struct mwifiex_adapter *adapter) 1527277b024eSKalle Valo { 1528277b024eSKalle Valo struct mwifiex_private *priv; 1529277b024eSKalle Valo int i; 1530277b024eSKalle Valo 1531277b024eSKalle Valo for (i = 0; i < adapter->priv_num; i++) { 1532277b024eSKalle Valo priv = adapter->priv[i]; 1533277b024eSKalle Valo if (priv) 1534277b024eSKalle Valo mwifiex_deauthenticate(priv, NULL); 1535277b024eSKalle Valo } 1536277b024eSKalle Valo } 1537277b024eSKalle Valo EXPORT_SYMBOL_GPL(mwifiex_deauthenticate_all); 1538277b024eSKalle Valo 1539277b024eSKalle Valo /* 1540277b024eSKalle Valo * This function converts band to radio type used in channel TLV. 1541277b024eSKalle Valo */ 1542277b024eSKalle Valo u8 1543277b024eSKalle Valo mwifiex_band_to_radio_type(u8 band) 1544277b024eSKalle Valo { 1545277b024eSKalle Valo switch (band) { 1546277b024eSKalle Valo case BAND_A: 1547277b024eSKalle Valo case BAND_AN: 1548277b024eSKalle Valo case BAND_A | BAND_AN: 1549277b024eSKalle Valo case BAND_A | BAND_AN | BAND_AAC: 1550277b024eSKalle Valo return HostCmd_SCAN_RADIO_TYPE_A; 1551277b024eSKalle Valo case BAND_B: 1552277b024eSKalle Valo case BAND_G: 1553277b024eSKalle Valo case BAND_B | BAND_G: 1554277b024eSKalle Valo default: 1555277b024eSKalle Valo return HostCmd_SCAN_RADIO_TYPE_BG; 1556277b024eSKalle Valo } 1557277b024eSKalle Valo } 1558