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