1/* 2 * Marvell Wireless LAN device driver: station command handling 3 * 4 * Copyright (C) 2011-2014, Marvell International Ltd. 5 * 6 * This software file (the "File") is distributed by Marvell International 7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991 8 * (the "License"). You may use, redistribute and/or modify this File in 9 * accordance with the terms and conditions of the License, a copy of which 10 * is available by writing to the Free Software Foundation, Inc., 11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the 12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 13 * 14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about 17 * this warranty disclaimer. 18 */ 19 20#include "decl.h" 21#include "ioctl.h" 22#include "util.h" 23#include "fw.h" 24#include "main.h" 25#include "wmm.h" 26#include "11n.h" 27#include "11ac.h" 28 29/* 30 * This function prepares command to set/get RSSI information. 31 * 32 * Preparation includes - 33 * - Setting command ID, action and proper size 34 * - Setting data/beacon average factors 35 * - Resetting SNR/NF/RSSI values in private structure 36 * - Ensuring correct endian-ness 37 */ 38static int 39mwifiex_cmd_802_11_rssi_info(struct mwifiex_private *priv, 40 struct host_cmd_ds_command *cmd, u16 cmd_action) 41{ 42 cmd->command = cpu_to_le16(HostCmd_CMD_RSSI_INFO); 43 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_rssi_info) + 44 S_DS_GEN); 45 cmd->params.rssi_info.action = cpu_to_le16(cmd_action); 46 cmd->params.rssi_info.ndata = cpu_to_le16(priv->data_avg_factor); 47 cmd->params.rssi_info.nbcn = cpu_to_le16(priv->bcn_avg_factor); 48 49 /* Reset SNR/NF/RSSI values in private structure */ 50 priv->data_rssi_last = 0; 51 priv->data_nf_last = 0; 52 priv->data_rssi_avg = 0; 53 priv->data_nf_avg = 0; 54 priv->bcn_rssi_last = 0; 55 priv->bcn_nf_last = 0; 56 priv->bcn_rssi_avg = 0; 57 priv->bcn_nf_avg = 0; 58 59 return 0; 60} 61 62/* 63 * This function prepares command to set MAC control. 64 * 65 * Preparation includes - 66 * - Setting command ID, action and proper size 67 * - Ensuring correct endian-ness 68 */ 69static int mwifiex_cmd_mac_control(struct mwifiex_private *priv, 70 struct host_cmd_ds_command *cmd, 71 u16 cmd_action, u16 *action) 72{ 73 struct host_cmd_ds_mac_control *mac_ctrl = &cmd->params.mac_ctrl; 74 75 if (cmd_action != HostCmd_ACT_GEN_SET) { 76 dev_err(priv->adapter->dev, 77 "mac_control: only support set cmd\n"); 78 return -1; 79 } 80 81 cmd->command = cpu_to_le16(HostCmd_CMD_MAC_CONTROL); 82 cmd->size = 83 cpu_to_le16(sizeof(struct host_cmd_ds_mac_control) + S_DS_GEN); 84 mac_ctrl->action = cpu_to_le16(*action); 85 86 return 0; 87} 88 89/* 90 * This function prepares command to set/get SNMP MIB. 91 * 92 * Preparation includes - 93 * - Setting command ID, action and proper size 94 * - Setting SNMP MIB OID number and value 95 * (as required) 96 * - Ensuring correct endian-ness 97 * 98 * The following SNMP MIB OIDs are supported - 99 * - FRAG_THRESH_I : Fragmentation threshold 100 * - RTS_THRESH_I : RTS threshold 101 * - SHORT_RETRY_LIM_I : Short retry limit 102 * - DOT11D_I : 11d support 103 */ 104static int mwifiex_cmd_802_11_snmp_mib(struct mwifiex_private *priv, 105 struct host_cmd_ds_command *cmd, 106 u16 cmd_action, u32 cmd_oid, 107 u16 *ul_temp) 108{ 109 struct host_cmd_ds_802_11_snmp_mib *snmp_mib = &cmd->params.smib; 110 111 dev_dbg(priv->adapter->dev, "cmd: SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid); 112 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SNMP_MIB); 113 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_snmp_mib) 114 - 1 + S_DS_GEN); 115 116 snmp_mib->oid = cpu_to_le16((u16)cmd_oid); 117 if (cmd_action == HostCmd_ACT_GEN_GET) { 118 snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_GET); 119 snmp_mib->buf_size = cpu_to_le16(MAX_SNMP_BUF_SIZE); 120 le16_add_cpu(&cmd->size, MAX_SNMP_BUF_SIZE); 121 } else if (cmd_action == HostCmd_ACT_GEN_SET) { 122 snmp_mib->query_type = cpu_to_le16(HostCmd_ACT_GEN_SET); 123 snmp_mib->buf_size = cpu_to_le16(sizeof(u16)); 124 *((__le16 *) (snmp_mib->value)) = cpu_to_le16(*ul_temp); 125 le16_add_cpu(&cmd->size, sizeof(u16)); 126 } 127 128 dev_dbg(priv->adapter->dev, 129 "cmd: SNMP_CMD: Action=0x%x, OID=0x%x, OIDSize=0x%x," 130 " Value=0x%x\n", 131 cmd_action, cmd_oid, le16_to_cpu(snmp_mib->buf_size), 132 le16_to_cpu(*(__le16 *) snmp_mib->value)); 133 return 0; 134} 135 136/* 137 * This function prepares command to get log. 138 * 139 * Preparation includes - 140 * - Setting command ID and proper size 141 * - Ensuring correct endian-ness 142 */ 143static int 144mwifiex_cmd_802_11_get_log(struct host_cmd_ds_command *cmd) 145{ 146 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_GET_LOG); 147 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_get_log) + 148 S_DS_GEN); 149 return 0; 150} 151 152/* 153 * This function prepares command to set/get Tx data rate configuration. 154 * 155 * Preparation includes - 156 * - Setting command ID, action and proper size 157 * - Setting configuration index, rate scope and rate drop pattern 158 * parameters (as required) 159 * - Ensuring correct endian-ness 160 */ 161static int mwifiex_cmd_tx_rate_cfg(struct mwifiex_private *priv, 162 struct host_cmd_ds_command *cmd, 163 u16 cmd_action, u16 *pbitmap_rates) 164{ 165 struct host_cmd_ds_tx_rate_cfg *rate_cfg = &cmd->params.tx_rate_cfg; 166 struct mwifiex_rate_scope *rate_scope; 167 struct mwifiex_rate_drop_pattern *rate_drop; 168 u32 i; 169 170 cmd->command = cpu_to_le16(HostCmd_CMD_TX_RATE_CFG); 171 172 rate_cfg->action = cpu_to_le16(cmd_action); 173 rate_cfg->cfg_index = 0; 174 175 rate_scope = (struct mwifiex_rate_scope *) ((u8 *) rate_cfg + 176 sizeof(struct host_cmd_ds_tx_rate_cfg)); 177 rate_scope->type = cpu_to_le16(TLV_TYPE_RATE_SCOPE); 178 rate_scope->length = cpu_to_le16 179 (sizeof(*rate_scope) - sizeof(struct mwifiex_ie_types_header)); 180 if (pbitmap_rates != NULL) { 181 rate_scope->hr_dsss_rate_bitmap = cpu_to_le16(pbitmap_rates[0]); 182 rate_scope->ofdm_rate_bitmap = cpu_to_le16(pbitmap_rates[1]); 183 for (i = 0; 184 i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(u16); 185 i++) 186 rate_scope->ht_mcs_rate_bitmap[i] = 187 cpu_to_le16(pbitmap_rates[2 + i]); 188 if (priv->adapter->fw_api_ver == MWIFIEX_FW_V15) { 189 for (i = 0; 190 i < ARRAY_SIZE(rate_scope->vht_mcs_rate_bitmap); 191 i++) 192 rate_scope->vht_mcs_rate_bitmap[i] = 193 cpu_to_le16(pbitmap_rates[10 + i]); 194 } 195 } else { 196 rate_scope->hr_dsss_rate_bitmap = 197 cpu_to_le16(priv->bitmap_rates[0]); 198 rate_scope->ofdm_rate_bitmap = 199 cpu_to_le16(priv->bitmap_rates[1]); 200 for (i = 0; 201 i < sizeof(rate_scope->ht_mcs_rate_bitmap) / sizeof(u16); 202 i++) 203 rate_scope->ht_mcs_rate_bitmap[i] = 204 cpu_to_le16(priv->bitmap_rates[2 + i]); 205 if (priv->adapter->fw_api_ver == MWIFIEX_FW_V15) { 206 for (i = 0; 207 i < ARRAY_SIZE(rate_scope->vht_mcs_rate_bitmap); 208 i++) 209 rate_scope->vht_mcs_rate_bitmap[i] = 210 cpu_to_le16(priv->bitmap_rates[10 + i]); 211 } 212 } 213 214 rate_drop = (struct mwifiex_rate_drop_pattern *) ((u8 *) rate_scope + 215 sizeof(struct mwifiex_rate_scope)); 216 rate_drop->type = cpu_to_le16(TLV_TYPE_RATE_DROP_CONTROL); 217 rate_drop->length = cpu_to_le16(sizeof(rate_drop->rate_drop_mode)); 218 rate_drop->rate_drop_mode = 0; 219 220 cmd->size = 221 cpu_to_le16(S_DS_GEN + sizeof(struct host_cmd_ds_tx_rate_cfg) + 222 sizeof(struct mwifiex_rate_scope) + 223 sizeof(struct mwifiex_rate_drop_pattern)); 224 225 return 0; 226} 227 228/* 229 * This function prepares command to set/get Tx power configuration. 230 * 231 * Preparation includes - 232 * - Setting command ID, action and proper size 233 * - Setting Tx power mode, power group TLV 234 * (as required) 235 * - Ensuring correct endian-ness 236 */ 237static int mwifiex_cmd_tx_power_cfg(struct host_cmd_ds_command *cmd, 238 u16 cmd_action, 239 struct host_cmd_ds_txpwr_cfg *txp) 240{ 241 struct mwifiex_types_power_group *pg_tlv; 242 struct host_cmd_ds_txpwr_cfg *cmd_txp_cfg = &cmd->params.txp_cfg; 243 244 cmd->command = cpu_to_le16(HostCmd_CMD_TXPWR_CFG); 245 cmd->size = 246 cpu_to_le16(S_DS_GEN + sizeof(struct host_cmd_ds_txpwr_cfg)); 247 switch (cmd_action) { 248 case HostCmd_ACT_GEN_SET: 249 if (txp->mode) { 250 pg_tlv = (struct mwifiex_types_power_group 251 *) ((unsigned long) txp + 252 sizeof(struct host_cmd_ds_txpwr_cfg)); 253 memmove(cmd_txp_cfg, txp, 254 sizeof(struct host_cmd_ds_txpwr_cfg) + 255 sizeof(struct mwifiex_types_power_group) + 256 le16_to_cpu(pg_tlv->length)); 257 258 pg_tlv = (struct mwifiex_types_power_group *) ((u8 *) 259 cmd_txp_cfg + 260 sizeof(struct host_cmd_ds_txpwr_cfg)); 261 cmd->size = cpu_to_le16(le16_to_cpu(cmd->size) + 262 sizeof(struct mwifiex_types_power_group) + 263 le16_to_cpu(pg_tlv->length)); 264 } else { 265 memmove(cmd_txp_cfg, txp, sizeof(*txp)); 266 } 267 cmd_txp_cfg->action = cpu_to_le16(cmd_action); 268 break; 269 case HostCmd_ACT_GEN_GET: 270 cmd_txp_cfg->action = cpu_to_le16(cmd_action); 271 break; 272 } 273 274 return 0; 275} 276 277/* 278 * This function prepares command to get RF Tx power. 279 */ 280static int mwifiex_cmd_rf_tx_power(struct mwifiex_private *priv, 281 struct host_cmd_ds_command *cmd, 282 u16 cmd_action, void *data_buf) 283{ 284 struct host_cmd_ds_rf_tx_pwr *txp = &cmd->params.txp; 285 286 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_rf_tx_pwr) 287 + S_DS_GEN); 288 cmd->command = cpu_to_le16(HostCmd_CMD_RF_TX_PWR); 289 txp->action = cpu_to_le16(cmd_action); 290 291 return 0; 292} 293 294/* 295 * This function prepares command to set rf antenna. 296 */ 297static int mwifiex_cmd_rf_antenna(struct mwifiex_private *priv, 298 struct host_cmd_ds_command *cmd, 299 u16 cmd_action, 300 struct mwifiex_ds_ant_cfg *ant_cfg) 301{ 302 struct host_cmd_ds_rf_ant_mimo *ant_mimo = &cmd->params.ant_mimo; 303 struct host_cmd_ds_rf_ant_siso *ant_siso = &cmd->params.ant_siso; 304 305 cmd->command = cpu_to_le16(HostCmd_CMD_RF_ANTENNA); 306 307 if (cmd_action != HostCmd_ACT_GEN_SET) 308 return 0; 309 310 if (priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2) { 311 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_rf_ant_mimo) + 312 S_DS_GEN); 313 ant_mimo->action_tx = cpu_to_le16(HostCmd_ACT_SET_TX); 314 ant_mimo->tx_ant_mode = cpu_to_le16((u16)ant_cfg->tx_ant); 315 ant_mimo->action_rx = cpu_to_le16(HostCmd_ACT_SET_RX); 316 ant_mimo->rx_ant_mode = cpu_to_le16((u16)ant_cfg->rx_ant); 317 } else { 318 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_rf_ant_siso) + 319 S_DS_GEN); 320 ant_siso->action = cpu_to_le16(HostCmd_ACT_SET_BOTH); 321 ant_siso->ant_mode = cpu_to_le16((u16)ant_cfg->tx_ant); 322 } 323 324 return 0; 325} 326 327/* 328 * This function prepares command to set Host Sleep configuration. 329 * 330 * Preparation includes - 331 * - Setting command ID and proper size 332 * - Setting Host Sleep action, conditions, ARP filters 333 * (as required) 334 * - Ensuring correct endian-ness 335 */ 336static int 337mwifiex_cmd_802_11_hs_cfg(struct mwifiex_private *priv, 338 struct host_cmd_ds_command *cmd, 339 u16 cmd_action, 340 struct mwifiex_hs_config_param *hscfg_param) 341{ 342 struct mwifiex_adapter *adapter = priv->adapter; 343 struct host_cmd_ds_802_11_hs_cfg_enh *hs_cfg = &cmd->params.opt_hs_cfg; 344 bool hs_activate = false; 345 346 if (!hscfg_param) 347 /* New Activate command */ 348 hs_activate = true; 349 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_HS_CFG_ENH); 350 351 if (!hs_activate && 352 (hscfg_param->conditions != cpu_to_le32(HS_CFG_CANCEL)) && 353 ((adapter->arp_filter_size > 0) && 354 (adapter->arp_filter_size <= ARP_FILTER_MAX_BUF_SIZE))) { 355 dev_dbg(adapter->dev, 356 "cmd: Attach %d bytes ArpFilter to HSCfg cmd\n", 357 adapter->arp_filter_size); 358 memcpy(((u8 *) hs_cfg) + 359 sizeof(struct host_cmd_ds_802_11_hs_cfg_enh), 360 adapter->arp_filter, adapter->arp_filter_size); 361 cmd->size = cpu_to_le16 362 (adapter->arp_filter_size + 363 sizeof(struct host_cmd_ds_802_11_hs_cfg_enh) 364 + S_DS_GEN); 365 } else { 366 cmd->size = cpu_to_le16(S_DS_GEN + sizeof(struct 367 host_cmd_ds_802_11_hs_cfg_enh)); 368 } 369 if (hs_activate) { 370 hs_cfg->action = cpu_to_le16(HS_ACTIVATE); 371 hs_cfg->params.hs_activate.resp_ctrl = cpu_to_le16(RESP_NEEDED); 372 } else { 373 hs_cfg->action = cpu_to_le16(HS_CONFIGURE); 374 hs_cfg->params.hs_config.conditions = hscfg_param->conditions; 375 hs_cfg->params.hs_config.gpio = hscfg_param->gpio; 376 hs_cfg->params.hs_config.gap = hscfg_param->gap; 377 dev_dbg(adapter->dev, 378 "cmd: HS_CFG_CMD: condition:0x%x gpio:0x%x gap:0x%x\n", 379 hs_cfg->params.hs_config.conditions, 380 hs_cfg->params.hs_config.gpio, 381 hs_cfg->params.hs_config.gap); 382 } 383 384 return 0; 385} 386 387/* 388 * This function prepares command to set/get MAC address. 389 * 390 * Preparation includes - 391 * - Setting command ID, action and proper size 392 * - Setting MAC address (for SET only) 393 * - Ensuring correct endian-ness 394 */ 395static int mwifiex_cmd_802_11_mac_address(struct mwifiex_private *priv, 396 struct host_cmd_ds_command *cmd, 397 u16 cmd_action) 398{ 399 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_MAC_ADDRESS); 400 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_mac_address) + 401 S_DS_GEN); 402 cmd->result = 0; 403 404 cmd->params.mac_addr.action = cpu_to_le16(cmd_action); 405 406 if (cmd_action == HostCmd_ACT_GEN_SET) 407 memcpy(cmd->params.mac_addr.mac_addr, priv->curr_addr, 408 ETH_ALEN); 409 return 0; 410} 411 412/* 413 * This function prepares command to set MAC multicast address. 414 * 415 * Preparation includes - 416 * - Setting command ID, action and proper size 417 * - Setting MAC multicast address 418 * - Ensuring correct endian-ness 419 */ 420static int 421mwifiex_cmd_mac_multicast_adr(struct host_cmd_ds_command *cmd, 422 u16 cmd_action, 423 struct mwifiex_multicast_list *mcast_list) 424{ 425 struct host_cmd_ds_mac_multicast_adr *mcast_addr = &cmd->params.mc_addr; 426 427 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_mac_multicast_adr) + 428 S_DS_GEN); 429 cmd->command = cpu_to_le16(HostCmd_CMD_MAC_MULTICAST_ADR); 430 431 mcast_addr->action = cpu_to_le16(cmd_action); 432 mcast_addr->num_of_adrs = 433 cpu_to_le16((u16) mcast_list->num_multicast_addr); 434 memcpy(mcast_addr->mac_list, mcast_list->mac_list, 435 mcast_list->num_multicast_addr * ETH_ALEN); 436 437 return 0; 438} 439 440/* 441 * This function prepares command to deauthenticate. 442 * 443 * Preparation includes - 444 * - Setting command ID and proper size 445 * - Setting AP MAC address and reason code 446 * - Ensuring correct endian-ness 447 */ 448static int mwifiex_cmd_802_11_deauthenticate(struct mwifiex_private *priv, 449 struct host_cmd_ds_command *cmd, 450 u8 *mac) 451{ 452 struct host_cmd_ds_802_11_deauthenticate *deauth = &cmd->params.deauth; 453 454 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_DEAUTHENTICATE); 455 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_deauthenticate) 456 + S_DS_GEN); 457 458 /* Set AP MAC address */ 459 memcpy(deauth->mac_addr, mac, ETH_ALEN); 460 461 dev_dbg(priv->adapter->dev, "cmd: Deauth: %pM\n", deauth->mac_addr); 462 463 deauth->reason_code = cpu_to_le16(WLAN_REASON_DEAUTH_LEAVING); 464 465 return 0; 466} 467 468/* 469 * This function prepares command to stop Ad-Hoc network. 470 * 471 * Preparation includes - 472 * - Setting command ID and proper size 473 * - Ensuring correct endian-ness 474 */ 475static int mwifiex_cmd_802_11_ad_hoc_stop(struct host_cmd_ds_command *cmd) 476{ 477 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_AD_HOC_STOP); 478 cmd->size = cpu_to_le16(S_DS_GEN); 479 return 0; 480} 481 482/* 483 * This function sets WEP key(s) to key parameter TLV(s). 484 * 485 * Multi-key parameter TLVs are supported, so we can send multiple 486 * WEP keys in a single buffer. 487 */ 488static int 489mwifiex_set_keyparamset_wep(struct mwifiex_private *priv, 490 struct mwifiex_ie_type_key_param_set *key_param_set, 491 u16 *key_param_len) 492{ 493 int cur_key_param_len; 494 u8 i; 495 496 /* Multi-key_param_set TLV is supported */ 497 for (i = 0; i < NUM_WEP_KEYS; i++) { 498 if ((priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP40) || 499 (priv->wep_key[i].key_length == WLAN_KEY_LEN_WEP104)) { 500 key_param_set->type = 501 cpu_to_le16(TLV_TYPE_KEY_MATERIAL); 502/* Key_param_set WEP fixed length */ 503#define KEYPARAMSET_WEP_FIXED_LEN 8 504 key_param_set->length = cpu_to_le16((u16) 505 (priv->wep_key[i]. 506 key_length + 507 KEYPARAMSET_WEP_FIXED_LEN)); 508 key_param_set->key_type_id = 509 cpu_to_le16(KEY_TYPE_ID_WEP); 510 key_param_set->key_info = 511 cpu_to_le16(KEY_ENABLED | KEY_UNICAST | 512 KEY_MCAST); 513 key_param_set->key_len = 514 cpu_to_le16(priv->wep_key[i].key_length); 515 /* Set WEP key index */ 516 key_param_set->key[0] = i; 517 /* Set default Tx key flag */ 518 if (i == 519 (priv-> 520 wep_key_curr_index & HostCmd_WEP_KEY_INDEX_MASK)) 521 key_param_set->key[1] = 1; 522 else 523 key_param_set->key[1] = 0; 524 memmove(&key_param_set->key[2], 525 priv->wep_key[i].key_material, 526 priv->wep_key[i].key_length); 527 528 cur_key_param_len = priv->wep_key[i].key_length + 529 KEYPARAMSET_WEP_FIXED_LEN + 530 sizeof(struct mwifiex_ie_types_header); 531 *key_param_len += (u16) cur_key_param_len; 532 key_param_set = 533 (struct mwifiex_ie_type_key_param_set *) 534 ((u8 *)key_param_set + 535 cur_key_param_len); 536 } else if (!priv->wep_key[i].key_length) { 537 continue; 538 } else { 539 dev_err(priv->adapter->dev, 540 "key%d Length = %d is incorrect\n", 541 (i + 1), priv->wep_key[i].key_length); 542 return -1; 543 } 544 } 545 546 return 0; 547} 548 549/* This function populates key material v2 command 550 * to set network key for AES & CMAC AES. 551 */ 552static int mwifiex_set_aes_key_v2(struct mwifiex_private *priv, 553 struct host_cmd_ds_command *cmd, 554 struct mwifiex_ds_encrypt_key *enc_key, 555 struct host_cmd_ds_802_11_key_material_v2 *km) 556{ 557 struct mwifiex_adapter *adapter = priv->adapter; 558 u16 size, len = KEY_PARAMS_FIXED_LEN; 559 560 if (enc_key->is_igtk_key) { 561 dev_dbg(adapter->dev, "%s: Set CMAC AES Key\n", __func__); 562 if (enc_key->is_rx_seq_valid) 563 memcpy(km->key_param_set.key_params.cmac_aes.ipn, 564 enc_key->pn, enc_key->pn_len); 565 km->key_param_set.key_info &= cpu_to_le16(~KEY_MCAST); 566 km->key_param_set.key_info |= cpu_to_le16(KEY_IGTK); 567 km->key_param_set.key_type = KEY_TYPE_ID_AES_CMAC; 568 km->key_param_set.key_params.cmac_aes.key_len = 569 cpu_to_le16(enc_key->key_len); 570 memcpy(km->key_param_set.key_params.cmac_aes.key, 571 enc_key->key_material, enc_key->key_len); 572 len += sizeof(struct mwifiex_cmac_aes_param); 573 } else { 574 dev_dbg(adapter->dev, "%s: Set AES Key\n", __func__); 575 if (enc_key->is_rx_seq_valid) 576 memcpy(km->key_param_set.key_params.aes.pn, 577 enc_key->pn, enc_key->pn_len); 578 km->key_param_set.key_type = KEY_TYPE_ID_AES; 579 km->key_param_set.key_params.aes.key_len = 580 cpu_to_le16(enc_key->key_len); 581 memcpy(km->key_param_set.key_params.aes.key, 582 enc_key->key_material, enc_key->key_len); 583 len += sizeof(struct mwifiex_aes_param); 584 } 585 586 km->key_param_set.len = cpu_to_le16(len); 587 size = len + sizeof(struct mwifiex_ie_types_header) + 588 sizeof(km->action) + S_DS_GEN; 589 cmd->size = cpu_to_le16(size); 590 591 return 0; 592} 593 594/* This function prepares command to set/get/reset network key(s). 595 * This function prepares key material command for V2 format. 596 * Preparation includes - 597 * - Setting command ID, action and proper size 598 * - Setting WEP keys, WAPI keys or WPA keys along with required 599 * encryption (TKIP, AES) (as required) 600 * - Ensuring correct endian-ness 601 */ 602static int 603mwifiex_cmd_802_11_key_material_v2(struct mwifiex_private *priv, 604 struct host_cmd_ds_command *cmd, 605 u16 cmd_action, u32 cmd_oid, 606 struct mwifiex_ds_encrypt_key *enc_key) 607{ 608 struct mwifiex_adapter *adapter = priv->adapter; 609 u8 *mac = enc_key->mac_addr; 610 u16 key_info, len = KEY_PARAMS_FIXED_LEN; 611 struct host_cmd_ds_802_11_key_material_v2 *km = 612 &cmd->params.key_material_v2; 613 614 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL); 615 km->action = cpu_to_le16(cmd_action); 616 617 if (cmd_action == HostCmd_ACT_GEN_GET) { 618 dev_dbg(adapter->dev, "%s: Get key\n", __func__); 619 km->key_param_set.key_idx = 620 enc_key->key_index & KEY_INDEX_MASK; 621 km->key_param_set.type = cpu_to_le16(TLV_TYPE_KEY_PARAM_V2); 622 km->key_param_set.len = cpu_to_le16(KEY_PARAMS_FIXED_LEN); 623 memcpy(km->key_param_set.mac_addr, mac, ETH_ALEN); 624 625 if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST) 626 key_info = KEY_UNICAST; 627 else 628 key_info = KEY_MCAST; 629 630 if (enc_key->is_igtk_key) 631 key_info |= KEY_IGTK; 632 633 km->key_param_set.key_info = cpu_to_le16(key_info); 634 635 cmd->size = cpu_to_le16(sizeof(struct mwifiex_ie_types_header) + 636 S_DS_GEN + KEY_PARAMS_FIXED_LEN + 637 sizeof(km->action)); 638 return 0; 639 } 640 641 memset(&km->key_param_set, 0, 642 sizeof(struct mwifiex_ie_type_key_param_set_v2)); 643 644 if (enc_key->key_disable) { 645 dev_dbg(adapter->dev, "%s: Remove key\n", __func__); 646 km->action = cpu_to_le16(HostCmd_ACT_GEN_REMOVE); 647 km->key_param_set.type = cpu_to_le16(TLV_TYPE_KEY_PARAM_V2); 648 km->key_param_set.len = cpu_to_le16(KEY_PARAMS_FIXED_LEN); 649 km->key_param_set.key_idx = enc_key->key_index & KEY_INDEX_MASK; 650 key_info = KEY_MCAST | KEY_UNICAST; 651 km->key_param_set.key_info = cpu_to_le16(key_info); 652 memcpy(km->key_param_set.mac_addr, mac, ETH_ALEN); 653 cmd->size = cpu_to_le16(sizeof(struct mwifiex_ie_types_header) + 654 S_DS_GEN + KEY_PARAMS_FIXED_LEN + 655 sizeof(km->action)); 656 return 0; 657 } 658 659 km->action = cpu_to_le16(HostCmd_ACT_GEN_SET); 660 km->key_param_set.key_idx = enc_key->key_index & KEY_INDEX_MASK; 661 km->key_param_set.type = cpu_to_le16(TLV_TYPE_KEY_PARAM_V2); 662 key_info = KEY_ENABLED; 663 memcpy(km->key_param_set.mac_addr, mac, ETH_ALEN); 664 665 if (enc_key->key_len <= WLAN_KEY_LEN_WEP104) { 666 dev_dbg(adapter->dev, "%s: Set WEP Key\n", __func__); 667 len += sizeof(struct mwifiex_wep_param); 668 km->key_param_set.len = cpu_to_le16(len); 669 km->key_param_set.key_type = KEY_TYPE_ID_WEP; 670 671 if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { 672 key_info |= KEY_MCAST | KEY_UNICAST; 673 } else { 674 if (enc_key->is_current_wep_key) { 675 key_info |= KEY_MCAST | KEY_UNICAST; 676 if (km->key_param_set.key_idx == 677 (priv->wep_key_curr_index & KEY_INDEX_MASK)) 678 key_info |= KEY_DEFAULT; 679 } else { 680 if (mac) { 681 if (is_broadcast_ether_addr(mac)) 682 key_info |= KEY_MCAST; 683 else 684 key_info |= KEY_UNICAST | 685 KEY_DEFAULT; 686 } else { 687 key_info |= KEY_MCAST; 688 } 689 } 690 } 691 km->key_param_set.key_info = cpu_to_le16(key_info); 692 693 km->key_param_set.key_params.wep.key_len = 694 cpu_to_le16(enc_key->key_len); 695 memcpy(km->key_param_set.key_params.wep.key, 696 enc_key->key_material, enc_key->key_len); 697 698 cmd->size = cpu_to_le16(sizeof(struct mwifiex_ie_types_header) + 699 len + sizeof(km->action) + S_DS_GEN); 700 return 0; 701 } 702 703 if (is_broadcast_ether_addr(mac)) 704 key_info |= KEY_MCAST | KEY_RX_KEY; 705 else 706 key_info |= KEY_UNICAST | KEY_TX_KEY | KEY_RX_KEY; 707 708 if (enc_key->is_wapi_key) { 709 dev_dbg(adapter->dev, "%s: Set WAPI Key\n", __func__); 710 km->key_param_set.key_type = KEY_TYPE_ID_WAPI; 711 memcpy(km->key_param_set.key_params.wapi.pn, enc_key->pn, 712 PN_LEN); 713 km->key_param_set.key_params.wapi.key_len = 714 cpu_to_le16(enc_key->key_len); 715 memcpy(km->key_param_set.key_params.wapi.key, 716 enc_key->key_material, enc_key->key_len); 717 if (is_broadcast_ether_addr(mac)) 718 priv->sec_info.wapi_key_on = true; 719 720 if (!priv->sec_info.wapi_key_on) 721 key_info |= KEY_DEFAULT; 722 km->key_param_set.key_info = cpu_to_le16(key_info); 723 724 len += sizeof(struct mwifiex_wapi_param); 725 km->key_param_set.len = cpu_to_le16(len); 726 cmd->size = cpu_to_le16(sizeof(struct mwifiex_ie_types_header) + 727 len + sizeof(km->action) + S_DS_GEN); 728 return 0; 729 } 730 731 if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { 732 key_info |= KEY_DEFAULT; 733 /* Enable unicast bit for WPA-NONE/ADHOC_AES */ 734 if (!priv->sec_info.wpa2_enabled && 735 !is_broadcast_ether_addr(mac)) 736 key_info |= KEY_UNICAST; 737 } else { 738 /* Enable default key for WPA/WPA2 */ 739 if (!priv->wpa_is_gtk_set) 740 key_info |= KEY_DEFAULT; 741 } 742 743 km->key_param_set.key_info = cpu_to_le16(key_info); 744 745 if (enc_key->key_len == WLAN_KEY_LEN_CCMP) 746 return mwifiex_set_aes_key_v2(priv, cmd, enc_key, km); 747 748 if (enc_key->key_len == WLAN_KEY_LEN_TKIP) { 749 dev_dbg(adapter->dev, "%s: Set TKIP Key\n", __func__); 750 if (enc_key->is_rx_seq_valid) 751 memcpy(km->key_param_set.key_params.tkip.pn, 752 enc_key->pn, enc_key->pn_len); 753 km->key_param_set.key_type = KEY_TYPE_ID_TKIP; 754 km->key_param_set.key_params.tkip.key_len = 755 cpu_to_le16(enc_key->key_len); 756 memcpy(km->key_param_set.key_params.tkip.key, 757 enc_key->key_material, enc_key->key_len); 758 759 len += sizeof(struct mwifiex_tkip_param); 760 km->key_param_set.len = cpu_to_le16(len); 761 cmd->size = cpu_to_le16(sizeof(struct mwifiex_ie_types_header) + 762 len + sizeof(km->action) + S_DS_GEN); 763 } 764 765 return 0; 766} 767 768/* 769 * This function prepares command to set/get/reset network key(s). 770 * This function prepares key material command for V1 format. 771 * 772 * Preparation includes - 773 * - Setting command ID, action and proper size 774 * - Setting WEP keys, WAPI keys or WPA keys along with required 775 * encryption (TKIP, AES) (as required) 776 * - Ensuring correct endian-ness 777 */ 778static int 779mwifiex_cmd_802_11_key_material_v1(struct mwifiex_private *priv, 780 struct host_cmd_ds_command *cmd, 781 u16 cmd_action, u32 cmd_oid, 782 struct mwifiex_ds_encrypt_key *enc_key) 783{ 784 struct host_cmd_ds_802_11_key_material *key_material = 785 &cmd->params.key_material; 786 struct host_cmd_tlv_mac_addr *tlv_mac; 787 u16 key_param_len = 0, cmd_size; 788 int ret = 0; 789 790 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_KEY_MATERIAL); 791 key_material->action = cpu_to_le16(cmd_action); 792 793 if (cmd_action == HostCmd_ACT_GEN_GET) { 794 cmd->size = 795 cpu_to_le16(sizeof(key_material->action) + S_DS_GEN); 796 return ret; 797 } 798 799 if (!enc_key) { 800 memset(&key_material->key_param_set, 0, 801 (NUM_WEP_KEYS * 802 sizeof(struct mwifiex_ie_type_key_param_set))); 803 ret = mwifiex_set_keyparamset_wep(priv, 804 &key_material->key_param_set, 805 &key_param_len); 806 cmd->size = cpu_to_le16(key_param_len + 807 sizeof(key_material->action) + S_DS_GEN); 808 return ret; 809 } else 810 memset(&key_material->key_param_set, 0, 811 sizeof(struct mwifiex_ie_type_key_param_set)); 812 if (enc_key->is_wapi_key) { 813 dev_dbg(priv->adapter->dev, "info: Set WAPI Key\n"); 814 key_material->key_param_set.key_type_id = 815 cpu_to_le16(KEY_TYPE_ID_WAPI); 816 if (cmd_oid == KEY_INFO_ENABLED) 817 key_material->key_param_set.key_info = 818 cpu_to_le16(KEY_ENABLED); 819 else 820 key_material->key_param_set.key_info = 821 cpu_to_le16(!KEY_ENABLED); 822 823 key_material->key_param_set.key[0] = enc_key->key_index; 824 if (!priv->sec_info.wapi_key_on) 825 key_material->key_param_set.key[1] = 1; 826 else 827 /* set 0 when re-key */ 828 key_material->key_param_set.key[1] = 0; 829 830 if (!is_broadcast_ether_addr(enc_key->mac_addr)) { 831 /* WAPI pairwise key: unicast */ 832 key_material->key_param_set.key_info |= 833 cpu_to_le16(KEY_UNICAST); 834 } else { /* WAPI group key: multicast */ 835 key_material->key_param_set.key_info |= 836 cpu_to_le16(KEY_MCAST); 837 priv->sec_info.wapi_key_on = true; 838 } 839 840 key_material->key_param_set.type = 841 cpu_to_le16(TLV_TYPE_KEY_MATERIAL); 842 key_material->key_param_set.key_len = 843 cpu_to_le16(WAPI_KEY_LEN); 844 memcpy(&key_material->key_param_set.key[2], 845 enc_key->key_material, enc_key->key_len); 846 memcpy(&key_material->key_param_set.key[2 + enc_key->key_len], 847 enc_key->pn, PN_LEN); 848 key_material->key_param_set.length = 849 cpu_to_le16(WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN); 850 851 key_param_len = (WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN) + 852 sizeof(struct mwifiex_ie_types_header); 853 cmd->size = cpu_to_le16(sizeof(key_material->action) 854 + S_DS_GEN + key_param_len); 855 return ret; 856 } 857 if (enc_key->key_len == WLAN_KEY_LEN_CCMP) { 858 if (enc_key->is_igtk_key) { 859 dev_dbg(priv->adapter->dev, "cmd: CMAC_AES\n"); 860 key_material->key_param_set.key_type_id = 861 cpu_to_le16(KEY_TYPE_ID_AES_CMAC); 862 if (cmd_oid == KEY_INFO_ENABLED) 863 key_material->key_param_set.key_info = 864 cpu_to_le16(KEY_ENABLED); 865 else 866 key_material->key_param_set.key_info = 867 cpu_to_le16(!KEY_ENABLED); 868 869 key_material->key_param_set.key_info |= 870 cpu_to_le16(KEY_IGTK); 871 } else { 872 dev_dbg(priv->adapter->dev, "cmd: WPA_AES\n"); 873 key_material->key_param_set.key_type_id = 874 cpu_to_le16(KEY_TYPE_ID_AES); 875 if (cmd_oid == KEY_INFO_ENABLED) 876 key_material->key_param_set.key_info = 877 cpu_to_le16(KEY_ENABLED); 878 else 879 key_material->key_param_set.key_info = 880 cpu_to_le16(!KEY_ENABLED); 881 882 if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST) 883 /* AES pairwise key: unicast */ 884 key_material->key_param_set.key_info |= 885 cpu_to_le16(KEY_UNICAST); 886 else /* AES group key: multicast */ 887 key_material->key_param_set.key_info |= 888 cpu_to_le16(KEY_MCAST); 889 } 890 } else if (enc_key->key_len == WLAN_KEY_LEN_TKIP) { 891 dev_dbg(priv->adapter->dev, "cmd: WPA_TKIP\n"); 892 key_material->key_param_set.key_type_id = 893 cpu_to_le16(KEY_TYPE_ID_TKIP); 894 key_material->key_param_set.key_info = 895 cpu_to_le16(KEY_ENABLED); 896 897 if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST) 898 /* TKIP pairwise key: unicast */ 899 key_material->key_param_set.key_info |= 900 cpu_to_le16(KEY_UNICAST); 901 else /* TKIP group key: multicast */ 902 key_material->key_param_set.key_info |= 903 cpu_to_le16(KEY_MCAST); 904 } 905 906 if (key_material->key_param_set.key_type_id) { 907 key_material->key_param_set.type = 908 cpu_to_le16(TLV_TYPE_KEY_MATERIAL); 909 key_material->key_param_set.key_len = 910 cpu_to_le16((u16) enc_key->key_len); 911 memcpy(key_material->key_param_set.key, enc_key->key_material, 912 enc_key->key_len); 913 key_material->key_param_set.length = 914 cpu_to_le16((u16) enc_key->key_len + 915 KEYPARAMSET_FIXED_LEN); 916 917 key_param_len = (u16)(enc_key->key_len + KEYPARAMSET_FIXED_LEN) 918 + sizeof(struct mwifiex_ie_types_header); 919 920 if (le16_to_cpu(key_material->key_param_set.key_type_id) == 921 KEY_TYPE_ID_AES_CMAC) { 922 struct mwifiex_cmac_param *param = 923 (void *)key_material->key_param_set.key; 924 925 memcpy(param->ipn, enc_key->pn, IGTK_PN_LEN); 926 memcpy(param->key, enc_key->key_material, 927 WLAN_KEY_LEN_AES_CMAC); 928 929 key_param_len = sizeof(struct mwifiex_cmac_param); 930 key_material->key_param_set.key_len = 931 cpu_to_le16(key_param_len); 932 key_param_len += KEYPARAMSET_FIXED_LEN; 933 key_material->key_param_set.length = 934 cpu_to_le16(key_param_len); 935 key_param_len += sizeof(struct mwifiex_ie_types_header); 936 } 937 938 cmd->size = cpu_to_le16(sizeof(key_material->action) + S_DS_GEN 939 + key_param_len); 940 941 if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) { 942 tlv_mac = (void *)((u8 *)&key_material->key_param_set + 943 key_param_len); 944 tlv_mac->header.type = 945 cpu_to_le16(TLV_TYPE_STA_MAC_ADDR); 946 tlv_mac->header.len = cpu_to_le16(ETH_ALEN); 947 memcpy(tlv_mac->mac_addr, enc_key->mac_addr, ETH_ALEN); 948 cmd_size = key_param_len + S_DS_GEN + 949 sizeof(key_material->action) + 950 sizeof(struct host_cmd_tlv_mac_addr); 951 } else { 952 cmd_size = key_param_len + S_DS_GEN + 953 sizeof(key_material->action); 954 } 955 cmd->size = cpu_to_le16(cmd_size); 956 } 957 958 return ret; 959} 960 961/* Wrapper function for setting network key depending upon FW KEY API version */ 962static int 963mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv, 964 struct host_cmd_ds_command *cmd, 965 u16 cmd_action, u32 cmd_oid, 966 struct mwifiex_ds_encrypt_key *enc_key) 967{ 968 if (priv->adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2) 969 return mwifiex_cmd_802_11_key_material_v2(priv, cmd, 970 cmd_action, cmd_oid, 971 enc_key); 972 973 else 974 return mwifiex_cmd_802_11_key_material_v1(priv, cmd, 975 cmd_action, cmd_oid, 976 enc_key); 977} 978 979/* 980 * This function prepares command to set/get 11d domain information. 981 * 982 * Preparation includes - 983 * - Setting command ID, action and proper size 984 * - Setting domain information fields (for SET only) 985 * - Ensuring correct endian-ness 986 */ 987static int mwifiex_cmd_802_11d_domain_info(struct mwifiex_private *priv, 988 struct host_cmd_ds_command *cmd, 989 u16 cmd_action) 990{ 991 struct mwifiex_adapter *adapter = priv->adapter; 992 struct host_cmd_ds_802_11d_domain_info *domain_info = 993 &cmd->params.domain_info; 994 struct mwifiex_ietypes_domain_param_set *domain = 995 &domain_info->domain; 996 u8 no_of_triplet = adapter->domain_reg.no_of_triplet; 997 998 dev_dbg(adapter->dev, "info: 11D: no_of_triplet=0x%x\n", no_of_triplet); 999 1000 cmd->command = cpu_to_le16(HostCmd_CMD_802_11D_DOMAIN_INFO); 1001 domain_info->action = cpu_to_le16(cmd_action); 1002 if (cmd_action == HostCmd_ACT_GEN_GET) { 1003 cmd->size = cpu_to_le16(sizeof(domain_info->action) + S_DS_GEN); 1004 return 0; 1005 } 1006 1007 /* Set domain info fields */ 1008 domain->header.type = cpu_to_le16(WLAN_EID_COUNTRY); 1009 memcpy(domain->country_code, adapter->domain_reg.country_code, 1010 sizeof(domain->country_code)); 1011 1012 domain->header.len = 1013 cpu_to_le16((no_of_triplet * 1014 sizeof(struct ieee80211_country_ie_triplet)) 1015 + sizeof(domain->country_code)); 1016 1017 if (no_of_triplet) { 1018 memcpy(domain->triplet, adapter->domain_reg.triplet, 1019 no_of_triplet * sizeof(struct 1020 ieee80211_country_ie_triplet)); 1021 1022 cmd->size = cpu_to_le16(sizeof(domain_info->action) + 1023 le16_to_cpu(domain->header.len) + 1024 sizeof(struct mwifiex_ie_types_header) 1025 + S_DS_GEN); 1026 } else { 1027 cmd->size = cpu_to_le16(sizeof(domain_info->action) + S_DS_GEN); 1028 } 1029 1030 return 0; 1031} 1032 1033/* 1034 * This function prepares command to set/get IBSS coalescing status. 1035 * 1036 * Preparation includes - 1037 * - Setting command ID, action and proper size 1038 * - Setting status to enable or disable (for SET only) 1039 * - Ensuring correct endian-ness 1040 */ 1041static int mwifiex_cmd_ibss_coalescing_status(struct host_cmd_ds_command *cmd, 1042 u16 cmd_action, u16 *enable) 1043{ 1044 struct host_cmd_ds_802_11_ibss_status *ibss_coal = 1045 &(cmd->params.ibss_coalescing); 1046 1047 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_IBSS_COALESCING_STATUS); 1048 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_ibss_status) + 1049 S_DS_GEN); 1050 cmd->result = 0; 1051 ibss_coal->action = cpu_to_le16(cmd_action); 1052 1053 switch (cmd_action) { 1054 case HostCmd_ACT_GEN_SET: 1055 if (enable) 1056 ibss_coal->enable = cpu_to_le16(*enable); 1057 else 1058 ibss_coal->enable = 0; 1059 break; 1060 1061 /* In other case.. Nothing to do */ 1062 case HostCmd_ACT_GEN_GET: 1063 default: 1064 break; 1065 } 1066 1067 return 0; 1068} 1069 1070/* 1071 * This function prepares command to set/get register value. 1072 * 1073 * Preparation includes - 1074 * - Setting command ID, action and proper size 1075 * - Setting register offset (for both GET and SET) and 1076 * register value (for SET only) 1077 * - Ensuring correct endian-ness 1078 * 1079 * The following type of registers can be accessed with this function - 1080 * - MAC register 1081 * - BBP register 1082 * - RF register 1083 * - PMIC register 1084 * - CAU register 1085 * - EEPROM 1086 */ 1087static int mwifiex_cmd_reg_access(struct host_cmd_ds_command *cmd, 1088 u16 cmd_action, void *data_buf) 1089{ 1090 struct mwifiex_ds_reg_rw *reg_rw = data_buf; 1091 1092 switch (le16_to_cpu(cmd->command)) { 1093 case HostCmd_CMD_MAC_REG_ACCESS: 1094 { 1095 struct host_cmd_ds_mac_reg_access *mac_reg; 1096 1097 cmd->size = cpu_to_le16(sizeof(*mac_reg) + S_DS_GEN); 1098 mac_reg = &cmd->params.mac_reg; 1099 mac_reg->action = cpu_to_le16(cmd_action); 1100 mac_reg->offset = 1101 cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); 1102 mac_reg->value = reg_rw->value; 1103 break; 1104 } 1105 case HostCmd_CMD_BBP_REG_ACCESS: 1106 { 1107 struct host_cmd_ds_bbp_reg_access *bbp_reg; 1108 1109 cmd->size = cpu_to_le16(sizeof(*bbp_reg) + S_DS_GEN); 1110 bbp_reg = &cmd->params.bbp_reg; 1111 bbp_reg->action = cpu_to_le16(cmd_action); 1112 bbp_reg->offset = 1113 cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); 1114 bbp_reg->value = (u8) le32_to_cpu(reg_rw->value); 1115 break; 1116 } 1117 case HostCmd_CMD_RF_REG_ACCESS: 1118 { 1119 struct host_cmd_ds_rf_reg_access *rf_reg; 1120 1121 cmd->size = cpu_to_le16(sizeof(*rf_reg) + S_DS_GEN); 1122 rf_reg = &cmd->params.rf_reg; 1123 rf_reg->action = cpu_to_le16(cmd_action); 1124 rf_reg->offset = cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); 1125 rf_reg->value = (u8) le32_to_cpu(reg_rw->value); 1126 break; 1127 } 1128 case HostCmd_CMD_PMIC_REG_ACCESS: 1129 { 1130 struct host_cmd_ds_pmic_reg_access *pmic_reg; 1131 1132 cmd->size = cpu_to_le16(sizeof(*pmic_reg) + S_DS_GEN); 1133 pmic_reg = &cmd->params.pmic_reg; 1134 pmic_reg->action = cpu_to_le16(cmd_action); 1135 pmic_reg->offset = 1136 cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); 1137 pmic_reg->value = (u8) le32_to_cpu(reg_rw->value); 1138 break; 1139 } 1140 case HostCmd_CMD_CAU_REG_ACCESS: 1141 { 1142 struct host_cmd_ds_rf_reg_access *cau_reg; 1143 1144 cmd->size = cpu_to_le16(sizeof(*cau_reg) + S_DS_GEN); 1145 cau_reg = &cmd->params.rf_reg; 1146 cau_reg->action = cpu_to_le16(cmd_action); 1147 cau_reg->offset = 1148 cpu_to_le16((u16) le32_to_cpu(reg_rw->offset)); 1149 cau_reg->value = (u8) le32_to_cpu(reg_rw->value); 1150 break; 1151 } 1152 case HostCmd_CMD_802_11_EEPROM_ACCESS: 1153 { 1154 struct mwifiex_ds_read_eeprom *rd_eeprom = data_buf; 1155 struct host_cmd_ds_802_11_eeprom_access *cmd_eeprom = 1156 &cmd->params.eeprom; 1157 1158 cmd->size = cpu_to_le16(sizeof(*cmd_eeprom) + S_DS_GEN); 1159 cmd_eeprom->action = cpu_to_le16(cmd_action); 1160 cmd_eeprom->offset = rd_eeprom->offset; 1161 cmd_eeprom->byte_count = rd_eeprom->byte_count; 1162 cmd_eeprom->value = 0; 1163 break; 1164 } 1165 default: 1166 return -1; 1167 } 1168 1169 return 0; 1170} 1171 1172/* 1173 * This function prepares command to set PCI-Express 1174 * host buffer configuration 1175 * 1176 * Preparation includes - 1177 * - Setting command ID, action and proper size 1178 * - Setting host buffer configuration 1179 * - Ensuring correct endian-ness 1180 */ 1181static int 1182mwifiex_cmd_pcie_host_spec(struct mwifiex_private *priv, 1183 struct host_cmd_ds_command *cmd, u16 action) 1184{ 1185 struct host_cmd_ds_pcie_details *host_spec = 1186 &cmd->params.pcie_host_spec; 1187 struct pcie_service_card *card = priv->adapter->card; 1188 1189 cmd->command = cpu_to_le16(HostCmd_CMD_PCIE_DESC_DETAILS); 1190 cmd->size = cpu_to_le16(sizeof(struct 1191 host_cmd_ds_pcie_details) + S_DS_GEN); 1192 cmd->result = 0; 1193 1194 memset(host_spec, 0, sizeof(struct host_cmd_ds_pcie_details)); 1195 1196 if (action != HostCmd_ACT_GEN_SET) 1197 return 0; 1198 1199 /* Send the ring base addresses and count to firmware */ 1200 host_spec->txbd_addr_lo = (u32)(card->txbd_ring_pbase); 1201 host_spec->txbd_addr_hi = (u32)(((u64)card->txbd_ring_pbase)>>32); 1202 host_spec->txbd_count = MWIFIEX_MAX_TXRX_BD; 1203 host_spec->rxbd_addr_lo = (u32)(card->rxbd_ring_pbase); 1204 host_spec->rxbd_addr_hi = (u32)(((u64)card->rxbd_ring_pbase)>>32); 1205 host_spec->rxbd_count = MWIFIEX_MAX_TXRX_BD; 1206 host_spec->evtbd_addr_lo = (u32)(card->evtbd_ring_pbase); 1207 host_spec->evtbd_addr_hi = (u32)(((u64)card->evtbd_ring_pbase)>>32); 1208 host_spec->evtbd_count = MWIFIEX_MAX_EVT_BD; 1209 if (card->sleep_cookie_vbase) { 1210 host_spec->sleep_cookie_addr_lo = 1211 (u32)(card->sleep_cookie_pbase); 1212 host_spec->sleep_cookie_addr_hi = 1213 (u32)(((u64)(card->sleep_cookie_pbase)) >> 32); 1214 dev_dbg(priv->adapter->dev, "sleep_cook_lo phy addr: 0x%x\n", 1215 host_spec->sleep_cookie_addr_lo); 1216 } 1217 1218 return 0; 1219} 1220 1221/* 1222 * This function prepares command for event subscription, configuration 1223 * and query. Events can be subscribed or unsubscribed. Current subscribed 1224 * events can be queried. Also, current subscribed events are reported in 1225 * every FW response. 1226 */ 1227static int 1228mwifiex_cmd_802_11_subsc_evt(struct mwifiex_private *priv, 1229 struct host_cmd_ds_command *cmd, 1230 struct mwifiex_ds_misc_subsc_evt *subsc_evt_cfg) 1231{ 1232 struct host_cmd_ds_802_11_subsc_evt *subsc_evt = &cmd->params.subsc_evt; 1233 struct mwifiex_ie_types_rssi_threshold *rssi_tlv; 1234 u16 event_bitmap; 1235 u8 *pos; 1236 1237 cmd->command = cpu_to_le16(HostCmd_CMD_802_11_SUBSCRIBE_EVENT); 1238 cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_subsc_evt) + 1239 S_DS_GEN); 1240 1241 subsc_evt->action = cpu_to_le16(subsc_evt_cfg->action); 1242 dev_dbg(priv->adapter->dev, "cmd: action: %d\n", subsc_evt_cfg->action); 1243 1244 /*For query requests, no configuration TLV structures are to be added.*/ 1245 if (subsc_evt_cfg->action == HostCmd_ACT_GEN_GET) 1246 return 0; 1247 1248 subsc_evt->events = cpu_to_le16(subsc_evt_cfg->events); 1249 1250 event_bitmap = subsc_evt_cfg->events; 1251 dev_dbg(priv->adapter->dev, "cmd: event bitmap : %16x\n", 1252 event_bitmap); 1253 1254 if (((subsc_evt_cfg->action == HostCmd_ACT_BITWISE_CLR) || 1255 (subsc_evt_cfg->action == HostCmd_ACT_BITWISE_SET)) && 1256 (event_bitmap == 0)) { 1257 dev_dbg(priv->adapter->dev, "Error: No event specified " 1258 "for bitwise action type\n"); 1259 return -EINVAL; 1260 } 1261 1262 /* 1263 * Append TLV structures for each of the specified events for 1264 * subscribing or re-configuring. This is not required for 1265 * bitwise unsubscribing request. 1266 */ 1267 if (subsc_evt_cfg->action == HostCmd_ACT_BITWISE_CLR) 1268 return 0; 1269 1270 pos = ((u8 *)subsc_evt) + 1271 sizeof(struct host_cmd_ds_802_11_subsc_evt); 1272 1273 if (event_bitmap & BITMASK_BCN_RSSI_LOW) { 1274 rssi_tlv = (struct mwifiex_ie_types_rssi_threshold *) pos; 1275 1276 rssi_tlv->header.type = cpu_to_le16(TLV_TYPE_RSSI_LOW); 1277 rssi_tlv->header.len = 1278 cpu_to_le16(sizeof(struct mwifiex_ie_types_rssi_threshold) - 1279 sizeof(struct mwifiex_ie_types_header)); 1280 rssi_tlv->abs_value = subsc_evt_cfg->bcn_l_rssi_cfg.abs_value; 1281 rssi_tlv->evt_freq = subsc_evt_cfg->bcn_l_rssi_cfg.evt_freq; 1282 1283 dev_dbg(priv->adapter->dev, "Cfg Beacon Low Rssi event, " 1284 "RSSI:-%d dBm, Freq:%d\n", 1285 subsc_evt_cfg->bcn_l_rssi_cfg.abs_value, 1286 subsc_evt_cfg->bcn_l_rssi_cfg.evt_freq); 1287 1288 pos += sizeof(struct mwifiex_ie_types_rssi_threshold); 1289 le16_add_cpu(&cmd->size, 1290 sizeof(struct mwifiex_ie_types_rssi_threshold)); 1291 } 1292 1293 if (event_bitmap & BITMASK_BCN_RSSI_HIGH) { 1294 rssi_tlv = (struct mwifiex_ie_types_rssi_threshold *) pos; 1295 1296 rssi_tlv->header.type = cpu_to_le16(TLV_TYPE_RSSI_HIGH); 1297 rssi_tlv->header.len = 1298 cpu_to_le16(sizeof(struct mwifiex_ie_types_rssi_threshold) - 1299 sizeof(struct mwifiex_ie_types_header)); 1300 rssi_tlv->abs_value = subsc_evt_cfg->bcn_h_rssi_cfg.abs_value; 1301 rssi_tlv->evt_freq = subsc_evt_cfg->bcn_h_rssi_cfg.evt_freq; 1302 1303 dev_dbg(priv->adapter->dev, "Cfg Beacon High Rssi event, " 1304 "RSSI:-%d dBm, Freq:%d\n", 1305 subsc_evt_cfg->bcn_h_rssi_cfg.abs_value, 1306 subsc_evt_cfg->bcn_h_rssi_cfg.evt_freq); 1307 1308 pos += sizeof(struct mwifiex_ie_types_rssi_threshold); 1309 le16_add_cpu(&cmd->size, 1310 sizeof(struct mwifiex_ie_types_rssi_threshold)); 1311 } 1312 1313 return 0; 1314} 1315 1316static int 1317mwifiex_cmd_append_rpn_expression(struct mwifiex_private *priv, 1318 struct mwifiex_mef_entry *mef_entry, 1319 u8 **buffer) 1320{ 1321 struct mwifiex_mef_filter *filter = mef_entry->filter; 1322 int i, byte_len; 1323 u8 *stack_ptr = *buffer; 1324 1325 for (i = 0; i < MWIFIEX_MEF_MAX_FILTERS; i++) { 1326 filter = &mef_entry->filter[i]; 1327 if (!filter->filt_type) 1328 break; 1329 *(__le32 *)stack_ptr = cpu_to_le32((u32)filter->repeat); 1330 stack_ptr += 4; 1331 *stack_ptr = TYPE_DNUM; 1332 stack_ptr += 1; 1333 1334 byte_len = filter->byte_seq[MWIFIEX_MEF_MAX_BYTESEQ]; 1335 memcpy(stack_ptr, filter->byte_seq, byte_len); 1336 stack_ptr += byte_len; 1337 *stack_ptr = byte_len; 1338 stack_ptr += 1; 1339 *stack_ptr = TYPE_BYTESEQ; 1340 stack_ptr += 1; 1341 1342 *(__le32 *)stack_ptr = cpu_to_le32((u32)filter->offset); 1343 stack_ptr += 4; 1344 *stack_ptr = TYPE_DNUM; 1345 stack_ptr += 1; 1346 1347 *stack_ptr = filter->filt_type; 1348 stack_ptr += 1; 1349 1350 if (filter->filt_action) { 1351 *stack_ptr = filter->filt_action; 1352 stack_ptr += 1; 1353 } 1354 1355 if (stack_ptr - *buffer > STACK_NBYTES) 1356 return -1; 1357 } 1358 1359 *buffer = stack_ptr; 1360 return 0; 1361} 1362 1363static int 1364mwifiex_cmd_mef_cfg(struct mwifiex_private *priv, 1365 struct host_cmd_ds_command *cmd, 1366 struct mwifiex_ds_mef_cfg *mef) 1367{ 1368 struct host_cmd_ds_mef_cfg *mef_cfg = &cmd->params.mef_cfg; 1369 u8 *pos = (u8 *)mef_cfg; 1370 1371 cmd->command = cpu_to_le16(HostCmd_CMD_MEF_CFG); 1372 1373 mef_cfg->criteria = cpu_to_le32(mef->criteria); 1374 mef_cfg->num_entries = cpu_to_le16(mef->num_entries); 1375 pos += sizeof(*mef_cfg); 1376 mef_cfg->mef_entry->mode = mef->mef_entry->mode; 1377 mef_cfg->mef_entry->action = mef->mef_entry->action; 1378 pos += sizeof(*(mef_cfg->mef_entry)); 1379 1380 if (mwifiex_cmd_append_rpn_expression(priv, mef->mef_entry, &pos)) 1381 return -1; 1382 1383 mef_cfg->mef_entry->exprsize = 1384 cpu_to_le16(pos - mef_cfg->mef_entry->expr); 1385 cmd->size = cpu_to_le16((u16) (pos - (u8 *)mef_cfg) + S_DS_GEN); 1386 1387 return 0; 1388} 1389 1390/* This function parse cal data from ASCII to hex */ 1391static u32 mwifiex_parse_cal_cfg(u8 *src, size_t len, u8 *dst) 1392{ 1393 u8 *s = src, *d = dst; 1394 1395 while (s - src < len) { 1396 if (*s && (isspace(*s) || *s == '\t')) { 1397 s++; 1398 continue; 1399 } 1400 if (isxdigit(*s)) { 1401 *d++ = simple_strtol(s, NULL, 16); 1402 s += 2; 1403 } else { 1404 s++; 1405 } 1406 } 1407 1408 return d - dst; 1409} 1410 1411int mwifiex_dnld_dt_cfgdata(struct mwifiex_private *priv, 1412 struct device_node *node, const char *prefix) 1413{ 1414#ifdef CONFIG_OF 1415 struct property *prop; 1416 size_t len = strlen(prefix); 1417 int ret; 1418 1419 /* look for all matching property names */ 1420 for_each_property_of_node(node, prop) { 1421 if (len > strlen(prop->name) || 1422 strncmp(prop->name, prefix, len)) 1423 continue; 1424 1425 /* property header is 6 bytes, data must fit in cmd buffer */ 1426 if (prop && prop->value && prop->length > 6 && 1427 prop->length <= MWIFIEX_SIZE_OF_CMD_BUFFER - S_DS_GEN) { 1428 ret = mwifiex_send_cmd(priv, HostCmd_CMD_CFG_DATA, 1429 HostCmd_ACT_GEN_SET, 0, 1430 prop, true); 1431 if (ret) 1432 return ret; 1433 } 1434 } 1435#endif 1436 return 0; 1437} 1438 1439/* This function prepares command of set_cfg_data. */ 1440static int mwifiex_cmd_cfg_data(struct mwifiex_private *priv, 1441 struct host_cmd_ds_command *cmd, void *data_buf) 1442{ 1443 struct mwifiex_adapter *adapter = priv->adapter; 1444 struct property *prop = data_buf; 1445 u32 len; 1446 u8 *data = (u8 *)cmd + S_DS_GEN; 1447 int ret; 1448 1449 if (prop) { 1450 len = prop->length; 1451 ret = of_property_read_u8_array(adapter->dt_node, prop->name, 1452 data, len); 1453 if (ret) 1454 return ret; 1455 dev_dbg(adapter->dev, 1456 "download cfg_data from device tree: %s\n", prop->name); 1457 } else if (adapter->cal_data->data && adapter->cal_data->size > 0) { 1458 len = mwifiex_parse_cal_cfg((u8 *)adapter->cal_data->data, 1459 adapter->cal_data->size, data); 1460 dev_dbg(adapter->dev, "download cfg_data from config file\n"); 1461 } else { 1462 return -1; 1463 } 1464 1465 cmd->command = cpu_to_le16(HostCmd_CMD_CFG_DATA); 1466 cmd->size = cpu_to_le16(S_DS_GEN + len); 1467 1468 return 0; 1469} 1470 1471static int 1472mwifiex_cmd_coalesce_cfg(struct mwifiex_private *priv, 1473 struct host_cmd_ds_command *cmd, 1474 u16 cmd_action, void *data_buf) 1475{ 1476 struct host_cmd_ds_coalesce_cfg *coalesce_cfg = 1477 &cmd->params.coalesce_cfg; 1478 struct mwifiex_ds_coalesce_cfg *cfg = data_buf; 1479 struct coalesce_filt_field_param *param; 1480 u16 cnt, idx, length; 1481 struct coalesce_receive_filt_rule *rule; 1482 1483 cmd->command = cpu_to_le16(HostCmd_CMD_COALESCE_CFG); 1484 cmd->size = cpu_to_le16(S_DS_GEN); 1485 1486 coalesce_cfg->action = cpu_to_le16(cmd_action); 1487 coalesce_cfg->num_of_rules = cpu_to_le16(cfg->num_of_rules); 1488 rule = coalesce_cfg->rule; 1489 1490 for (cnt = 0; cnt < cfg->num_of_rules; cnt++) { 1491 rule->header.type = cpu_to_le16(TLV_TYPE_COALESCE_RULE); 1492 rule->max_coalescing_delay = 1493 cpu_to_le16(cfg->rule[cnt].max_coalescing_delay); 1494 rule->pkt_type = cfg->rule[cnt].pkt_type; 1495 rule->num_of_fields = cfg->rule[cnt].num_of_fields; 1496 1497 length = 0; 1498 1499 param = rule->params; 1500 for (idx = 0; idx < cfg->rule[cnt].num_of_fields; idx++) { 1501 param->operation = cfg->rule[cnt].params[idx].operation; 1502 param->operand_len = 1503 cfg->rule[cnt].params[idx].operand_len; 1504 param->offset = 1505 cpu_to_le16(cfg->rule[cnt].params[idx].offset); 1506 memcpy(param->operand_byte_stream, 1507 cfg->rule[cnt].params[idx].operand_byte_stream, 1508 param->operand_len); 1509 1510 length += sizeof(struct coalesce_filt_field_param); 1511 1512 param++; 1513 } 1514 1515 /* Total rule length is sizeof max_coalescing_delay(u16), 1516 * num_of_fields(u8), pkt_type(u8) and total length of the all 1517 * params 1518 */ 1519 rule->header.len = cpu_to_le16(length + sizeof(u16) + 1520 sizeof(u8) + sizeof(u8)); 1521 1522 /* Add the rule length to the command size*/ 1523 le16_add_cpu(&cmd->size, le16_to_cpu(rule->header.len) + 1524 sizeof(struct mwifiex_ie_types_header)); 1525 1526 rule = (void *)((u8 *)rule->params + length); 1527 } 1528 1529 /* Add sizeof action, num_of_rules to total command length */ 1530 le16_add_cpu(&cmd->size, sizeof(u16) + sizeof(u16)); 1531 1532 return 0; 1533} 1534 1535static int 1536mwifiex_cmd_tdls_oper(struct mwifiex_private *priv, 1537 struct host_cmd_ds_command *cmd, 1538 void *data_buf) 1539{ 1540 struct host_cmd_ds_tdls_oper *tdls_oper = &cmd->params.tdls_oper; 1541 struct mwifiex_ds_tdls_oper *oper = data_buf; 1542 struct mwifiex_sta_node *sta_ptr; 1543 struct host_cmd_tlv_rates *tlv_rates; 1544 struct mwifiex_ie_types_htcap *ht_capab; 1545 struct mwifiex_ie_types_qos_info *wmm_qos_info; 1546 struct mwifiex_ie_types_extcap *extcap; 1547 struct mwifiex_ie_types_vhtcap *vht_capab; 1548 struct mwifiex_ie_types_aid *aid; 1549 struct mwifiex_ie_types_tdls_idle_timeout *timeout; 1550 u8 *pos, qos_info; 1551 u16 config_len = 0; 1552 struct station_parameters *params = priv->sta_params; 1553 1554 cmd->command = cpu_to_le16(HostCmd_CMD_TDLS_OPER); 1555 cmd->size = cpu_to_le16(S_DS_GEN); 1556 le16_add_cpu(&cmd->size, sizeof(struct host_cmd_ds_tdls_oper)); 1557 1558 tdls_oper->reason = 0; 1559 memcpy(tdls_oper->peer_mac, oper->peer_mac, ETH_ALEN); 1560 sta_ptr = mwifiex_get_sta_entry(priv, oper->peer_mac); 1561 1562 pos = (u8 *)tdls_oper + sizeof(struct host_cmd_ds_tdls_oper); 1563 1564 switch (oper->tdls_action) { 1565 case MWIFIEX_TDLS_DISABLE_LINK: 1566 tdls_oper->tdls_action = cpu_to_le16(ACT_TDLS_DELETE); 1567 break; 1568 case MWIFIEX_TDLS_CREATE_LINK: 1569 tdls_oper->tdls_action = cpu_to_le16(ACT_TDLS_CREATE); 1570 break; 1571 case MWIFIEX_TDLS_CONFIG_LINK: 1572 tdls_oper->tdls_action = cpu_to_le16(ACT_TDLS_CONFIG); 1573 1574 if (!params) { 1575 dev_err(priv->adapter->dev, 1576 "TDLS config params not available for %pM\n", 1577 oper->peer_mac); 1578 return -ENODATA; 1579 } 1580 1581 *(__le16 *)pos = cpu_to_le16(params->capability); 1582 config_len += sizeof(params->capability); 1583 1584 qos_info = params->uapsd_queues | (params->max_sp << 5); 1585 wmm_qos_info = (struct mwifiex_ie_types_qos_info *)(pos + 1586 config_len); 1587 wmm_qos_info->header.type = cpu_to_le16(WLAN_EID_QOS_CAPA); 1588 wmm_qos_info->header.len = cpu_to_le16(sizeof(qos_info)); 1589 wmm_qos_info->qos_info = qos_info; 1590 config_len += sizeof(struct mwifiex_ie_types_qos_info); 1591 1592 if (params->ht_capa) { 1593 ht_capab = (struct mwifiex_ie_types_htcap *)(pos + 1594 config_len); 1595 ht_capab->header.type = 1596 cpu_to_le16(WLAN_EID_HT_CAPABILITY); 1597 ht_capab->header.len = 1598 cpu_to_le16(sizeof(struct ieee80211_ht_cap)); 1599 memcpy(&ht_capab->ht_cap, params->ht_capa, 1600 sizeof(struct ieee80211_ht_cap)); 1601 config_len += sizeof(struct mwifiex_ie_types_htcap); 1602 } 1603 1604 if (params->supported_rates && params->supported_rates_len) { 1605 tlv_rates = (struct host_cmd_tlv_rates *)(pos + 1606 config_len); 1607 tlv_rates->header.type = 1608 cpu_to_le16(WLAN_EID_SUPP_RATES); 1609 tlv_rates->header.len = 1610 cpu_to_le16(params->supported_rates_len); 1611 memcpy(tlv_rates->rates, params->supported_rates, 1612 params->supported_rates_len); 1613 config_len += sizeof(struct host_cmd_tlv_rates) + 1614 params->supported_rates_len; 1615 } 1616 1617 if (params->ext_capab && params->ext_capab_len) { 1618 extcap = (struct mwifiex_ie_types_extcap *)(pos + 1619 config_len); 1620 extcap->header.type = 1621 cpu_to_le16(WLAN_EID_EXT_CAPABILITY); 1622 extcap->header.len = cpu_to_le16(params->ext_capab_len); 1623 memcpy(extcap->ext_capab, params->ext_capab, 1624 params->ext_capab_len); 1625 config_len += sizeof(struct mwifiex_ie_types_extcap) + 1626 params->ext_capab_len; 1627 } 1628 if (params->vht_capa) { 1629 vht_capab = (struct mwifiex_ie_types_vhtcap *)(pos + 1630 config_len); 1631 vht_capab->header.type = 1632 cpu_to_le16(WLAN_EID_VHT_CAPABILITY); 1633 vht_capab->header.len = 1634 cpu_to_le16(sizeof(struct ieee80211_vht_cap)); 1635 memcpy(&vht_capab->vht_cap, params->vht_capa, 1636 sizeof(struct ieee80211_vht_cap)); 1637 config_len += sizeof(struct mwifiex_ie_types_vhtcap); 1638 } 1639 if (params->aid) { 1640 aid = (struct mwifiex_ie_types_aid *)(pos + config_len); 1641 aid->header.type = cpu_to_le16(WLAN_EID_AID); 1642 aid->header.len = cpu_to_le16(sizeof(params->aid)); 1643 aid->aid = cpu_to_le16(params->aid); 1644 config_len += sizeof(struct mwifiex_ie_types_aid); 1645 } 1646 1647 timeout = (void *)(pos + config_len); 1648 timeout->header.type = cpu_to_le16(TLV_TYPE_TDLS_IDLE_TIMEOUT); 1649 timeout->header.len = cpu_to_le16(sizeof(timeout->value)); 1650 timeout->value = cpu_to_le16(MWIFIEX_TDLS_IDLE_TIMEOUT_IN_SEC); 1651 config_len += sizeof(struct mwifiex_ie_types_tdls_idle_timeout); 1652 1653 break; 1654 default: 1655 dev_err(priv->adapter->dev, "Unknown TDLS operation\n"); 1656 return -ENOTSUPP; 1657 } 1658 1659 le16_add_cpu(&cmd->size, config_len); 1660 1661 return 0; 1662} 1663/* 1664 * This function prepares the commands before sending them to the firmware. 1665 * 1666 * This is a generic function which calls specific command preparation 1667 * routines based upon the command number. 1668 */ 1669int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, 1670 u16 cmd_action, u32 cmd_oid, 1671 void *data_buf, void *cmd_buf) 1672{ 1673 struct host_cmd_ds_command *cmd_ptr = cmd_buf; 1674 int ret = 0; 1675 1676 /* Prepare command */ 1677 switch (cmd_no) { 1678 case HostCmd_CMD_GET_HW_SPEC: 1679 ret = mwifiex_cmd_get_hw_spec(priv, cmd_ptr); 1680 break; 1681 case HostCmd_CMD_CFG_DATA: 1682 ret = mwifiex_cmd_cfg_data(priv, cmd_ptr, data_buf); 1683 break; 1684 case HostCmd_CMD_MAC_CONTROL: 1685 ret = mwifiex_cmd_mac_control(priv, cmd_ptr, cmd_action, 1686 data_buf); 1687 break; 1688 case HostCmd_CMD_802_11_MAC_ADDRESS: 1689 ret = mwifiex_cmd_802_11_mac_address(priv, cmd_ptr, 1690 cmd_action); 1691 break; 1692 case HostCmd_CMD_MAC_MULTICAST_ADR: 1693 ret = mwifiex_cmd_mac_multicast_adr(cmd_ptr, cmd_action, 1694 data_buf); 1695 break; 1696 case HostCmd_CMD_TX_RATE_CFG: 1697 ret = mwifiex_cmd_tx_rate_cfg(priv, cmd_ptr, cmd_action, 1698 data_buf); 1699 break; 1700 case HostCmd_CMD_TXPWR_CFG: 1701 ret = mwifiex_cmd_tx_power_cfg(cmd_ptr, cmd_action, 1702 data_buf); 1703 break; 1704 case HostCmd_CMD_RF_TX_PWR: 1705 ret = mwifiex_cmd_rf_tx_power(priv, cmd_ptr, cmd_action, 1706 data_buf); 1707 break; 1708 case HostCmd_CMD_RF_ANTENNA: 1709 ret = mwifiex_cmd_rf_antenna(priv, cmd_ptr, cmd_action, 1710 data_buf); 1711 break; 1712 case HostCmd_CMD_802_11_PS_MODE_ENH: 1713 ret = mwifiex_cmd_enh_power_mode(priv, cmd_ptr, cmd_action, 1714 (uint16_t)cmd_oid, data_buf); 1715 break; 1716 case HostCmd_CMD_802_11_HS_CFG_ENH: 1717 ret = mwifiex_cmd_802_11_hs_cfg(priv, cmd_ptr, cmd_action, 1718 (struct mwifiex_hs_config_param *) data_buf); 1719 break; 1720 case HostCmd_CMD_802_11_SCAN: 1721 ret = mwifiex_cmd_802_11_scan(cmd_ptr, data_buf); 1722 break; 1723 case HostCmd_CMD_802_11_BG_SCAN_QUERY: 1724 ret = mwifiex_cmd_802_11_bg_scan_query(cmd_ptr); 1725 break; 1726 case HostCmd_CMD_802_11_ASSOCIATE: 1727 ret = mwifiex_cmd_802_11_associate(priv, cmd_ptr, data_buf); 1728 break; 1729 case HostCmd_CMD_802_11_DEAUTHENTICATE: 1730 ret = mwifiex_cmd_802_11_deauthenticate(priv, cmd_ptr, 1731 data_buf); 1732 break; 1733 case HostCmd_CMD_802_11_AD_HOC_START: 1734 ret = mwifiex_cmd_802_11_ad_hoc_start(priv, cmd_ptr, 1735 data_buf); 1736 break; 1737 case HostCmd_CMD_802_11_GET_LOG: 1738 ret = mwifiex_cmd_802_11_get_log(cmd_ptr); 1739 break; 1740 case HostCmd_CMD_802_11_AD_HOC_JOIN: 1741 ret = mwifiex_cmd_802_11_ad_hoc_join(priv, cmd_ptr, 1742 data_buf); 1743 break; 1744 case HostCmd_CMD_802_11_AD_HOC_STOP: 1745 ret = mwifiex_cmd_802_11_ad_hoc_stop(cmd_ptr); 1746 break; 1747 case HostCmd_CMD_RSSI_INFO: 1748 ret = mwifiex_cmd_802_11_rssi_info(priv, cmd_ptr, cmd_action); 1749 break; 1750 case HostCmd_CMD_802_11_SNMP_MIB: 1751 ret = mwifiex_cmd_802_11_snmp_mib(priv, cmd_ptr, cmd_action, 1752 cmd_oid, data_buf); 1753 break; 1754 case HostCmd_CMD_802_11_TX_RATE_QUERY: 1755 cmd_ptr->command = 1756 cpu_to_le16(HostCmd_CMD_802_11_TX_RATE_QUERY); 1757 cmd_ptr->size = 1758 cpu_to_le16(sizeof(struct host_cmd_ds_tx_rate_query) + 1759 S_DS_GEN); 1760 priv->tx_rate = 0; 1761 ret = 0; 1762 break; 1763 case HostCmd_CMD_VERSION_EXT: 1764 cmd_ptr->command = cpu_to_le16(cmd_no); 1765 cmd_ptr->params.verext.version_str_sel = 1766 (u8) (*((u32 *) data_buf)); 1767 memcpy(&cmd_ptr->params, data_buf, 1768 sizeof(struct host_cmd_ds_version_ext)); 1769 cmd_ptr->size = 1770 cpu_to_le16(sizeof(struct host_cmd_ds_version_ext) + 1771 S_DS_GEN); 1772 ret = 0; 1773 break; 1774 case HostCmd_CMD_MGMT_FRAME_REG: 1775 cmd_ptr->command = cpu_to_le16(cmd_no); 1776 cmd_ptr->params.reg_mask.action = cpu_to_le16(cmd_action); 1777 cmd_ptr->params.reg_mask.mask = cpu_to_le32(*(u32 *)data_buf); 1778 cmd_ptr->size = 1779 cpu_to_le16(sizeof(struct host_cmd_ds_mgmt_frame_reg) + 1780 S_DS_GEN); 1781 ret = 0; 1782 break; 1783 case HostCmd_CMD_REMAIN_ON_CHAN: 1784 cmd_ptr->command = cpu_to_le16(cmd_no); 1785 memcpy(&cmd_ptr->params, data_buf, 1786 sizeof(struct host_cmd_ds_remain_on_chan)); 1787 cmd_ptr->size = 1788 cpu_to_le16(sizeof(struct host_cmd_ds_remain_on_chan) + 1789 S_DS_GEN); 1790 break; 1791 case HostCmd_CMD_11AC_CFG: 1792 ret = mwifiex_cmd_11ac_cfg(priv, cmd_ptr, cmd_action, data_buf); 1793 break; 1794 case HostCmd_CMD_P2P_MODE_CFG: 1795 cmd_ptr->command = cpu_to_le16(cmd_no); 1796 cmd_ptr->params.mode_cfg.action = cpu_to_le16(cmd_action); 1797 cmd_ptr->params.mode_cfg.mode = cpu_to_le16(*(u16 *)data_buf); 1798 cmd_ptr->size = 1799 cpu_to_le16(sizeof(struct host_cmd_ds_p2p_mode_cfg) + 1800 S_DS_GEN); 1801 break; 1802 case HostCmd_CMD_FUNC_INIT: 1803 if (priv->adapter->hw_status == MWIFIEX_HW_STATUS_RESET) 1804 priv->adapter->hw_status = MWIFIEX_HW_STATUS_READY; 1805 cmd_ptr->command = cpu_to_le16(cmd_no); 1806 cmd_ptr->size = cpu_to_le16(S_DS_GEN); 1807 break; 1808 case HostCmd_CMD_FUNC_SHUTDOWN: 1809 priv->adapter->hw_status = MWIFIEX_HW_STATUS_RESET; 1810 cmd_ptr->command = cpu_to_le16(cmd_no); 1811 cmd_ptr->size = cpu_to_le16(S_DS_GEN); 1812 break; 1813 case HostCmd_CMD_11N_ADDBA_REQ: 1814 ret = mwifiex_cmd_11n_addba_req(cmd_ptr, data_buf); 1815 break; 1816 case HostCmd_CMD_11N_DELBA: 1817 ret = mwifiex_cmd_11n_delba(cmd_ptr, data_buf); 1818 break; 1819 case HostCmd_CMD_11N_ADDBA_RSP: 1820 ret = mwifiex_cmd_11n_addba_rsp_gen(priv, cmd_ptr, data_buf); 1821 break; 1822 case HostCmd_CMD_802_11_KEY_MATERIAL: 1823 ret = mwifiex_cmd_802_11_key_material(priv, cmd_ptr, 1824 cmd_action, cmd_oid, 1825 data_buf); 1826 break; 1827 case HostCmd_CMD_802_11D_DOMAIN_INFO: 1828 ret = mwifiex_cmd_802_11d_domain_info(priv, cmd_ptr, 1829 cmd_action); 1830 break; 1831 case HostCmd_CMD_RECONFIGURE_TX_BUFF: 1832 ret = mwifiex_cmd_recfg_tx_buf(priv, cmd_ptr, cmd_action, 1833 data_buf); 1834 break; 1835 case HostCmd_CMD_AMSDU_AGGR_CTRL: 1836 ret = mwifiex_cmd_amsdu_aggr_ctrl(cmd_ptr, cmd_action, 1837 data_buf); 1838 break; 1839 case HostCmd_CMD_11N_CFG: 1840 ret = mwifiex_cmd_11n_cfg(priv, cmd_ptr, cmd_action, data_buf); 1841 break; 1842 case HostCmd_CMD_WMM_GET_STATUS: 1843 dev_dbg(priv->adapter->dev, 1844 "cmd: WMM: WMM_GET_STATUS cmd sent\n"); 1845 cmd_ptr->command = cpu_to_le16(HostCmd_CMD_WMM_GET_STATUS); 1846 cmd_ptr->size = 1847 cpu_to_le16(sizeof(struct host_cmd_ds_wmm_get_status) + 1848 S_DS_GEN); 1849 ret = 0; 1850 break; 1851 case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS: 1852 ret = mwifiex_cmd_ibss_coalescing_status(cmd_ptr, cmd_action, 1853 data_buf); 1854 break; 1855 case HostCmd_CMD_802_11_SCAN_EXT: 1856 ret = mwifiex_cmd_802_11_scan_ext(priv, cmd_ptr, data_buf); 1857 break; 1858 case HostCmd_CMD_MAC_REG_ACCESS: 1859 case HostCmd_CMD_BBP_REG_ACCESS: 1860 case HostCmd_CMD_RF_REG_ACCESS: 1861 case HostCmd_CMD_PMIC_REG_ACCESS: 1862 case HostCmd_CMD_CAU_REG_ACCESS: 1863 case HostCmd_CMD_802_11_EEPROM_ACCESS: 1864 ret = mwifiex_cmd_reg_access(cmd_ptr, cmd_action, data_buf); 1865 break; 1866 case HostCmd_CMD_SET_BSS_MODE: 1867 cmd_ptr->command = cpu_to_le16(cmd_no); 1868 if (priv->bss_mode == NL80211_IFTYPE_ADHOC) 1869 cmd_ptr->params.bss_mode.con_type = 1870 CONNECTION_TYPE_ADHOC; 1871 else if (priv->bss_mode == NL80211_IFTYPE_STATION) 1872 cmd_ptr->params.bss_mode.con_type = 1873 CONNECTION_TYPE_INFRA; 1874 else if (priv->bss_mode == NL80211_IFTYPE_AP) 1875 cmd_ptr->params.bss_mode.con_type = CONNECTION_TYPE_AP; 1876 cmd_ptr->size = cpu_to_le16(sizeof(struct 1877 host_cmd_ds_set_bss_mode) + S_DS_GEN); 1878 ret = 0; 1879 break; 1880 case HostCmd_CMD_PCIE_DESC_DETAILS: 1881 ret = mwifiex_cmd_pcie_host_spec(priv, cmd_ptr, cmd_action); 1882 break; 1883 case HostCmd_CMD_802_11_SUBSCRIBE_EVENT: 1884 ret = mwifiex_cmd_802_11_subsc_evt(priv, cmd_ptr, data_buf); 1885 break; 1886 case HostCmd_CMD_MEF_CFG: 1887 ret = mwifiex_cmd_mef_cfg(priv, cmd_ptr, data_buf); 1888 break; 1889 case HostCmd_CMD_COALESCE_CFG: 1890 ret = mwifiex_cmd_coalesce_cfg(priv, cmd_ptr, cmd_action, 1891 data_buf); 1892 break; 1893 case HostCmd_CMD_TDLS_OPER: 1894 ret = mwifiex_cmd_tdls_oper(priv, cmd_ptr, data_buf); 1895 break; 1896 default: 1897 dev_err(priv->adapter->dev, 1898 "PREP_CMD: unknown cmd- %#x\n", cmd_no); 1899 ret = -1; 1900 break; 1901 } 1902 return ret; 1903} 1904 1905/* 1906 * This function issues commands to initialize firmware. 1907 * 1908 * This is called after firmware download to bring the card to 1909 * working state. 1910 * 1911 * The following commands are issued sequentially - 1912 * - Set PCI-Express host buffer configuration (PCIE only) 1913 * - Function init (for first interface only) 1914 * - Read MAC address (for first interface only) 1915 * - Reconfigure Tx buffer size (for first interface only) 1916 * - Enable auto deep sleep (for first interface only) 1917 * - Get Tx rate 1918 * - Get Tx power 1919 * - Set IBSS coalescing status 1920 * - Set AMSDU aggregation control 1921 * - Set 11d control 1922 * - Set MAC control (this must be the last command to initialize firmware) 1923 */ 1924int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) 1925{ 1926 struct mwifiex_adapter *adapter = priv->adapter; 1927 int ret; 1928 u16 enable = true; 1929 struct mwifiex_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl; 1930 struct mwifiex_ds_auto_ds auto_ds; 1931 enum state_11d_t state_11d; 1932 struct mwifiex_ds_11n_tx_cfg tx_cfg; 1933 1934 if (first_sta) { 1935 if (priv->adapter->iface_type == MWIFIEX_PCIE) { 1936 ret = mwifiex_send_cmd(priv, 1937 HostCmd_CMD_PCIE_DESC_DETAILS, 1938 HostCmd_ACT_GEN_SET, 0, NULL, 1939 true); 1940 if (ret) 1941 return -1; 1942 } 1943 1944 ret = mwifiex_send_cmd(priv, HostCmd_CMD_FUNC_INIT, 1945 HostCmd_ACT_GEN_SET, 0, NULL, true); 1946 if (ret) 1947 return -1; 1948 1949 /* Download calibration data to firmware. 1950 * The cal-data can be read from device tree and/or 1951 * a configuration file and downloaded to firmware. 1952 */ 1953 adapter->dt_node = 1954 of_find_node_by_name(NULL, "marvell_cfgdata"); 1955 if (adapter->dt_node) { 1956 ret = mwifiex_dnld_dt_cfgdata(priv, adapter->dt_node, 1957 "marvell,caldata"); 1958 if (ret) 1959 return -1; 1960 } 1961 1962 if (adapter->cal_data) { 1963 ret = mwifiex_send_cmd(priv, HostCmd_CMD_CFG_DATA, 1964 HostCmd_ACT_GEN_SET, 0, NULL, 1965 true); 1966 if (ret) 1967 return -1; 1968 } 1969 1970 /* Read MAC address from HW */ 1971 ret = mwifiex_send_cmd(priv, HostCmd_CMD_GET_HW_SPEC, 1972 HostCmd_ACT_GEN_GET, 0, NULL, true); 1973 if (ret) 1974 return -1; 1975 1976 /* Reconfigure tx buf size */ 1977 ret = mwifiex_send_cmd(priv, HostCmd_CMD_RECONFIGURE_TX_BUFF, 1978 HostCmd_ACT_GEN_SET, 0, 1979 &priv->adapter->tx_buf_size, true); 1980 if (ret) 1981 return -1; 1982 1983 if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) { 1984 /* Enable IEEE PS by default */ 1985 priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; 1986 ret = mwifiex_send_cmd(priv, 1987 HostCmd_CMD_802_11_PS_MODE_ENH, 1988 EN_AUTO_PS, BITMAP_STA_PS, NULL, 1989 true); 1990 if (ret) 1991 return -1; 1992 } 1993 } 1994 1995 /* get tx rate */ 1996 ret = mwifiex_send_cmd(priv, HostCmd_CMD_TX_RATE_CFG, 1997 HostCmd_ACT_GEN_GET, 0, NULL, true); 1998 if (ret) 1999 return -1; 2000 priv->data_rate = 0; 2001 2002 /* get tx power */ 2003 ret = mwifiex_send_cmd(priv, HostCmd_CMD_RF_TX_PWR, 2004 HostCmd_ACT_GEN_GET, 0, NULL, true); 2005 if (ret) 2006 return -1; 2007 2008 if (priv->bss_type == MWIFIEX_BSS_TYPE_STA) { 2009 /* set ibss coalescing_status */ 2010 ret = mwifiex_send_cmd( 2011 priv, 2012 HostCmd_CMD_802_11_IBSS_COALESCING_STATUS, 2013 HostCmd_ACT_GEN_SET, 0, &enable, true); 2014 if (ret) 2015 return -1; 2016 } 2017 2018 memset(&amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl)); 2019 amsdu_aggr_ctrl.enable = true; 2020 /* Send request to firmware */ 2021 ret = mwifiex_send_cmd(priv, HostCmd_CMD_AMSDU_AGGR_CTRL, 2022 HostCmd_ACT_GEN_SET, 0, 2023 &amsdu_aggr_ctrl, true); 2024 if (ret) 2025 return -1; 2026 /* MAC Control must be the last command in init_fw */ 2027 /* set MAC Control */ 2028 ret = mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL, 2029 HostCmd_ACT_GEN_SET, 0, 2030 &priv->curr_pkt_filter, true); 2031 if (ret) 2032 return -1; 2033 2034 if (first_sta && priv->adapter->iface_type != MWIFIEX_USB && 2035 priv->bss_type != MWIFIEX_BSS_TYPE_UAP) { 2036 /* Enable auto deep sleep */ 2037 auto_ds.auto_ds = DEEP_SLEEP_ON; 2038 auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME; 2039 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH, 2040 EN_AUTO_PS, BITMAP_AUTO_DS, 2041 &auto_ds, true); 2042 if (ret) 2043 return -1; 2044 } 2045 2046 if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) { 2047 /* Send cmd to FW to enable/disable 11D function */ 2048 state_11d = ENABLE_11D; 2049 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB, 2050 HostCmd_ACT_GEN_SET, DOT11D_I, 2051 &state_11d, true); 2052 if (ret) 2053 dev_err(priv->adapter->dev, 2054 "11D: failed to enable 11D\n"); 2055 } 2056 2057 /* set last_init_cmd before sending the command */ 2058 priv->adapter->last_init_cmd = HostCmd_CMD_11N_CFG; 2059 2060 /* Send cmd to FW to configure 11n specific configuration 2061 * (Short GI, Channel BW, Green field support etc.) for transmit 2062 */ 2063 tx_cfg.tx_htcap = MWIFIEX_FW_DEF_HTTXCFG; 2064 ret = mwifiex_send_cmd(priv, HostCmd_CMD_11N_CFG, 2065 HostCmd_ACT_GEN_SET, 0, &tx_cfg, true); 2066 2067 ret = -EINPROGRESS; 2068 2069 return ret; 2070} 2071