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 */ 256277b024eSKalle Valo ie_header.type = cpu_to_le16(TLV_TYPE_MGMT_IE); 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; 647277b024eSKalle Valo 648277b024eSKalle Valo assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params; 649277b024eSKalle Valo 650277b024eSKalle Valo cap_info = le16_to_cpu(assoc_rsp->cap_info_bitmap); 651277b024eSKalle Valo status_code = le16_to_cpu(assoc_rsp->status_code); 652277b024eSKalle Valo aid = le16_to_cpu(assoc_rsp->a_id); 653277b024eSKalle Valo 654277b024eSKalle Valo if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) 655277b024eSKalle Valo dev_err(priv->adapter->dev, 656277b024eSKalle Valo "invalid AID value 0x%x; bits 15:14 not set\n", 657277b024eSKalle Valo aid); 658277b024eSKalle Valo 659277b024eSKalle Valo aid &= ~(BIT(15) | BIT(14)); 660277b024eSKalle Valo 661277b024eSKalle Valo priv->assoc_rsp_size = min(le16_to_cpu(resp->size) - S_DS_GEN, 662277b024eSKalle Valo sizeof(priv->assoc_rsp_buf)); 663277b024eSKalle Valo 664277b024eSKalle Valo memcpy(priv->assoc_rsp_buf, &resp->params, priv->assoc_rsp_size); 665277b024eSKalle Valo 666277b024eSKalle Valo assoc_rsp->a_id = cpu_to_le16(aid); 667277b024eSKalle Valo 668277b024eSKalle Valo if (status_code) { 669277b024eSKalle Valo priv->adapter->dbg.num_cmd_assoc_failure++; 670277b024eSKalle Valo mwifiex_dbg(priv->adapter, ERROR, 671277b024eSKalle Valo "ASSOC_RESP: failed,\t" 672277b024eSKalle Valo "status code=%d err=%#x a_id=%#x\n", 673277b024eSKalle Valo status_code, cap_info, 674277b024eSKalle Valo le16_to_cpu(assoc_rsp->a_id)); 675277b024eSKalle Valo 676277b024eSKalle Valo mwifiex_dbg(priv->adapter, ERROR, "assoc failure: reason %s\n", 677277b024eSKalle Valo assoc_failure_reason_to_str(cap_info)); 678277b024eSKalle Valo if (cap_info == CONNECT_ERR_ASSOC_ERR_TIMEOUT) { 679277b024eSKalle Valo if (status_code == MWIFIEX_ASSOC_CMD_FAILURE_AUTH) { 680277b024eSKalle Valo ret = WLAN_STATUS_AUTH_TIMEOUT; 681277b024eSKalle Valo mwifiex_dbg(priv->adapter, ERROR, 682277b024eSKalle Valo "ASSOC_RESP: AUTH timeout\n"); 683277b024eSKalle Valo } else { 684277b024eSKalle Valo ret = WLAN_STATUS_UNSPECIFIED_FAILURE; 685277b024eSKalle Valo mwifiex_dbg(priv->adapter, ERROR, 686277b024eSKalle Valo "ASSOC_RESP: UNSPECIFIED failure\n"); 687277b024eSKalle Valo } 688277b024eSKalle Valo } else { 689277b024eSKalle Valo ret = status_code; 690277b024eSKalle Valo } 691277b024eSKalle Valo 692277b024eSKalle Valo goto done; 693277b024eSKalle Valo } 694277b024eSKalle Valo 695277b024eSKalle Valo /* Send a Media Connected event, according to the Spec */ 696277b024eSKalle Valo priv->media_connected = true; 697277b024eSKalle Valo 698277b024eSKalle Valo priv->adapter->ps_state = PS_STATE_AWAKE; 699277b024eSKalle Valo priv->adapter->pps_uapsd_mode = false; 700277b024eSKalle Valo priv->adapter->tx_lock_flag = false; 701277b024eSKalle Valo 702277b024eSKalle Valo /* Set the attempted BSSID Index to current */ 703277b024eSKalle Valo bss_desc = priv->attempted_bss_desc; 704277b024eSKalle Valo 705277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: ASSOC_RESP: %s\n", 706277b024eSKalle Valo bss_desc->ssid.ssid); 707277b024eSKalle Valo 708277b024eSKalle Valo /* Make a copy of current BSSID descriptor */ 709277b024eSKalle Valo memcpy(&priv->curr_bss_params.bss_descriptor, 710277b024eSKalle Valo bss_desc, sizeof(struct mwifiex_bssdescriptor)); 711277b024eSKalle Valo 712277b024eSKalle Valo /* Update curr_bss_params */ 713277b024eSKalle Valo priv->curr_bss_params.bss_descriptor.channel 714277b024eSKalle Valo = bss_desc->phy_param_set.ds_param_set.current_chan; 715277b024eSKalle Valo 716277b024eSKalle Valo priv->curr_bss_params.band = (u8) bss_desc->bss_band; 717277b024eSKalle Valo 718277b024eSKalle Valo if (bss_desc->wmm_ie.vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC) 719277b024eSKalle Valo priv->curr_bss_params.wmm_enabled = true; 720277b024eSKalle Valo else 721277b024eSKalle Valo priv->curr_bss_params.wmm_enabled = false; 722277b024eSKalle Valo 723277b024eSKalle Valo if ((priv->wmm_required || bss_desc->bcn_ht_cap) && 724277b024eSKalle Valo priv->curr_bss_params.wmm_enabled) 725277b024eSKalle Valo priv->wmm_enabled = true; 726277b024eSKalle Valo else 727277b024eSKalle Valo priv->wmm_enabled = false; 728277b024eSKalle Valo 729277b024eSKalle Valo priv->curr_bss_params.wmm_uapsd_enabled = false; 730277b024eSKalle Valo 731277b024eSKalle Valo if (priv->wmm_enabled) 732277b024eSKalle Valo priv->curr_bss_params.wmm_uapsd_enabled 733277b024eSKalle Valo = ((bss_desc->wmm_ie.qos_info_bitmap & 734277b024eSKalle Valo IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) ? 1 : 0); 735277b024eSKalle Valo 736277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, 737277b024eSKalle Valo "info: ASSOC_RESP: curr_pkt_filter is %#x\n", 738277b024eSKalle Valo priv->curr_pkt_filter); 739277b024eSKalle Valo if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) 740277b024eSKalle Valo priv->wpa_is_gtk_set = false; 741277b024eSKalle Valo 742277b024eSKalle Valo if (priv->wmm_enabled) { 743277b024eSKalle Valo /* Don't re-enable carrier until we get the WMM_GET_STATUS 744277b024eSKalle Valo event */ 745277b024eSKalle Valo enable_data = false; 746277b024eSKalle Valo } else { 747277b024eSKalle Valo /* Since WMM is not enabled, setup the queues with the 748277b024eSKalle Valo defaults */ 749277b024eSKalle Valo mwifiex_wmm_setup_queue_priorities(priv, NULL); 750277b024eSKalle Valo mwifiex_wmm_setup_ac_downgrade(priv); 751277b024eSKalle Valo } 752277b024eSKalle Valo 753277b024eSKalle Valo if (enable_data) 754277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, 755277b024eSKalle Valo "info: post association, re-enabling data flow\n"); 756277b024eSKalle Valo 757277b024eSKalle Valo /* Reset SNR/NF/RSSI values */ 758277b024eSKalle Valo priv->data_rssi_last = 0; 759277b024eSKalle Valo priv->data_nf_last = 0; 760277b024eSKalle Valo priv->data_rssi_avg = 0; 761277b024eSKalle Valo priv->data_nf_avg = 0; 762277b024eSKalle Valo priv->bcn_rssi_last = 0; 763277b024eSKalle Valo priv->bcn_nf_last = 0; 764277b024eSKalle Valo priv->bcn_rssi_avg = 0; 765277b024eSKalle Valo priv->bcn_nf_avg = 0; 766277b024eSKalle Valo priv->rxpd_rate = 0; 767277b024eSKalle Valo priv->rxpd_htinfo = 0; 768277b024eSKalle Valo 769277b024eSKalle Valo mwifiex_save_curr_bcn(priv); 770277b024eSKalle Valo 771277b024eSKalle Valo priv->adapter->dbg.num_cmd_assoc_success++; 772277b024eSKalle Valo 773277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: ASSOC_RESP: associated\n"); 774277b024eSKalle Valo 775277b024eSKalle Valo /* Add the ra_list here for infra mode as there will be only 1 ra 776277b024eSKalle Valo always */ 777277b024eSKalle Valo mwifiex_ralist_add(priv, 778277b024eSKalle Valo priv->curr_bss_params.bss_descriptor.mac_address); 779277b024eSKalle Valo 780277b024eSKalle Valo if (!netif_carrier_ok(priv->netdev)) 781277b024eSKalle Valo netif_carrier_on(priv->netdev); 782277b024eSKalle Valo mwifiex_wake_up_net_dev_queue(priv->netdev, adapter); 783277b024eSKalle Valo 784277b024eSKalle Valo if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) 785277b024eSKalle Valo priv->scan_block = true; 786277b024eSKalle Valo else 787277b024eSKalle Valo priv->port_open = true; 788277b024eSKalle Valo 789277b024eSKalle Valo done: 790277b024eSKalle Valo /* Need to indicate IOCTL complete */ 791277b024eSKalle Valo if (adapter->curr_cmd->wait_q_enabled) { 792277b024eSKalle Valo if (ret) 793277b024eSKalle Valo adapter->cmd_wait_q.status = -1; 794277b024eSKalle Valo else 795277b024eSKalle Valo adapter->cmd_wait_q.status = 0; 796277b024eSKalle Valo } 797277b024eSKalle Valo 798277b024eSKalle Valo return ret; 799277b024eSKalle Valo } 800277b024eSKalle Valo 801277b024eSKalle Valo /* 802277b024eSKalle Valo * This function prepares command for ad-hoc start. 803277b024eSKalle Valo * 804277b024eSKalle Valo * Driver will fill up SSID, BSS mode, IBSS parameters, physical 805277b024eSKalle Valo * parameters, probe delay, and capability information. Firmware 806277b024eSKalle Valo * will fill up beacon period, basic rates and operational rates. 807277b024eSKalle Valo * 808277b024eSKalle Valo * In addition, the following TLVs are added - 809277b024eSKalle Valo * - Channel TLV 810277b024eSKalle Valo * - Vendor specific IE 811277b024eSKalle Valo * - WPA/WPA2 IE 812277b024eSKalle Valo * - HT Capabilities IE 813277b024eSKalle Valo * - HT Information IE 814277b024eSKalle Valo * 815277b024eSKalle Valo * Preparation also includes - 816277b024eSKalle Valo * - Setting command ID and proper size 817277b024eSKalle Valo * - Ensuring correct endian-ness 818277b024eSKalle Valo */ 819277b024eSKalle Valo int 820277b024eSKalle Valo mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv, 821277b024eSKalle Valo struct host_cmd_ds_command *cmd, 822277b024eSKalle Valo struct cfg80211_ssid *req_ssid) 823277b024eSKalle Valo { 824277b024eSKalle Valo int rsn_ie_len = 0; 825277b024eSKalle Valo struct mwifiex_adapter *adapter = priv->adapter; 826277b024eSKalle Valo struct host_cmd_ds_802_11_ad_hoc_start *adhoc_start = 827277b024eSKalle Valo &cmd->params.adhoc_start; 828277b024eSKalle Valo struct mwifiex_bssdescriptor *bss_desc; 829277b024eSKalle Valo u32 cmd_append_size = 0; 830277b024eSKalle Valo u32 i; 831277b024eSKalle Valo u16 tmp_cap; 832277b024eSKalle Valo struct mwifiex_ie_types_chan_list_param_set *chan_tlv; 833277b024eSKalle Valo u8 radio_type; 834277b024eSKalle Valo 835277b024eSKalle Valo struct mwifiex_ie_types_htcap *ht_cap; 836277b024eSKalle Valo struct mwifiex_ie_types_htinfo *ht_info; 837277b024eSKalle Valo u8 *pos = (u8 *) adhoc_start + 838277b024eSKalle Valo sizeof(struct host_cmd_ds_802_11_ad_hoc_start); 839277b024eSKalle Valo 840277b024eSKalle Valo if (!adapter) 841277b024eSKalle Valo return -1; 842277b024eSKalle Valo 843277b024eSKalle Valo cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_START); 844277b024eSKalle Valo 845277b024eSKalle Valo bss_desc = &priv->curr_bss_params.bss_descriptor; 846277b024eSKalle Valo priv->attempted_bss_desc = bss_desc; 847277b024eSKalle Valo 848277b024eSKalle Valo /* 849277b024eSKalle Valo * Fill in the parameters for 2 data structures: 850277b024eSKalle Valo * 1. struct host_cmd_ds_802_11_ad_hoc_start command 851277b024eSKalle Valo * 2. bss_desc 852277b024eSKalle Valo * Driver will fill up SSID, bss_mode,IBSS param, Physical Param, 853277b024eSKalle Valo * probe delay, and Cap info. 854277b024eSKalle Valo * Firmware will fill up beacon period, Basic rates 855277b024eSKalle Valo * and operational rates. 856277b024eSKalle Valo */ 857277b024eSKalle Valo 858277b024eSKalle Valo memset(adhoc_start->ssid, 0, IEEE80211_MAX_SSID_LEN); 859277b024eSKalle Valo 860277b024eSKalle Valo memcpy(adhoc_start->ssid, req_ssid->ssid, req_ssid->ssid_len); 861277b024eSKalle Valo 862277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: SSID = %s\n", 863277b024eSKalle Valo adhoc_start->ssid); 864277b024eSKalle Valo 865277b024eSKalle Valo memset(bss_desc->ssid.ssid, 0, IEEE80211_MAX_SSID_LEN); 866277b024eSKalle Valo memcpy(bss_desc->ssid.ssid, req_ssid->ssid, req_ssid->ssid_len); 867277b024eSKalle Valo 868277b024eSKalle Valo bss_desc->ssid.ssid_len = req_ssid->ssid_len; 869277b024eSKalle Valo 870277b024eSKalle Valo /* Set the BSS mode */ 871277b024eSKalle Valo adhoc_start->bss_mode = HostCmd_BSS_MODE_IBSS; 872277b024eSKalle Valo bss_desc->bss_mode = NL80211_IFTYPE_ADHOC; 873277b024eSKalle Valo adhoc_start->beacon_period = cpu_to_le16(priv->beacon_period); 874277b024eSKalle Valo bss_desc->beacon_period = priv->beacon_period; 875277b024eSKalle Valo 876277b024eSKalle Valo /* Set Physical param set */ 877277b024eSKalle Valo /* Parameter IE Id */ 878277b024eSKalle Valo #define DS_PARA_IE_ID 3 879277b024eSKalle Valo /* Parameter IE length */ 880277b024eSKalle Valo #define DS_PARA_IE_LEN 1 881277b024eSKalle Valo 882277b024eSKalle Valo adhoc_start->phy_param_set.ds_param_set.element_id = DS_PARA_IE_ID; 883277b024eSKalle Valo adhoc_start->phy_param_set.ds_param_set.len = DS_PARA_IE_LEN; 884277b024eSKalle Valo 885277b024eSKalle Valo if (!mwifiex_get_cfp(priv, adapter->adhoc_start_band, 886277b024eSKalle Valo (u16) priv->adhoc_channel, 0)) { 887277b024eSKalle Valo struct mwifiex_chan_freq_power *cfp; 888277b024eSKalle Valo cfp = mwifiex_get_cfp(priv, adapter->adhoc_start_band, 889277b024eSKalle Valo FIRST_VALID_CHANNEL, 0); 890277b024eSKalle Valo if (cfp) 891277b024eSKalle Valo priv->adhoc_channel = (u8) cfp->channel; 892277b024eSKalle Valo } 893277b024eSKalle Valo 894277b024eSKalle Valo if (!priv->adhoc_channel) { 895277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 896277b024eSKalle Valo "ADHOC_S_CMD: adhoc_channel cannot be 0\n"); 897277b024eSKalle Valo return -1; 898277b024eSKalle Valo } 899277b024eSKalle Valo 900277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 901277b024eSKalle Valo "info: ADHOC_S_CMD: creating ADHOC on channel %d\n", 902277b024eSKalle Valo priv->adhoc_channel); 903277b024eSKalle Valo 904277b024eSKalle Valo priv->curr_bss_params.bss_descriptor.channel = priv->adhoc_channel; 905277b024eSKalle Valo priv->curr_bss_params.band = adapter->adhoc_start_band; 906277b024eSKalle Valo 907277b024eSKalle Valo bss_desc->channel = priv->adhoc_channel; 908277b024eSKalle Valo adhoc_start->phy_param_set.ds_param_set.current_chan = 909277b024eSKalle Valo priv->adhoc_channel; 910277b024eSKalle Valo 911277b024eSKalle Valo memcpy(&bss_desc->phy_param_set, &adhoc_start->phy_param_set, 912277b024eSKalle Valo sizeof(union ieee_types_phy_param_set)); 913277b024eSKalle Valo 914277b024eSKalle Valo /* Set IBSS param set */ 915277b024eSKalle Valo /* IBSS parameter IE Id */ 916277b024eSKalle Valo #define IBSS_PARA_IE_ID 6 917277b024eSKalle Valo /* IBSS parameter IE length */ 918277b024eSKalle Valo #define IBSS_PARA_IE_LEN 2 919277b024eSKalle Valo 920277b024eSKalle Valo adhoc_start->ss_param_set.ibss_param_set.element_id = IBSS_PARA_IE_ID; 921277b024eSKalle Valo adhoc_start->ss_param_set.ibss_param_set.len = IBSS_PARA_IE_LEN; 922277b024eSKalle Valo adhoc_start->ss_param_set.ibss_param_set.atim_window 923277b024eSKalle Valo = cpu_to_le16(priv->atim_window); 924277b024eSKalle Valo memcpy(&bss_desc->ss_param_set, &adhoc_start->ss_param_set, 925277b024eSKalle Valo sizeof(union ieee_types_ss_param_set)); 926277b024eSKalle Valo 927277b024eSKalle Valo /* Set Capability info */ 928277b024eSKalle Valo bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_IBSS; 929277b024eSKalle Valo tmp_cap = WLAN_CAPABILITY_IBSS; 930277b024eSKalle Valo 931277b024eSKalle Valo /* Set up privacy in bss_desc */ 932277b024eSKalle Valo if (priv->sec_info.encryption_mode) { 933277b024eSKalle Valo /* Ad-Hoc capability privacy on */ 934277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 935277b024eSKalle Valo "info: ADHOC_S_CMD: wep_status set privacy to WEP\n"); 936277b024eSKalle Valo bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; 937277b024eSKalle Valo tmp_cap |= WLAN_CAPABILITY_PRIVACY; 938277b024eSKalle Valo } else { 939277b024eSKalle Valo mwifiex_dbg(adapter, INFO, 940277b024eSKalle Valo "info: ADHOC_S_CMD: wep_status NOT set,\t" 941277b024eSKalle Valo "setting privacy to ACCEPT ALL\n"); 942277b024eSKalle Valo bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL; 943277b024eSKalle Valo } 944277b024eSKalle Valo 945277b024eSKalle Valo memset(adhoc_start->data_rate, 0, sizeof(adhoc_start->data_rate)); 946277b024eSKalle Valo mwifiex_get_active_data_rates(priv, adhoc_start->data_rate); 947277b024eSKalle Valo if ((adapter->adhoc_start_band & BAND_G) && 948277b024eSKalle Valo (priv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) { 949277b024eSKalle Valo if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL, 950277b024eSKalle Valo HostCmd_ACT_GEN_SET, 0, 951277b024eSKalle Valo &priv->curr_pkt_filter, false)) { 952277b024eSKalle Valo mwifiex_dbg(adapter, ERROR, 953277b024eSKalle Valo "ADHOC_S_CMD: G Protection config failed\n"); 954277b024eSKalle Valo return -1; 955277b024eSKalle Valo } 956277b024eSKalle Valo } 957277b024eSKalle Valo /* Find the last non zero */ 958277b024eSKalle Valo for (i = 0; i < sizeof(adhoc_start->data_rate); i++) 959277b024eSKalle Valo if (!adhoc_start->data_rate[i]) 960277b024eSKalle Valo break; 961277b024eSKalle Valo 962277b024eSKalle Valo priv->curr_bss_params.num_of_rates = i; 963277b024eSKalle Valo 964277b024eSKalle Valo /* Copy the ad-hoc creating rates into Current BSS rate structure */ 965277b024eSKalle Valo memcpy(&priv->curr_bss_params.data_rates, 966277b024eSKalle Valo &adhoc_start->data_rate, priv->curr_bss_params.num_of_rates); 967277b024eSKalle Valo 968277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: rates=%4ph\n", 969277b024eSKalle Valo adhoc_start->data_rate); 970277b024eSKalle Valo 971277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: AD-HOC Start command is ready\n"); 972277b024eSKalle Valo 973277b024eSKalle Valo if (IS_SUPPORT_MULTI_BANDS(adapter)) { 974277b024eSKalle Valo /* Append a channel TLV */ 975277b024eSKalle Valo chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; 976277b024eSKalle Valo chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); 977277b024eSKalle Valo chan_tlv->header.len = 978277b024eSKalle Valo cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); 979277b024eSKalle Valo 980277b024eSKalle Valo memset(chan_tlv->chan_scan_param, 0x00, 981277b024eSKalle Valo sizeof(struct mwifiex_chan_scan_param_set)); 982277b024eSKalle Valo chan_tlv->chan_scan_param[0].chan_number = 983277b024eSKalle Valo (u8) priv->curr_bss_params.bss_descriptor.channel; 984277b024eSKalle Valo 985277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: TLV Chan = %d\n", 986277b024eSKalle Valo chan_tlv->chan_scan_param[0].chan_number); 987277b024eSKalle Valo 988277b024eSKalle Valo chan_tlv->chan_scan_param[0].radio_type 989277b024eSKalle Valo = mwifiex_band_to_radio_type(priv->curr_bss_params.band); 990277b024eSKalle Valo if (adapter->adhoc_start_band & BAND_GN || 991277b024eSKalle Valo adapter->adhoc_start_band & BAND_AN) { 992277b024eSKalle Valo if (adapter->sec_chan_offset == 993277b024eSKalle Valo IEEE80211_HT_PARAM_CHA_SEC_ABOVE) 994277b024eSKalle Valo chan_tlv->chan_scan_param[0].radio_type |= 995277b024eSKalle Valo (IEEE80211_HT_PARAM_CHA_SEC_ABOVE << 4); 996277b024eSKalle Valo else if (adapter->sec_chan_offset == 997277b024eSKalle Valo IEEE80211_HT_PARAM_CHA_SEC_BELOW) 998277b024eSKalle Valo chan_tlv->chan_scan_param[0].radio_type |= 999277b024eSKalle Valo (IEEE80211_HT_PARAM_CHA_SEC_BELOW << 4); 1000277b024eSKalle Valo } 1001277b024eSKalle Valo mwifiex_dbg(adapter, INFO, "info: ADHOC_S_CMD: TLV Band = %d\n", 1002277b024eSKalle Valo chan_tlv->chan_scan_param[0].radio_type); 1003277b024eSKalle Valo pos += sizeof(chan_tlv->header) + 1004277b024eSKalle Valo sizeof(struct mwifiex_chan_scan_param_set); 1005277b024eSKalle Valo cmd_append_size += 1006277b024eSKalle Valo sizeof(chan_tlv->header) + 1007277b024eSKalle Valo sizeof(struct mwifiex_chan_scan_param_set); 1008277b024eSKalle Valo } 1009277b024eSKalle Valo 1010277b024eSKalle Valo /* Append vendor specific IE TLV */ 1011277b024eSKalle Valo cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv, 1012277b024eSKalle Valo MWIFIEX_VSIE_MASK_ADHOC, &pos); 1013277b024eSKalle Valo 1014277b024eSKalle Valo if (priv->sec_info.wpa_enabled) { 1015277b024eSKalle Valo rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); 1016277b024eSKalle Valo if (rsn_ie_len == -1) 1017277b024eSKalle Valo return -1; 1018277b024eSKalle Valo cmd_append_size += rsn_ie_len; 1019277b024eSKalle Valo } 1020277b024eSKalle Valo 1021277b024eSKalle Valo if (adapter->adhoc_11n_enabled) { 1022277b024eSKalle Valo /* Fill HT CAPABILITY */ 1023277b024eSKalle Valo ht_cap = (struct mwifiex_ie_types_htcap *) pos; 1024277b024eSKalle Valo memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap)); 1025277b024eSKalle Valo ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); 1026277b024eSKalle Valo ht_cap->header.len = 1027277b024eSKalle Valo cpu_to_le16(sizeof(struct ieee80211_ht_cap)); 1028277b024eSKalle Valo radio_type = mwifiex_band_to_radio_type( 1029277b024eSKalle Valo priv->adapter->config_bands); 1030277b024eSKalle Valo mwifiex_fill_cap_info(priv, radio_type, &ht_cap->ht_cap); 1031277b024eSKalle Valo 1032277b024eSKalle Valo if (adapter->sec_chan_offset == 1033277b024eSKalle Valo IEEE80211_HT_PARAM_CHA_SEC_NONE) { 1034277b024eSKalle Valo u16 tmp_ht_cap; 1035277b024eSKalle Valo 1036277b024eSKalle Valo tmp_ht_cap = le16_to_cpu(ht_cap->ht_cap.cap_info); 1037277b024eSKalle Valo tmp_ht_cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; 1038277b024eSKalle Valo tmp_ht_cap &= ~IEEE80211_HT_CAP_SGI_40; 1039277b024eSKalle Valo ht_cap->ht_cap.cap_info = cpu_to_le16(tmp_ht_cap); 1040277b024eSKalle Valo } 1041277b024eSKalle Valo 1042277b024eSKalle Valo pos += sizeof(struct mwifiex_ie_types_htcap); 1043277b024eSKalle Valo cmd_append_size += sizeof(struct mwifiex_ie_types_htcap); 1044277b024eSKalle Valo 1045277b024eSKalle Valo /* Fill HT INFORMATION */ 1046277b024eSKalle Valo ht_info = (struct mwifiex_ie_types_htinfo *) pos; 1047277b024eSKalle Valo memset(ht_info, 0, sizeof(struct mwifiex_ie_types_htinfo)); 1048277b024eSKalle Valo ht_info->header.type = cpu_to_le16(WLAN_EID_HT_OPERATION); 1049277b024eSKalle Valo ht_info->header.len = 1050277b024eSKalle Valo cpu_to_le16(sizeof(struct ieee80211_ht_operation)); 1051277b024eSKalle Valo 1052277b024eSKalle Valo ht_info->ht_oper.primary_chan = 1053277b024eSKalle Valo (u8) priv->curr_bss_params.bss_descriptor.channel; 1054277b024eSKalle Valo if (adapter->sec_chan_offset) { 1055277b024eSKalle Valo ht_info->ht_oper.ht_param = adapter->sec_chan_offset; 1056277b024eSKalle Valo ht_info->ht_oper.ht_param |= 1057277b024eSKalle Valo IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; 1058277b024eSKalle Valo } 1059277b024eSKalle Valo ht_info->ht_oper.operation_mode = 1060277b024eSKalle Valo cpu_to_le16(IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); 1061277b024eSKalle Valo ht_info->ht_oper.basic_set[0] = 0xff; 1062277b024eSKalle Valo pos += sizeof(struct mwifiex_ie_types_htinfo); 1063277b024eSKalle Valo cmd_append_size += 1064277b024eSKalle Valo sizeof(struct mwifiex_ie_types_htinfo); 1065277b024eSKalle Valo } 1066277b024eSKalle Valo 1067277b024eSKalle Valo cmd->size = 1068277b024eSKalle Valo cpu_to_le16((u16)(sizeof(struct host_cmd_ds_802_11_ad_hoc_start) 1069277b024eSKalle Valo + S_DS_GEN + cmd_append_size)); 1070277b024eSKalle Valo 1071277b024eSKalle Valo if (adapter->adhoc_start_band == BAND_B) 1072277b024eSKalle Valo tmp_cap &= ~WLAN_CAPABILITY_SHORT_SLOT_TIME; 1073277b024eSKalle Valo else 1074277b024eSKalle Valo tmp_cap |= WLAN_CAPABILITY_SHORT_SLOT_TIME; 1075277b024eSKalle Valo 1076277b024eSKalle Valo adhoc_start->cap_info_bitmap = cpu_to_le16(tmp_cap); 1077277b024eSKalle Valo 1078277b024eSKalle Valo return 0; 1079277b024eSKalle Valo } 1080277b024eSKalle Valo 1081277b024eSKalle Valo /* 1082277b024eSKalle Valo * This function prepares command for ad-hoc join. 1083277b024eSKalle Valo * 1084277b024eSKalle Valo * Most of the parameters are set up by copying from the target BSS descriptor 1085277b024eSKalle Valo * from the scan response. 1086277b024eSKalle Valo * 1087277b024eSKalle Valo * In addition, the following TLVs are added - 1088277b024eSKalle Valo * - Channel TLV 1089277b024eSKalle Valo * - Vendor specific IE 1090277b024eSKalle Valo * - WPA/WPA2 IE 1091277b024eSKalle Valo * - 11n IE 1092277b024eSKalle Valo * 1093277b024eSKalle Valo * Preparation also includes - 1094277b024eSKalle Valo * - Setting command ID and proper size 1095277b024eSKalle Valo * - Ensuring correct endian-ness 1096277b024eSKalle Valo */ 1097277b024eSKalle Valo int 1098277b024eSKalle Valo mwifiex_cmd_802_11_ad_hoc_join(struct mwifiex_private *priv, 1099277b024eSKalle Valo struct host_cmd_ds_command *cmd, 1100277b024eSKalle Valo struct mwifiex_bssdescriptor *bss_desc) 1101277b024eSKalle Valo { 1102277b024eSKalle Valo int rsn_ie_len = 0; 1103277b024eSKalle Valo struct host_cmd_ds_802_11_ad_hoc_join *adhoc_join = 1104277b024eSKalle Valo &cmd->params.adhoc_join; 1105277b024eSKalle Valo struct mwifiex_ie_types_chan_list_param_set *chan_tlv; 1106277b024eSKalle Valo u32 cmd_append_size = 0; 1107277b024eSKalle Valo u16 tmp_cap; 1108277b024eSKalle Valo u32 i, rates_size = 0; 1109277b024eSKalle Valo u16 curr_pkt_filter; 1110277b024eSKalle Valo u8 *pos = 1111277b024eSKalle Valo (u8 *) adhoc_join + 1112277b024eSKalle Valo sizeof(struct host_cmd_ds_802_11_ad_hoc_join); 1113277b024eSKalle Valo 1114277b024eSKalle Valo /* Use G protection */ 1115277b024eSKalle Valo #define USE_G_PROTECTION 0x02 1116277b024eSKalle Valo if (bss_desc->erp_flags & USE_G_PROTECTION) { 1117277b024eSKalle Valo curr_pkt_filter = 1118277b024eSKalle Valo priv-> 1119277b024eSKalle Valo curr_pkt_filter | HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON; 1120277b024eSKalle Valo 1121277b024eSKalle Valo if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL, 1122277b024eSKalle Valo HostCmd_ACT_GEN_SET, 0, 1123277b024eSKalle Valo &curr_pkt_filter, false)) { 1124277b024eSKalle Valo mwifiex_dbg(priv->adapter, ERROR, 1125277b024eSKalle Valo "ADHOC_J_CMD: G Protection config failed\n"); 1126277b024eSKalle Valo return -1; 1127277b024eSKalle Valo } 1128277b024eSKalle Valo } 1129277b024eSKalle Valo 1130277b024eSKalle Valo priv->attempted_bss_desc = bss_desc; 1131277b024eSKalle Valo 1132277b024eSKalle Valo cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_JOIN); 1133277b024eSKalle Valo 1134277b024eSKalle Valo adhoc_join->bss_descriptor.bss_mode = HostCmd_BSS_MODE_IBSS; 1135277b024eSKalle Valo 1136277b024eSKalle Valo adhoc_join->bss_descriptor.beacon_period 1137277b024eSKalle Valo = cpu_to_le16(bss_desc->beacon_period); 1138277b024eSKalle Valo 1139277b024eSKalle Valo memcpy(&adhoc_join->bss_descriptor.bssid, 1140277b024eSKalle Valo &bss_desc->mac_address, ETH_ALEN); 1141277b024eSKalle Valo 1142277b024eSKalle Valo memcpy(&adhoc_join->bss_descriptor.ssid, 1143277b024eSKalle Valo &bss_desc->ssid.ssid, bss_desc->ssid.ssid_len); 1144277b024eSKalle Valo 1145277b024eSKalle Valo memcpy(&adhoc_join->bss_descriptor.phy_param_set, 1146277b024eSKalle Valo &bss_desc->phy_param_set, 1147277b024eSKalle Valo sizeof(union ieee_types_phy_param_set)); 1148277b024eSKalle Valo 1149277b024eSKalle Valo memcpy(&adhoc_join->bss_descriptor.ss_param_set, 1150277b024eSKalle Valo &bss_desc->ss_param_set, sizeof(union ieee_types_ss_param_set)); 1151277b024eSKalle Valo 1152277b024eSKalle Valo tmp_cap = bss_desc->cap_info_bitmap; 1153277b024eSKalle Valo 1154277b024eSKalle Valo tmp_cap &= CAPINFO_MASK; 1155277b024eSKalle Valo 1156277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, 1157277b024eSKalle Valo "info: ADHOC_J_CMD: tmp_cap=%4X CAPINFO_MASK=%4lX\n", 1158277b024eSKalle Valo tmp_cap, CAPINFO_MASK); 1159277b024eSKalle Valo 1160277b024eSKalle Valo /* Information on BSSID descriptor passed to FW */ 1161277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, 1162277b024eSKalle Valo "info: ADHOC_J_CMD: BSSID=%pM, SSID='%s'\n", 1163277b024eSKalle Valo adhoc_join->bss_descriptor.bssid, 1164277b024eSKalle Valo adhoc_join->bss_descriptor.ssid); 1165277b024eSKalle Valo 1166277b024eSKalle Valo for (i = 0; i < MWIFIEX_SUPPORTED_RATES && 1167277b024eSKalle Valo bss_desc->supported_rates[i]; i++) 1168277b024eSKalle Valo ; 1169277b024eSKalle Valo rates_size = i; 1170277b024eSKalle Valo 1171277b024eSKalle Valo /* Copy Data Rates from the Rates recorded in scan response */ 1172277b024eSKalle Valo memset(adhoc_join->bss_descriptor.data_rates, 0, 1173277b024eSKalle Valo sizeof(adhoc_join->bss_descriptor.data_rates)); 1174277b024eSKalle Valo memcpy(adhoc_join->bss_descriptor.data_rates, 1175277b024eSKalle Valo bss_desc->supported_rates, rates_size); 1176277b024eSKalle Valo 1177277b024eSKalle Valo /* Copy the adhoc join rates into Current BSS state structure */ 1178277b024eSKalle Valo priv->curr_bss_params.num_of_rates = rates_size; 1179277b024eSKalle Valo memcpy(&priv->curr_bss_params.data_rates, bss_desc->supported_rates, 1180277b024eSKalle Valo rates_size); 1181277b024eSKalle Valo 1182277b024eSKalle Valo /* Copy the channel information */ 1183277b024eSKalle Valo priv->curr_bss_params.bss_descriptor.channel = bss_desc->channel; 1184277b024eSKalle Valo priv->curr_bss_params.band = (u8) bss_desc->bss_band; 1185277b024eSKalle Valo 1186277b024eSKalle Valo if (priv->sec_info.wep_enabled || priv->sec_info.wpa_enabled) 1187277b024eSKalle Valo tmp_cap |= WLAN_CAPABILITY_PRIVACY; 1188277b024eSKalle Valo 1189277b024eSKalle Valo if (IS_SUPPORT_MULTI_BANDS(priv->adapter)) { 1190277b024eSKalle Valo /* Append a channel TLV */ 1191277b024eSKalle Valo chan_tlv = (struct mwifiex_ie_types_chan_list_param_set *) pos; 1192277b024eSKalle Valo chan_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); 1193277b024eSKalle Valo chan_tlv->header.len = 1194277b024eSKalle Valo cpu_to_le16(sizeof(struct mwifiex_chan_scan_param_set)); 1195277b024eSKalle Valo 1196277b024eSKalle Valo memset(chan_tlv->chan_scan_param, 0x00, 1197277b024eSKalle Valo sizeof(struct mwifiex_chan_scan_param_set)); 1198277b024eSKalle Valo chan_tlv->chan_scan_param[0].chan_number = 1199277b024eSKalle Valo (bss_desc->phy_param_set.ds_param_set.current_chan); 1200277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_J_CMD: TLV Chan=%d\n", 1201277b024eSKalle Valo chan_tlv->chan_scan_param[0].chan_number); 1202277b024eSKalle Valo 1203277b024eSKalle Valo chan_tlv->chan_scan_param[0].radio_type = 1204277b024eSKalle Valo mwifiex_band_to_radio_type((u8) bss_desc->bss_band); 1205277b024eSKalle Valo 1206277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_J_CMD: TLV Band=%d\n", 1207277b024eSKalle Valo chan_tlv->chan_scan_param[0].radio_type); 1208277b024eSKalle Valo pos += sizeof(chan_tlv->header) + 1209277b024eSKalle Valo sizeof(struct mwifiex_chan_scan_param_set); 1210277b024eSKalle Valo cmd_append_size += sizeof(chan_tlv->header) + 1211277b024eSKalle Valo sizeof(struct mwifiex_chan_scan_param_set); 1212277b024eSKalle Valo } 1213277b024eSKalle Valo 1214277b024eSKalle Valo if (priv->sec_info.wpa_enabled) 1215277b024eSKalle Valo rsn_ie_len = mwifiex_append_rsn_ie_wpa_wpa2(priv, &pos); 1216277b024eSKalle Valo if (rsn_ie_len == -1) 1217277b024eSKalle Valo return -1; 1218277b024eSKalle Valo cmd_append_size += rsn_ie_len; 1219277b024eSKalle Valo 1220277b024eSKalle Valo if (ISSUPP_11NENABLED(priv->adapter->fw_cap_info)) 1221277b024eSKalle Valo cmd_append_size += mwifiex_cmd_append_11n_tlv(priv, 1222277b024eSKalle Valo bss_desc, &pos); 1223277b024eSKalle Valo 1224277b024eSKalle Valo /* Append vendor specific IE TLV */ 1225277b024eSKalle Valo cmd_append_size += mwifiex_cmd_append_vsie_tlv(priv, 1226277b024eSKalle Valo MWIFIEX_VSIE_MASK_ADHOC, &pos); 1227277b024eSKalle Valo 1228277b024eSKalle Valo cmd->size = cpu_to_le16 1229277b024eSKalle Valo ((u16) (sizeof(struct host_cmd_ds_802_11_ad_hoc_join) 1230277b024eSKalle Valo + S_DS_GEN + cmd_append_size)); 1231277b024eSKalle Valo 1232277b024eSKalle Valo adhoc_join->bss_descriptor.cap_info_bitmap = cpu_to_le16(tmp_cap); 1233277b024eSKalle Valo 1234277b024eSKalle Valo return 0; 1235277b024eSKalle Valo } 1236277b024eSKalle Valo 1237277b024eSKalle Valo /* 1238277b024eSKalle Valo * This function handles the command response of ad-hoc start and 1239277b024eSKalle Valo * ad-hoc join. 1240277b024eSKalle Valo * 1241277b024eSKalle Valo * The function generates a device-connected event to notify 1242277b024eSKalle Valo * the applications, in case of successful ad-hoc start/join, and 1243277b024eSKalle Valo * saves the beacon buffer. 1244277b024eSKalle Valo */ 1245277b024eSKalle Valo int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv, 1246277b024eSKalle Valo struct host_cmd_ds_command *resp) 1247277b024eSKalle Valo { 1248277b024eSKalle Valo int ret = 0; 1249277b024eSKalle Valo struct mwifiex_adapter *adapter = priv->adapter; 1250277b024eSKalle Valo struct host_cmd_ds_802_11_ad_hoc_result *adhoc_result; 1251277b024eSKalle Valo struct mwifiex_bssdescriptor *bss_desc; 1252277b024eSKalle Valo u16 reason_code; 1253277b024eSKalle Valo 1254277b024eSKalle Valo adhoc_result = &resp->params.adhoc_result; 1255277b024eSKalle Valo 1256277b024eSKalle Valo bss_desc = priv->attempted_bss_desc; 1257277b024eSKalle Valo 1258277b024eSKalle Valo /* Join result code 0 --> SUCCESS */ 1259277b024eSKalle Valo reason_code = le16_to_cpu(resp->result); 1260277b024eSKalle Valo if (reason_code) { 1261277b024eSKalle Valo mwifiex_dbg(priv->adapter, ERROR, "ADHOC_RESP: failed\n"); 1262277b024eSKalle Valo if (priv->media_connected) 1263277b024eSKalle Valo mwifiex_reset_connect_state(priv, reason_code); 1264277b024eSKalle Valo 1265277b024eSKalle Valo memset(&priv->curr_bss_params.bss_descriptor, 1266277b024eSKalle Valo 0x00, sizeof(struct mwifiex_bssdescriptor)); 1267277b024eSKalle Valo 1268277b024eSKalle Valo ret = -1; 1269277b024eSKalle Valo goto done; 1270277b024eSKalle Valo } 1271277b024eSKalle Valo 1272277b024eSKalle Valo /* Send a Media Connected event, according to the Spec */ 1273277b024eSKalle Valo priv->media_connected = true; 1274277b024eSKalle Valo 1275277b024eSKalle Valo if (le16_to_cpu(resp->command) == HostCmd_CMD_802_11_AD_HOC_START) { 1276277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_S_RESP %s\n", 1277277b024eSKalle Valo bss_desc->ssid.ssid); 1278277b024eSKalle Valo 1279277b024eSKalle Valo /* Update the created network descriptor with the new BSSID */ 1280277b024eSKalle Valo memcpy(bss_desc->mac_address, 1281277b024eSKalle Valo adhoc_result->bssid, ETH_ALEN); 1282277b024eSKalle Valo 1283277b024eSKalle Valo priv->adhoc_state = ADHOC_STARTED; 1284277b024eSKalle Valo } else { 1285277b024eSKalle Valo /* 1286277b024eSKalle Valo * Now the join cmd should be successful. 1287277b024eSKalle Valo * If BSSID has changed use SSID to compare instead of BSSID 1288277b024eSKalle Valo */ 1289277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, 1290277b024eSKalle Valo "info: ADHOC_J_RESP %s\n", 1291277b024eSKalle Valo bss_desc->ssid.ssid); 1292277b024eSKalle Valo 1293277b024eSKalle Valo /* 1294277b024eSKalle Valo * Make a copy of current BSSID descriptor, only needed for 1295277b024eSKalle Valo * join since the current descriptor is already being used 1296277b024eSKalle Valo * for adhoc start 1297277b024eSKalle Valo */ 1298277b024eSKalle Valo memcpy(&priv->curr_bss_params.bss_descriptor, 1299277b024eSKalle Valo bss_desc, sizeof(struct mwifiex_bssdescriptor)); 1300277b024eSKalle Valo 1301277b024eSKalle Valo priv->adhoc_state = ADHOC_JOINED; 1302277b024eSKalle Valo } 1303277b024eSKalle Valo 1304277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_RESP: channel = %d\n", 1305277b024eSKalle Valo priv->adhoc_channel); 1306277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: ADHOC_RESP: BSSID = %pM\n", 1307277b024eSKalle Valo priv->curr_bss_params.bss_descriptor.mac_address); 1308277b024eSKalle Valo 1309277b024eSKalle Valo if (!netif_carrier_ok(priv->netdev)) 1310277b024eSKalle Valo netif_carrier_on(priv->netdev); 1311277b024eSKalle Valo mwifiex_wake_up_net_dev_queue(priv->netdev, adapter); 1312277b024eSKalle Valo 1313277b024eSKalle Valo mwifiex_save_curr_bcn(priv); 1314277b024eSKalle Valo 1315277b024eSKalle Valo done: 1316277b024eSKalle Valo /* Need to indicate IOCTL complete */ 1317277b024eSKalle Valo if (adapter->curr_cmd->wait_q_enabled) { 1318277b024eSKalle Valo if (ret) 1319277b024eSKalle Valo adapter->cmd_wait_q.status = -1; 1320277b024eSKalle Valo else 1321277b024eSKalle Valo adapter->cmd_wait_q.status = 0; 1322277b024eSKalle Valo 1323277b024eSKalle Valo } 1324277b024eSKalle Valo 1325277b024eSKalle Valo return ret; 1326277b024eSKalle Valo } 1327277b024eSKalle Valo 1328277b024eSKalle Valo /* 1329277b024eSKalle Valo * This function associates to a specific BSS discovered in a scan. 1330277b024eSKalle Valo * 1331277b024eSKalle Valo * It clears any past association response stored for application 1332277b024eSKalle Valo * retrieval and calls the command preparation routine to send the 1333277b024eSKalle Valo * command to firmware. 1334277b024eSKalle Valo */ 1335277b024eSKalle Valo int mwifiex_associate(struct mwifiex_private *priv, 1336277b024eSKalle Valo struct mwifiex_bssdescriptor *bss_desc) 1337277b024eSKalle Valo { 1338277b024eSKalle Valo /* Return error if the adapter is not STA role or table entry 1339277b024eSKalle Valo * is not marked as infra. 1340277b024eSKalle Valo */ 1341277b024eSKalle Valo if ((GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) || 1342277b024eSKalle Valo (bss_desc->bss_mode != NL80211_IFTYPE_STATION)) 1343277b024eSKalle Valo return -1; 1344277b024eSKalle Valo 1345277b024eSKalle Valo if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) && 1346277b024eSKalle Valo !bss_desc->disable_11n && !bss_desc->disable_11ac && 1347277b024eSKalle Valo priv->adapter->config_bands & BAND_AAC) 1348277b024eSKalle Valo mwifiex_set_11ac_ba_params(priv); 1349277b024eSKalle Valo else 1350277b024eSKalle Valo mwifiex_set_ba_params(priv); 1351277b024eSKalle Valo 1352277b024eSKalle Valo /* Clear any past association response stored for application 1353277b024eSKalle Valo retrieval */ 1354277b024eSKalle Valo priv->assoc_rsp_size = 0; 1355277b024eSKalle Valo 1356277b024eSKalle Valo return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_ASSOCIATE, 1357277b024eSKalle Valo HostCmd_ACT_GEN_SET, 0, bss_desc, true); 1358277b024eSKalle Valo } 1359277b024eSKalle Valo 1360277b024eSKalle Valo /* 1361277b024eSKalle Valo * This function starts an ad-hoc network. 1362277b024eSKalle Valo * 1363277b024eSKalle Valo * It calls the command preparation routine to send the command to firmware. 1364277b024eSKalle Valo */ 1365277b024eSKalle Valo int 1366277b024eSKalle Valo mwifiex_adhoc_start(struct mwifiex_private *priv, 1367277b024eSKalle Valo struct cfg80211_ssid *adhoc_ssid) 1368277b024eSKalle Valo { 1369277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: Adhoc Channel = %d\n", 1370277b024eSKalle Valo priv->adhoc_channel); 1371277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: curr_bss_params.channel = %d\n", 1372277b024eSKalle Valo priv->curr_bss_params.bss_descriptor.channel); 1373277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: curr_bss_params.band = %d\n", 1374277b024eSKalle Valo priv->curr_bss_params.band); 1375277b024eSKalle Valo 1376277b024eSKalle Valo if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) && 1377277b024eSKalle Valo priv->adapter->config_bands & BAND_AAC) 1378277b024eSKalle Valo mwifiex_set_11ac_ba_params(priv); 1379277b024eSKalle Valo else 1380277b024eSKalle Valo mwifiex_set_ba_params(priv); 1381277b024eSKalle Valo 1382277b024eSKalle Valo return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_START, 1383277b024eSKalle Valo HostCmd_ACT_GEN_SET, 0, adhoc_ssid, true); 1384277b024eSKalle Valo } 1385277b024eSKalle Valo 1386277b024eSKalle Valo /* 1387277b024eSKalle Valo * This function joins an ad-hoc network found in a previous scan. 1388277b024eSKalle Valo * 1389277b024eSKalle Valo * It calls the command preparation routine to send the command to firmware, 1390277b024eSKalle Valo * if already not connected to the requested SSID. 1391277b024eSKalle Valo */ 1392277b024eSKalle Valo int mwifiex_adhoc_join(struct mwifiex_private *priv, 1393277b024eSKalle Valo struct mwifiex_bssdescriptor *bss_desc) 1394277b024eSKalle Valo { 1395277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, 1396277b024eSKalle Valo "info: adhoc join: curr_bss ssid =%s\n", 1397277b024eSKalle Valo priv->curr_bss_params.bss_descriptor.ssid.ssid); 1398277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, 1399277b024eSKalle Valo "info: adhoc join: curr_bss ssid_len =%u\n", 1400277b024eSKalle Valo priv->curr_bss_params.bss_descriptor.ssid.ssid_len); 1401277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: adhoc join: ssid =%s\n", 1402277b024eSKalle Valo bss_desc->ssid.ssid); 1403277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, "info: adhoc join: ssid_len =%u\n", 1404277b024eSKalle Valo bss_desc->ssid.ssid_len); 1405277b024eSKalle Valo 1406277b024eSKalle Valo /* Check if the requested SSID is already joined */ 1407277b024eSKalle Valo if (priv->curr_bss_params.bss_descriptor.ssid.ssid_len && 1408277b024eSKalle Valo !mwifiex_ssid_cmp(&bss_desc->ssid, 1409277b024eSKalle Valo &priv->curr_bss_params.bss_descriptor.ssid) && 1410277b024eSKalle Valo (priv->curr_bss_params.bss_descriptor.bss_mode == 1411277b024eSKalle Valo NL80211_IFTYPE_ADHOC)) { 1412277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, 1413277b024eSKalle Valo "info: ADHOC_J_CMD: new ad-hoc SSID\t" 1414277b024eSKalle Valo "is the same as current; not attempting to re-join\n"); 1415277b024eSKalle Valo return -1; 1416277b024eSKalle Valo } 1417277b024eSKalle Valo 1418277b024eSKalle Valo if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info) && 1419277b024eSKalle Valo !bss_desc->disable_11n && !bss_desc->disable_11ac && 1420277b024eSKalle Valo priv->adapter->config_bands & BAND_AAC) 1421277b024eSKalle Valo mwifiex_set_11ac_ba_params(priv); 1422277b024eSKalle Valo else 1423277b024eSKalle Valo mwifiex_set_ba_params(priv); 1424277b024eSKalle Valo 1425277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, 1426277b024eSKalle Valo "info: curr_bss_params.channel = %d\n", 1427277b024eSKalle Valo priv->curr_bss_params.bss_descriptor.channel); 1428277b024eSKalle Valo mwifiex_dbg(priv->adapter, INFO, 1429277b024eSKalle Valo "info: curr_bss_params.band = %c\n", 1430277b024eSKalle Valo priv->curr_bss_params.band); 1431277b024eSKalle Valo 1432277b024eSKalle Valo return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_JOIN, 1433277b024eSKalle Valo HostCmd_ACT_GEN_SET, 0, bss_desc, true); 1434277b024eSKalle Valo } 1435277b024eSKalle Valo 1436277b024eSKalle Valo /* 1437277b024eSKalle Valo * This function deauthenticates/disconnects from infra network by sending 1438277b024eSKalle Valo * deauthentication request. 1439277b024eSKalle Valo */ 1440277b024eSKalle Valo static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, u8 *mac) 1441277b024eSKalle Valo { 1442277b024eSKalle Valo u8 mac_address[ETH_ALEN]; 1443277b024eSKalle Valo int ret; 1444277b024eSKalle Valo 1445277b024eSKalle Valo if (!mac || is_zero_ether_addr(mac)) 1446277b024eSKalle Valo memcpy(mac_address, 1447277b024eSKalle Valo priv->curr_bss_params.bss_descriptor.mac_address, 1448277b024eSKalle Valo ETH_ALEN); 1449277b024eSKalle Valo else 1450277b024eSKalle Valo memcpy(mac_address, mac, ETH_ALEN); 1451277b024eSKalle Valo 1452277b024eSKalle Valo ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_DEAUTHENTICATE, 1453277b024eSKalle Valo HostCmd_ACT_GEN_SET, 0, mac_address, true); 1454277b024eSKalle Valo 1455277b024eSKalle Valo return ret; 1456277b024eSKalle Valo } 1457277b024eSKalle Valo 1458277b024eSKalle Valo /* 1459277b024eSKalle Valo * This function deauthenticates/disconnects from a BSS. 1460277b024eSKalle Valo * 1461277b024eSKalle Valo * In case of infra made, it sends deauthentication request, and 1462277b024eSKalle Valo * in case of ad-hoc mode, a stop network request is sent to the firmware. 1463277b024eSKalle Valo * In AP mode, a command to stop bss is sent to firmware. 1464277b024eSKalle Valo */ 1465277b024eSKalle Valo int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac) 1466277b024eSKalle Valo { 1467277b024eSKalle Valo int ret = 0; 1468277b024eSKalle Valo 1469277b024eSKalle Valo if (!priv->media_connected) 1470277b024eSKalle Valo return 0; 1471277b024eSKalle Valo 1472277b024eSKalle Valo switch (priv->bss_mode) { 1473277b024eSKalle Valo case NL80211_IFTYPE_STATION: 1474277b024eSKalle Valo case NL80211_IFTYPE_P2P_CLIENT: 1475277b024eSKalle Valo ret = mwifiex_deauthenticate_infra(priv, mac); 1476277b024eSKalle Valo if (ret) 1477277b024eSKalle Valo cfg80211_disconnected(priv->netdev, 0, NULL, 0, 1478277b024eSKalle Valo true, GFP_KERNEL); 1479277b024eSKalle Valo break; 1480277b024eSKalle Valo case NL80211_IFTYPE_ADHOC: 1481277b024eSKalle Valo return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_AD_HOC_STOP, 1482277b024eSKalle Valo HostCmd_ACT_GEN_SET, 0, NULL, true); 1483277b024eSKalle Valo case NL80211_IFTYPE_AP: 1484277b024eSKalle Valo return mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP, 1485277b024eSKalle Valo HostCmd_ACT_GEN_SET, 0, NULL, true); 1486277b024eSKalle Valo default: 1487277b024eSKalle Valo break; 1488277b024eSKalle Valo } 1489277b024eSKalle Valo 1490277b024eSKalle Valo return ret; 1491277b024eSKalle Valo } 1492277b024eSKalle Valo 1493277b024eSKalle Valo /* This function deauthenticates/disconnects from all BSS. */ 1494277b024eSKalle Valo void mwifiex_deauthenticate_all(struct mwifiex_adapter *adapter) 1495277b024eSKalle Valo { 1496277b024eSKalle Valo struct mwifiex_private *priv; 1497277b024eSKalle Valo int i; 1498277b024eSKalle Valo 1499277b024eSKalle Valo for (i = 0; i < adapter->priv_num; i++) { 1500277b024eSKalle Valo priv = adapter->priv[i]; 1501277b024eSKalle Valo if (priv) 1502277b024eSKalle Valo mwifiex_deauthenticate(priv, NULL); 1503277b024eSKalle Valo } 1504277b024eSKalle Valo } 1505277b024eSKalle Valo EXPORT_SYMBOL_GPL(mwifiex_deauthenticate_all); 1506277b024eSKalle Valo 1507277b024eSKalle Valo /* 1508277b024eSKalle Valo * This function converts band to radio type used in channel TLV. 1509277b024eSKalle Valo */ 1510277b024eSKalle Valo u8 1511277b024eSKalle Valo mwifiex_band_to_radio_type(u8 band) 1512277b024eSKalle Valo { 1513277b024eSKalle Valo switch (band) { 1514277b024eSKalle Valo case BAND_A: 1515277b024eSKalle Valo case BAND_AN: 1516277b024eSKalle Valo case BAND_A | BAND_AN: 1517277b024eSKalle Valo case BAND_A | BAND_AN | BAND_AAC: 1518277b024eSKalle Valo return HostCmd_SCAN_RADIO_TYPE_A; 1519277b024eSKalle Valo case BAND_B: 1520277b024eSKalle Valo case BAND_G: 1521277b024eSKalle Valo case BAND_B | BAND_G: 1522277b024eSKalle Valo default: 1523277b024eSKalle Valo return HostCmd_SCAN_RADIO_TYPE_BG; 1524277b024eSKalle Valo } 1525277b024eSKalle Valo } 1526