1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * NXP Wireless LAN device driver: functions for station ioctl 4 * 5 * Copyright 2011-2020 NXP 6 */ 7 8 #include "decl.h" 9 #include "ioctl.h" 10 #include "util.h" 11 #include "fw.h" 12 #include "main.h" 13 #include "wmm.h" 14 #include "11n.h" 15 #include "cfg80211.h" 16 17 static int disconnect_on_suspend; 18 module_param(disconnect_on_suspend, int, 0644); 19 20 /* 21 * Copies the multicast address list from device to driver. 22 * 23 * This function does not validate the destination memory for 24 * size, and the calling function must ensure enough memory is 25 * available. 26 */ 27 int mwifiex_copy_mcast_addr(struct mwifiex_multicast_list *mlist, 28 struct net_device *dev) 29 { 30 int i = 0; 31 struct netdev_hw_addr *ha; 32 33 netdev_for_each_mc_addr(ha, dev) 34 memcpy(&mlist->mac_list[i++], ha->addr, ETH_ALEN); 35 36 return i; 37 } 38 39 /* 40 * Wait queue completion handler. 41 * 42 * This function waits on a cmd wait queue. It also cancels the pending 43 * request after waking up, in case of errors. 44 */ 45 int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter, 46 struct cmd_ctrl_node *cmd_queued) 47 { 48 int status; 49 50 /* Wait for completion */ 51 status = wait_event_interruptible_timeout(adapter->cmd_wait_q.wait, 52 *(cmd_queued->condition), 53 (12 * HZ)); 54 if (status <= 0) { 55 if (status == 0) 56 status = -ETIMEDOUT; 57 mwifiex_dbg(adapter, ERROR, "cmd_wait_q terminated: %d\n", 58 status); 59 mwifiex_cancel_all_pending_cmd(adapter); 60 return status; 61 } 62 63 status = adapter->cmd_wait_q.status; 64 adapter->cmd_wait_q.status = 0; 65 66 return status; 67 } 68 69 /* 70 * This function prepares the correct firmware command and 71 * issues it to set the multicast list. 72 * 73 * This function can be used to enable promiscuous mode, or enable all 74 * multicast packets, or to enable selective multicast. 75 */ 76 int mwifiex_request_set_multicast_list(struct mwifiex_private *priv, 77 struct mwifiex_multicast_list *mcast_list) 78 { 79 int ret = 0; 80 u16 old_pkt_filter; 81 82 old_pkt_filter = priv->curr_pkt_filter; 83 84 if (mcast_list->mode == MWIFIEX_PROMISC_MODE) { 85 mwifiex_dbg(priv->adapter, INFO, 86 "info: Enable Promiscuous mode\n"); 87 priv->curr_pkt_filter |= HostCmd_ACT_MAC_PROMISCUOUS_ENABLE; 88 priv->curr_pkt_filter &= 89 ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; 90 } else { 91 /* Multicast */ 92 priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_PROMISCUOUS_ENABLE; 93 if (mcast_list->mode == MWIFIEX_ALL_MULTI_MODE) { 94 mwifiex_dbg(priv->adapter, INFO, 95 "info: Enabling All Multicast!\n"); 96 priv->curr_pkt_filter |= 97 HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; 98 } else { 99 priv->curr_pkt_filter &= 100 ~HostCmd_ACT_MAC_ALL_MULTICAST_ENABLE; 101 mwifiex_dbg(priv->adapter, INFO, 102 "info: Set multicast list=%d\n", 103 mcast_list->num_multicast_addr); 104 /* Send multicast addresses to firmware */ 105 ret = mwifiex_send_cmd(priv, 106 HostCmd_CMD_MAC_MULTICAST_ADR, 107 HostCmd_ACT_GEN_SET, 0, 108 mcast_list, false); 109 } 110 } 111 mwifiex_dbg(priv->adapter, INFO, 112 "info: old_pkt_filter=%#x, curr_pkt_filter=%#x\n", 113 old_pkt_filter, priv->curr_pkt_filter); 114 if (old_pkt_filter != priv->curr_pkt_filter) { 115 ret = mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL, 116 HostCmd_ACT_GEN_SET, 117 0, &priv->curr_pkt_filter, false); 118 } 119 120 return ret; 121 } 122 123 /* 124 * This function fills bss descriptor structure using provided 125 * information. 126 * beacon_ie buffer is allocated in this function. It is caller's 127 * responsibility to free the memory. 128 */ 129 int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, 130 struct cfg80211_bss *bss, 131 struct mwifiex_bssdescriptor *bss_desc) 132 { 133 u8 *beacon_ie; 134 size_t beacon_ie_len; 135 struct mwifiex_bss_priv *bss_priv = (void *)bss->priv; 136 const struct cfg80211_bss_ies *ies; 137 138 rcu_read_lock(); 139 ies = rcu_dereference(bss->ies); 140 beacon_ie = kmemdup(ies->data, ies->len, GFP_ATOMIC); 141 beacon_ie_len = ies->len; 142 bss_desc->timestamp = ies->tsf; 143 rcu_read_unlock(); 144 145 if (!beacon_ie) { 146 mwifiex_dbg(priv->adapter, ERROR, 147 " failed to alloc beacon_ie\n"); 148 return -ENOMEM; 149 } 150 151 memcpy(bss_desc->mac_address, bss->bssid, ETH_ALEN); 152 bss_desc->rssi = bss->signal; 153 /* The caller of this function will free beacon_ie */ 154 bss_desc->beacon_buf = beacon_ie; 155 bss_desc->beacon_buf_size = beacon_ie_len; 156 bss_desc->beacon_period = bss->beacon_interval; 157 bss_desc->cap_info_bitmap = bss->capability; 158 bss_desc->bss_band = bss_priv->band; 159 bss_desc->fw_tsf = bss_priv->fw_tsf; 160 if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) { 161 mwifiex_dbg(priv->adapter, INFO, 162 "info: InterpretIE: AP WEP enabled\n"); 163 bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP; 164 } else { 165 bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL; 166 } 167 if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_IBSS) 168 bss_desc->bss_mode = NL80211_IFTYPE_ADHOC; 169 else 170 bss_desc->bss_mode = NL80211_IFTYPE_STATION; 171 172 /* Disable 11ac by default. Enable it only where there 173 * exist VHT_CAP IE in AP beacon 174 */ 175 bss_desc->disable_11ac = true; 176 177 if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_SPECTRUM_MGMT) 178 bss_desc->sensed_11h = true; 179 180 return mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc); 181 } 182 183 static void mwifiex_dnld_dt_txpwr_table(struct mwifiex_private *priv) 184 { 185 if (priv->adapter->dt_node) { 186 char txpwr[] = {"marvell,00_txpwrlimit"}; 187 188 memcpy(&txpwr[8], priv->adapter->country_code, 2); 189 mwifiex_dnld_dt_cfgdata(priv, priv->adapter->dt_node, txpwr); 190 } 191 } 192 193 static int mwifiex_request_rgpower_table(struct mwifiex_private *priv) 194 { 195 struct mwifiex_802_11d_domain_reg *domain_info = &priv->adapter->domain_reg; 196 struct mwifiex_adapter *adapter = priv->adapter; 197 char rgpower_table_name[30]; 198 char country_code[3]; 199 200 strscpy(country_code, domain_info->country_code, sizeof(country_code)); 201 202 /* World regulatory domain "00" has WW as country code */ 203 if (strncmp(country_code, "00", 2) == 0) 204 strscpy(country_code, "WW", sizeof(country_code)); 205 206 snprintf(rgpower_table_name, sizeof(rgpower_table_name), 207 "nxp/rgpower_%s.bin", country_code); 208 209 mwifiex_dbg(adapter, INFO, "info: %s: requesting regulatory power table %s\n", 210 __func__, rgpower_table_name); 211 212 if (adapter->rgpower_data) { 213 release_firmware(adapter->rgpower_data); 214 adapter->rgpower_data = NULL; 215 } 216 217 if ((request_firmware(&adapter->rgpower_data, rgpower_table_name, 218 adapter->dev))) { 219 mwifiex_dbg( 220 adapter, INFO, 221 "info: %s: failed to request regulatory power table\n", 222 __func__); 223 return -EIO; 224 } 225 226 return 0; 227 } 228 229 static int mwifiex_dnld_rgpower_table(struct mwifiex_private *priv) 230 { 231 int ret; 232 233 ret = mwifiex_request_rgpower_table(priv); 234 if (ret) 235 return ret; 236 237 return mwifiex_send_rgpower_table(priv, priv->adapter->rgpower_data->data, 238 priv->adapter->rgpower_data->size); 239 } 240 241 void mwifiex_dnld_txpwr_table(struct mwifiex_private *priv) 242 { 243 if (mwifiex_dnld_rgpower_table(priv) == 0) 244 return; 245 246 mwifiex_dnld_dt_txpwr_table(priv); 247 } 248 249 static int mwifiex_process_country_ie(struct mwifiex_private *priv, 250 struct cfg80211_bss *bss) 251 { 252 const u8 *country_ie; 253 u8 country_ie_len; 254 struct mwifiex_802_11d_domain_reg *domain_info = 255 &priv->adapter->domain_reg; 256 257 rcu_read_lock(); 258 country_ie = ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY); 259 if (!country_ie) { 260 rcu_read_unlock(); 261 return 0; 262 } 263 264 country_ie_len = country_ie[1]; 265 if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) { 266 rcu_read_unlock(); 267 return 0; 268 } 269 270 if (!strncmp(priv->adapter->country_code, &country_ie[2], 2)) { 271 rcu_read_unlock(); 272 mwifiex_dbg(priv->adapter, INFO, 273 "11D: skip setting domain info in FW\n"); 274 return 0; 275 } 276 277 if (country_ie_len > 278 (IEEE80211_COUNTRY_STRING_LEN + MWIFIEX_MAX_TRIPLET_802_11D)) { 279 rcu_read_unlock(); 280 mwifiex_dbg(priv->adapter, ERROR, 281 "11D: country_ie_len overflow!, deauth AP\n"); 282 return -EINVAL; 283 } 284 285 memcpy(priv->adapter->country_code, &country_ie[2], 2); 286 287 domain_info->country_code[0] = country_ie[2]; 288 domain_info->country_code[1] = country_ie[3]; 289 domain_info->country_code[2] = ' '; 290 291 country_ie_len -= IEEE80211_COUNTRY_STRING_LEN; 292 293 domain_info->no_of_triplet = 294 country_ie_len / sizeof(struct ieee80211_country_ie_triplet); 295 296 memcpy((u8 *)domain_info->triplet, 297 &country_ie[2] + IEEE80211_COUNTRY_STRING_LEN, country_ie_len); 298 299 rcu_read_unlock(); 300 301 if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, 302 HostCmd_ACT_GEN_SET, 0, NULL, false)) { 303 mwifiex_dbg(priv->adapter, ERROR, 304 "11D: setting domain info in FW fail\n"); 305 return -1; 306 } 307 308 mwifiex_dnld_txpwr_table(priv); 309 310 return 0; 311 } 312 313 /* 314 * In Ad-Hoc mode, the IBSS is created if not found in scan list. 315 * In both Ad-Hoc and infra mode, an deauthentication is performed 316 * first. 317 */ 318 int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, 319 struct cfg80211_ssid *req_ssid) 320 { 321 int ret; 322 struct mwifiex_adapter *adapter = priv->adapter; 323 struct mwifiex_bssdescriptor *bss_desc = NULL; 324 325 priv->scan_block = false; 326 327 if (bss) { 328 if (adapter->region_code == 0x00 && 329 mwifiex_process_country_ie(priv, bss)) 330 return -EINVAL; 331 332 /* Allocate and fill new bss descriptor */ 333 bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor), 334 GFP_KERNEL); 335 if (!bss_desc) 336 return -ENOMEM; 337 338 ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc); 339 if (ret) 340 goto done; 341 } 342 343 if (priv->bss_mode == NL80211_IFTYPE_STATION || 344 priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) { 345 u8 config_bands; 346 347 if (!bss_desc) 348 return -1; 349 350 if (mwifiex_band_to_radio_type(bss_desc->bss_band) == 351 HostCmd_SCAN_RADIO_TYPE_BG) { 352 config_bands = BAND_B | BAND_G | BAND_GN; 353 } else { 354 config_bands = BAND_A | BAND_AN; 355 if (adapter->fw_bands & BAND_AAC) 356 config_bands |= BAND_AAC; 357 } 358 359 if (!((config_bands | adapter->fw_bands) & ~adapter->fw_bands)) 360 adapter->config_bands = config_bands; 361 362 ret = mwifiex_check_network_compatibility(priv, bss_desc); 363 if (ret) 364 goto done; 365 366 if (mwifiex_11h_get_csa_closed_channel(priv) == 367 (u8)bss_desc->channel) { 368 mwifiex_dbg(adapter, ERROR, 369 "Attempt to reconnect on csa closed chan(%d)\n", 370 bss_desc->channel); 371 ret = -1; 372 goto done; 373 } 374 375 mwifiex_dbg(adapter, INFO, 376 "info: SSID found in scan list ...\t" 377 "associating...\n"); 378 379 mwifiex_stop_net_dev_queue(priv->netdev, adapter); 380 if (netif_carrier_ok(priv->netdev)) 381 netif_carrier_off(priv->netdev); 382 383 /* Clear any past association response stored for 384 * application retrieval */ 385 priv->assoc_rsp_size = 0; 386 ret = mwifiex_associate(priv, bss_desc); 387 388 /* If auth type is auto and association fails using open mode, 389 * try to connect using shared mode */ 390 if (ret == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG && 391 priv->sec_info.is_authtype_auto && 392 priv->sec_info.wep_enabled) { 393 priv->sec_info.authentication_mode = 394 NL80211_AUTHTYPE_SHARED_KEY; 395 ret = mwifiex_associate(priv, bss_desc); 396 } 397 398 if (bss && !priv->adapter->host_mlme_enabled) 399 cfg80211_put_bss(priv->adapter->wiphy, bss); 400 } else { 401 /* Adhoc mode */ 402 /* If the requested SSID matches current SSID, return */ 403 if (bss_desc && bss_desc->ssid.ssid_len && 404 cfg80211_ssid_eq(&priv->curr_bss_params.bss_descriptor.ssid, 405 &bss_desc->ssid)) { 406 ret = 0; 407 goto done; 408 } 409 410 ret = mwifiex_check_network_compatibility(priv, bss_desc); 411 412 mwifiex_stop_net_dev_queue(priv->netdev, adapter); 413 if (netif_carrier_ok(priv->netdev)) 414 netif_carrier_off(priv->netdev); 415 416 if (!ret) { 417 mwifiex_dbg(adapter, INFO, 418 "info: network found in scan\t" 419 " list. Joining...\n"); 420 ret = mwifiex_adhoc_join(priv, bss_desc); 421 if (bss) 422 cfg80211_put_bss(priv->adapter->wiphy, bss); 423 } else { 424 mwifiex_dbg(adapter, INFO, 425 "info: Network not found in\t" 426 "the list, creating adhoc with ssid = %s\n", 427 req_ssid->ssid); 428 ret = mwifiex_adhoc_start(priv, req_ssid); 429 } 430 } 431 432 done: 433 /* beacon_ie buffer was allocated in function 434 * mwifiex_fill_new_bss_desc(). Free it now. 435 */ 436 if (bss_desc) 437 kfree(bss_desc->beacon_buf); 438 kfree(bss_desc); 439 440 if (ret < 0) 441 priv->attempted_bss_desc = NULL; 442 443 return ret; 444 } 445 446 /* 447 * IOCTL request handler to set host sleep configuration. 448 * 449 * This function prepares the correct firmware command and 450 * issues it. 451 */ 452 int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action, 453 int cmd_type, struct mwifiex_ds_hs_cfg *hs_cfg) 454 455 { 456 struct mwifiex_adapter *adapter = priv->adapter; 457 int status = 0; 458 u32 prev_cond = 0; 459 460 if (!hs_cfg) 461 return -ENOMEM; 462 463 switch (action) { 464 case HostCmd_ACT_GEN_SET: 465 if (adapter->pps_uapsd_mode) { 466 mwifiex_dbg(adapter, INFO, 467 "info: Host Sleep IOCTL\t" 468 "is blocked in UAPSD/PPS mode\n"); 469 status = -1; 470 break; 471 } 472 if (hs_cfg->is_invoke_hostcmd) { 473 if (hs_cfg->conditions == HS_CFG_CANCEL) { 474 if (!test_bit(MWIFIEX_IS_HS_CONFIGURED, 475 &adapter->work_flags)) 476 /* Already cancelled */ 477 break; 478 /* Save previous condition */ 479 prev_cond = le32_to_cpu(adapter->hs_cfg 480 .conditions); 481 adapter->hs_cfg.conditions = 482 cpu_to_le32(hs_cfg->conditions); 483 } else if (hs_cfg->conditions) { 484 adapter->hs_cfg.conditions = 485 cpu_to_le32(hs_cfg->conditions); 486 adapter->hs_cfg.gpio = (u8)hs_cfg->gpio; 487 if (hs_cfg->gap) 488 adapter->hs_cfg.gap = (u8)hs_cfg->gap; 489 } else if (adapter->hs_cfg.conditions == 490 cpu_to_le32(HS_CFG_CANCEL)) { 491 /* Return failure if no parameters for HS 492 enable */ 493 status = -1; 494 break; 495 } 496 497 status = mwifiex_send_cmd(priv, 498 HostCmd_CMD_802_11_HS_CFG_ENH, 499 HostCmd_ACT_GEN_SET, 0, 500 &adapter->hs_cfg, 501 cmd_type == MWIFIEX_SYNC_CMD); 502 503 if (hs_cfg->conditions == HS_CFG_CANCEL) 504 /* Restore previous condition */ 505 adapter->hs_cfg.conditions = 506 cpu_to_le32(prev_cond); 507 } else { 508 adapter->hs_cfg.conditions = 509 cpu_to_le32(hs_cfg->conditions); 510 adapter->hs_cfg.gpio = (u8)hs_cfg->gpio; 511 adapter->hs_cfg.gap = (u8)hs_cfg->gap; 512 } 513 break; 514 case HostCmd_ACT_GEN_GET: 515 hs_cfg->conditions = le32_to_cpu(adapter->hs_cfg.conditions); 516 hs_cfg->gpio = adapter->hs_cfg.gpio; 517 hs_cfg->gap = adapter->hs_cfg.gap; 518 break; 519 default: 520 status = -1; 521 break; 522 } 523 524 return status; 525 } 526 527 /* 528 * Sends IOCTL request to cancel the existing Host Sleep configuration. 529 * 530 * This function allocates the IOCTL request buffer, fills it 531 * with requisite parameters and calls the IOCTL handler. 532 */ 533 int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type) 534 { 535 struct mwifiex_ds_hs_cfg hscfg; 536 537 hscfg.conditions = HS_CFG_CANCEL; 538 hscfg.is_invoke_hostcmd = true; 539 540 return mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET, 541 cmd_type, &hscfg); 542 } 543 EXPORT_SYMBOL_GPL(mwifiex_cancel_hs); 544 545 /* 546 * Sends IOCTL request to cancel the existing Host Sleep configuration. 547 * 548 * This function allocates the IOCTL request buffer, fills it 549 * with requisite parameters and calls the IOCTL handler. 550 */ 551 int mwifiex_enable_hs(struct mwifiex_adapter *adapter) 552 { 553 struct mwifiex_ds_hs_cfg hscfg; 554 struct mwifiex_private *priv; 555 int i; 556 557 if (disconnect_on_suspend) { 558 for (i = 0; i < adapter->priv_num; i++) { 559 priv = adapter->priv[i]; 560 mwifiex_deauthenticate(priv, NULL); 561 } 562 } 563 564 priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); 565 566 if (priv && priv->sched_scanning) { 567 #ifdef CONFIG_PM 568 if (priv->wdev.wiphy->wowlan_config && 569 !priv->wdev.wiphy->wowlan_config->nd_config) { 570 #endif 571 mwifiex_dbg(adapter, CMD, "aborting bgscan!\n"); 572 mwifiex_stop_bg_scan(priv); 573 cfg80211_sched_scan_stopped(priv->wdev.wiphy, 0); 574 #ifdef CONFIG_PM 575 } 576 #endif 577 } 578 579 if (adapter->hs_activated) { 580 mwifiex_dbg(adapter, CMD, 581 "cmd: HS Already activated\n"); 582 return true; 583 } 584 585 adapter->hs_activate_wait_q_woken = false; 586 587 memset(&hscfg, 0, sizeof(hscfg)); 588 hscfg.is_invoke_hostcmd = true; 589 590 set_bit(MWIFIEX_IS_HS_ENABLING, &adapter->work_flags); 591 mwifiex_cancel_all_pending_cmd(adapter); 592 593 if (mwifiex_set_hs_params(mwifiex_get_priv(adapter, 594 MWIFIEX_BSS_ROLE_STA), 595 HostCmd_ACT_GEN_SET, MWIFIEX_SYNC_CMD, 596 &hscfg)) { 597 mwifiex_dbg(adapter, ERROR, 598 "IOCTL request HS enable failed\n"); 599 return false; 600 } 601 602 if (wait_event_interruptible_timeout(adapter->hs_activate_wait_q, 603 adapter->hs_activate_wait_q_woken, 604 (5 * HZ)) <= 0) { 605 mwifiex_dbg(adapter, ERROR, 606 "hs_activate_wait_q terminated\n"); 607 return false; 608 } 609 610 return true; 611 } 612 EXPORT_SYMBOL_GPL(mwifiex_enable_hs); 613 614 /* 615 * IOCTL request handler to get BSS information. 616 * 617 * This function collates the information from different driver structures 618 * to send to the user. 619 */ 620 int mwifiex_get_bss_info(struct mwifiex_private *priv, 621 struct mwifiex_bss_info *info) 622 { 623 struct mwifiex_adapter *adapter = priv->adapter; 624 struct mwifiex_bssdescriptor *bss_desc; 625 626 if (!info) 627 return -1; 628 629 bss_desc = &priv->curr_bss_params.bss_descriptor; 630 631 info->bss_mode = priv->bss_mode; 632 633 memcpy(&info->ssid, &bss_desc->ssid, sizeof(struct cfg80211_ssid)); 634 635 memcpy(&info->bssid, &bss_desc->mac_address, ETH_ALEN); 636 637 info->bss_chan = bss_desc->channel; 638 639 memcpy(info->country_code, adapter->country_code, 640 IEEE80211_COUNTRY_STRING_LEN); 641 642 info->media_connected = priv->media_connected; 643 644 info->max_power_level = priv->max_tx_power_level; 645 info->min_power_level = priv->min_tx_power_level; 646 647 info->adhoc_state = priv->adhoc_state; 648 649 info->bcn_nf_last = priv->bcn_nf_last; 650 651 if (priv->sec_info.wep_enabled) 652 info->wep_status = true; 653 else 654 info->wep_status = false; 655 656 info->is_hs_configured = test_bit(MWIFIEX_IS_HS_CONFIGURED, 657 &adapter->work_flags); 658 info->is_deep_sleep = adapter->is_deep_sleep; 659 660 return 0; 661 } 662 663 /* 664 * The function disables auto deep sleep mode. 665 */ 666 int mwifiex_disable_auto_ds(struct mwifiex_private *priv) 667 { 668 struct mwifiex_ds_auto_ds auto_ds = { 669 .auto_ds = DEEP_SLEEP_OFF, 670 }; 671 672 return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH, 673 DIS_AUTO_PS, BITMAP_AUTO_DS, &auto_ds, true); 674 } 675 EXPORT_SYMBOL_GPL(mwifiex_disable_auto_ds); 676 677 /* 678 * Sends IOCTL request to get the data rate. 679 * 680 * This function allocates the IOCTL request buffer, fills it 681 * with requisite parameters and calls the IOCTL handler. 682 */ 683 int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, u32 *rate) 684 { 685 int ret; 686 687 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_TX_RATE_QUERY, 688 HostCmd_ACT_GEN_GET, 0, NULL, true); 689 690 if (!ret) { 691 if (priv->is_data_rate_auto) 692 *rate = mwifiex_index_to_data_rate(priv, priv->tx_rate, 693 priv->tx_htinfo); 694 else 695 *rate = priv->data_rate; 696 } 697 698 return ret; 699 } 700 701 /* 702 * IOCTL request handler to set tx power configuration. 703 * 704 * This function prepares the correct firmware command and 705 * issues it. 706 * 707 * For non-auto power mode, all the following power groups are set - 708 * - Modulation class HR/DSSS 709 * - Modulation class OFDM 710 * - Modulation class HTBW20 711 * - Modulation class HTBW40 712 */ 713 int mwifiex_set_tx_power(struct mwifiex_private *priv, 714 struct mwifiex_power_cfg *power_cfg) 715 { 716 int ret; 717 struct host_cmd_ds_txpwr_cfg *txp_cfg; 718 struct mwifiex_types_power_group *pg_tlv; 719 struct mwifiex_power_group *pg; 720 u8 *buf; 721 u16 dbm = 0; 722 723 if (!power_cfg->is_power_auto) { 724 dbm = (u16) power_cfg->power_level; 725 if ((dbm < priv->min_tx_power_level) || 726 (dbm > priv->max_tx_power_level)) { 727 mwifiex_dbg(priv->adapter, ERROR, 728 "txpower value %d dBm\t" 729 "is out of range (%d dBm-%d dBm)\n", 730 dbm, priv->min_tx_power_level, 731 priv->max_tx_power_level); 732 return -1; 733 } 734 } 735 buf = kzalloc(MWIFIEX_SIZE_OF_CMD_BUFFER, GFP_KERNEL); 736 if (!buf) 737 return -ENOMEM; 738 739 txp_cfg = (struct host_cmd_ds_txpwr_cfg *) buf; 740 txp_cfg->action = cpu_to_le16(HostCmd_ACT_GEN_SET); 741 if (!power_cfg->is_power_auto) { 742 u16 dbm_min = power_cfg->is_power_fixed ? 743 dbm : priv->min_tx_power_level; 744 745 txp_cfg->mode = cpu_to_le32(1); 746 pg_tlv = (struct mwifiex_types_power_group *) 747 (buf + sizeof(struct host_cmd_ds_txpwr_cfg)); 748 pg_tlv->type = cpu_to_le16(TLV_TYPE_POWER_GROUP); 749 pg_tlv->length = 750 cpu_to_le16(4 * sizeof(struct mwifiex_power_group)); 751 pg = (struct mwifiex_power_group *) 752 (buf + sizeof(struct host_cmd_ds_txpwr_cfg) 753 + sizeof(struct mwifiex_types_power_group)); 754 /* Power group for modulation class HR/DSSS */ 755 pg->first_rate_code = 0x00; 756 pg->last_rate_code = 0x03; 757 pg->modulation_class = MOD_CLASS_HR_DSSS; 758 pg->power_step = 0; 759 pg->power_min = (s8) dbm_min; 760 pg->power_max = (s8) dbm; 761 pg++; 762 /* Power group for modulation class OFDM */ 763 pg->first_rate_code = 0x00; 764 pg->last_rate_code = 0x07; 765 pg->modulation_class = MOD_CLASS_OFDM; 766 pg->power_step = 0; 767 pg->power_min = (s8) dbm_min; 768 pg->power_max = (s8) dbm; 769 pg++; 770 /* Power group for modulation class HTBW20 */ 771 pg->first_rate_code = 0x00; 772 pg->last_rate_code = 0x20; 773 pg->modulation_class = MOD_CLASS_HT; 774 pg->power_step = 0; 775 pg->power_min = (s8) dbm_min; 776 pg->power_max = (s8) dbm; 777 pg->ht_bandwidth = HT_BW_20; 778 pg++; 779 /* Power group for modulation class HTBW40 */ 780 pg->first_rate_code = 0x00; 781 pg->last_rate_code = 0x20; 782 pg->modulation_class = MOD_CLASS_HT; 783 pg->power_step = 0; 784 pg->power_min = (s8) dbm_min; 785 pg->power_max = (s8) dbm; 786 pg->ht_bandwidth = HT_BW_40; 787 } 788 ret = mwifiex_send_cmd(priv, HostCmd_CMD_TXPWR_CFG, 789 HostCmd_ACT_GEN_SET, 0, buf, true); 790 791 kfree(buf); 792 return ret; 793 } 794 795 /* 796 * IOCTL request handler to get power save mode. 797 * 798 * This function prepares the correct firmware command and 799 * issues it. 800 */ 801 int mwifiex_drv_set_power(struct mwifiex_private *priv, u32 *ps_mode) 802 { 803 int ret; 804 struct mwifiex_adapter *adapter = priv->adapter; 805 u16 sub_cmd; 806 807 if (*ps_mode) 808 adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; 809 else 810 adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; 811 sub_cmd = (*ps_mode) ? EN_AUTO_PS : DIS_AUTO_PS; 812 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH, 813 sub_cmd, BITMAP_STA_PS, NULL, true); 814 if ((!ret) && (sub_cmd == DIS_AUTO_PS)) 815 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH, 816 GET_PS, 0, NULL, false); 817 818 return ret; 819 } 820 821 /* 822 * IOCTL request handler to set/reset WPA IE. 823 * 824 * The supplied WPA IE is treated as a opaque buffer. Only the first field 825 * is checked to determine WPA version. If buffer length is zero, the existing 826 * WPA IE is reset. 827 */ 828 static int mwifiex_set_wpa_ie(struct mwifiex_private *priv, 829 u8 *ie_data_ptr, u16 ie_len) 830 { 831 if (ie_len) { 832 if (ie_len > sizeof(priv->wpa_ie)) { 833 mwifiex_dbg(priv->adapter, ERROR, 834 "failed to copy WPA IE, too big\n"); 835 return -1; 836 } 837 memcpy(priv->wpa_ie, ie_data_ptr, ie_len); 838 priv->wpa_ie_len = ie_len; 839 mwifiex_dbg(priv->adapter, CMD, 840 "cmd: Set Wpa_ie_len=%d IE=%#x\n", 841 priv->wpa_ie_len, priv->wpa_ie[0]); 842 843 if (priv->wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC) { 844 priv->sec_info.wpa_enabled = true; 845 } else if (priv->wpa_ie[0] == WLAN_EID_RSN) { 846 priv->sec_info.wpa2_enabled = true; 847 } else { 848 priv->sec_info.wpa_enabled = false; 849 priv->sec_info.wpa2_enabled = false; 850 } 851 } else { 852 memset(priv->wpa_ie, 0, sizeof(priv->wpa_ie)); 853 priv->wpa_ie_len = 0; 854 mwifiex_dbg(priv->adapter, INFO, 855 "info: reset wpa_ie_len=%d IE=%#x\n", 856 priv->wpa_ie_len, priv->wpa_ie[0]); 857 priv->sec_info.wpa_enabled = false; 858 priv->sec_info.wpa2_enabled = false; 859 } 860 861 return 0; 862 } 863 864 /* 865 * IOCTL request handler to set/reset WAPI IE. 866 * 867 * The supplied WAPI IE is treated as a opaque buffer. Only the first field 868 * is checked to internally enable WAPI. If buffer length is zero, the existing 869 * WAPI IE is reset. 870 */ 871 static int mwifiex_set_wapi_ie(struct mwifiex_private *priv, 872 u8 *ie_data_ptr, u16 ie_len) 873 { 874 if (ie_len) { 875 if (ie_len > sizeof(priv->wapi_ie)) { 876 mwifiex_dbg(priv->adapter, ERROR, 877 "info: failed to copy WAPI IE, too big\n"); 878 return -1; 879 } 880 memcpy(priv->wapi_ie, ie_data_ptr, ie_len); 881 priv->wapi_ie_len = ie_len; 882 mwifiex_dbg(priv->adapter, CMD, 883 "cmd: Set wapi_ie_len=%d IE=%#x\n", 884 priv->wapi_ie_len, priv->wapi_ie[0]); 885 886 if (priv->wapi_ie[0] == WLAN_EID_BSS_AC_ACCESS_DELAY) 887 priv->sec_info.wapi_enabled = true; 888 } else { 889 memset(priv->wapi_ie, 0, sizeof(priv->wapi_ie)); 890 priv->wapi_ie_len = ie_len; 891 mwifiex_dbg(priv->adapter, INFO, 892 "info: Reset wapi_ie_len=%d IE=%#x\n", 893 priv->wapi_ie_len, priv->wapi_ie[0]); 894 priv->sec_info.wapi_enabled = false; 895 } 896 return 0; 897 } 898 899 /* 900 * IOCTL request handler to set/reset WPS IE. 901 * 902 * The supplied WPS IE is treated as a opaque buffer. Only the first field 903 * is checked to internally enable WPS. If buffer length is zero, the existing 904 * WPS IE is reset. 905 */ 906 static int mwifiex_set_wps_ie(struct mwifiex_private *priv, 907 u8 *ie_data_ptr, u16 ie_len) 908 { 909 if (ie_len) { 910 if (ie_len > MWIFIEX_MAX_VSIE_LEN) { 911 mwifiex_dbg(priv->adapter, ERROR, 912 "info: failed to copy WPS IE, too big\n"); 913 return -1; 914 } 915 916 priv->wps_ie = kzalloc(MWIFIEX_MAX_VSIE_LEN, GFP_KERNEL); 917 if (!priv->wps_ie) 918 return -ENOMEM; 919 920 memcpy(priv->wps_ie, ie_data_ptr, ie_len); 921 priv->wps_ie_len = ie_len; 922 mwifiex_dbg(priv->adapter, CMD, 923 "cmd: Set wps_ie_len=%d IE=%#x\n", 924 priv->wps_ie_len, priv->wps_ie[0]); 925 } else { 926 kfree(priv->wps_ie); 927 priv->wps_ie_len = ie_len; 928 mwifiex_dbg(priv->adapter, INFO, 929 "info: Reset wps_ie_len=%d\n", priv->wps_ie_len); 930 } 931 return 0; 932 } 933 934 /* 935 * IOCTL request handler to set WAPI key. 936 * 937 * This function prepares the correct firmware command and 938 * issues it. 939 */ 940 static int mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_private *priv, 941 struct mwifiex_ds_encrypt_key *encrypt_key) 942 { 943 944 return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, 945 HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED, 946 encrypt_key, true); 947 } 948 949 /* 950 * IOCTL request handler to set WEP network key. 951 * 952 * This function prepares the correct firmware command and 953 * issues it, after validation checks. 954 */ 955 static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv, 956 struct mwifiex_ds_encrypt_key *encrypt_key) 957 { 958 struct mwifiex_adapter *adapter = priv->adapter; 959 int ret; 960 struct mwifiex_wep_key *wep_key; 961 int index; 962 963 if (priv->wep_key_curr_index >= NUM_WEP_KEYS) 964 priv->wep_key_curr_index = 0; 965 wep_key = &priv->wep_key[priv->wep_key_curr_index]; 966 index = encrypt_key->key_index; 967 if (encrypt_key->key_disable) { 968 priv->sec_info.wep_enabled = 0; 969 } else if (!encrypt_key->key_len) { 970 /* Copy the required key as the current key */ 971 wep_key = &priv->wep_key[index]; 972 if (!wep_key->key_length) { 973 mwifiex_dbg(adapter, ERROR, 974 "key not set, so cannot enable it\n"); 975 return -1; 976 } 977 978 if (adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2) { 979 memcpy(encrypt_key->key_material, 980 wep_key->key_material, wep_key->key_length); 981 encrypt_key->key_len = wep_key->key_length; 982 } 983 984 priv->wep_key_curr_index = (u16) index; 985 priv->sec_info.wep_enabled = 1; 986 } else { 987 wep_key = &priv->wep_key[index]; 988 memset(wep_key, 0, sizeof(struct mwifiex_wep_key)); 989 /* Copy the key in the driver */ 990 memcpy(wep_key->key_material, 991 encrypt_key->key_material, 992 encrypt_key->key_len); 993 wep_key->key_index = index; 994 wep_key->key_length = encrypt_key->key_len; 995 priv->sec_info.wep_enabled = 1; 996 } 997 if (wep_key->key_length) { 998 void *enc_key; 999 1000 if (encrypt_key->key_disable) { 1001 memset(&priv->wep_key[index], 0, 1002 sizeof(struct mwifiex_wep_key)); 1003 goto done; 1004 } 1005 1006 if (adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2) 1007 enc_key = encrypt_key; 1008 else 1009 enc_key = NULL; 1010 1011 /* Send request to firmware */ 1012 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, 1013 HostCmd_ACT_GEN_SET, 0, enc_key, false); 1014 if (ret) 1015 return ret; 1016 } 1017 1018 done: 1019 if (priv->sec_info.wep_enabled) 1020 priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE; 1021 else 1022 priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE; 1023 1024 ret = mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL, 1025 HostCmd_ACT_GEN_SET, 0, 1026 &priv->curr_pkt_filter, true); 1027 1028 return ret; 1029 } 1030 1031 /* 1032 * IOCTL request handler to set WPA key. 1033 * 1034 * This function prepares the correct firmware command and 1035 * issues it, after validation checks. 1036 * 1037 * Current driver only supports key length of up to 32 bytes. 1038 * 1039 * This function can also be used to disable a currently set key. 1040 */ 1041 static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private *priv, 1042 struct mwifiex_ds_encrypt_key *encrypt_key) 1043 { 1044 int ret; 1045 u8 remove_key = false; 1046 struct host_cmd_ds_802_11_key_material *ibss_key; 1047 1048 /* Current driver only supports key length of up to 32 bytes */ 1049 if (encrypt_key->key_len > WLAN_MAX_KEY_LEN) { 1050 mwifiex_dbg(priv->adapter, ERROR, 1051 "key length too long\n"); 1052 return -1; 1053 } 1054 1055 if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { 1056 /* 1057 * IBSS/WPA-None uses only one key (Group) for both receiving 1058 * and sending unicast and multicast packets. 1059 */ 1060 /* Send the key as PTK to firmware */ 1061 encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST; 1062 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, 1063 HostCmd_ACT_GEN_SET, 1064 KEY_INFO_ENABLED, encrypt_key, false); 1065 if (ret) 1066 return ret; 1067 1068 ibss_key = &priv->aes_key; 1069 memset(ibss_key, 0, 1070 sizeof(struct host_cmd_ds_802_11_key_material)); 1071 /* Copy the key in the driver */ 1072 memcpy(ibss_key->key_param_set.key, encrypt_key->key_material, 1073 encrypt_key->key_len); 1074 memcpy(&ibss_key->key_param_set.key_len, &encrypt_key->key_len, 1075 sizeof(ibss_key->key_param_set.key_len)); 1076 ibss_key->key_param_set.key_type_id 1077 = cpu_to_le16(KEY_TYPE_ID_TKIP); 1078 ibss_key->key_param_set.key_info = cpu_to_le16(KEY_ENABLED); 1079 1080 /* Send the key as GTK to firmware */ 1081 encrypt_key->key_index = ~MWIFIEX_KEY_INDEX_UNICAST; 1082 } 1083 1084 if (!encrypt_key->key_index) 1085 encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST; 1086 1087 if (remove_key) 1088 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, 1089 HostCmd_ACT_GEN_SET, 1090 !KEY_INFO_ENABLED, encrypt_key, true); 1091 else 1092 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL, 1093 HostCmd_ACT_GEN_SET, 1094 KEY_INFO_ENABLED, encrypt_key, true); 1095 1096 return ret; 1097 } 1098 1099 /* 1100 * IOCTL request handler to set/get network keys. 1101 * 1102 * This is a generic key handling function which supports WEP, WPA 1103 * and WAPI. 1104 */ 1105 static int 1106 mwifiex_sec_ioctl_encrypt_key(struct mwifiex_private *priv, 1107 struct mwifiex_ds_encrypt_key *encrypt_key) 1108 { 1109 int status; 1110 1111 if (encrypt_key->is_wapi_key) 1112 status = mwifiex_sec_ioctl_set_wapi_key(priv, encrypt_key); 1113 else if (encrypt_key->key_len > WLAN_KEY_LEN_WEP104) 1114 status = mwifiex_sec_ioctl_set_wpa_key(priv, encrypt_key); 1115 else 1116 status = mwifiex_sec_ioctl_set_wep_key(priv, encrypt_key); 1117 return status; 1118 } 1119 1120 /* 1121 * This function returns the driver version. 1122 */ 1123 int 1124 mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version, 1125 int max_len) 1126 { 1127 union { 1128 __le32 l; 1129 u8 c[4]; 1130 } ver; 1131 char fw_ver[32]; 1132 1133 ver.l = cpu_to_le32(adapter->fw_release_number); 1134 sprintf(fw_ver, "%u.%u.%u.p%u", ver.c[2], ver.c[1], ver.c[0], ver.c[3]); 1135 1136 snprintf(version, max_len, driver_version, fw_ver); 1137 1138 mwifiex_dbg(adapter, MSG, "info: MWIFIEX VERSION: %s\n", version); 1139 1140 return 0; 1141 } 1142 1143 /* 1144 * Sends IOCTL request to set encoding parameters. 1145 * 1146 * This function allocates the IOCTL request buffer, fills it 1147 * with requisite parameters and calls the IOCTL handler. 1148 */ 1149 int mwifiex_set_encode(struct mwifiex_private *priv, struct key_params *kp, 1150 const u8 *key, int key_len, u8 key_index, 1151 const u8 *mac_addr, int disable) 1152 { 1153 struct mwifiex_ds_encrypt_key encrypt_key; 1154 1155 memset(&encrypt_key, 0, sizeof(encrypt_key)); 1156 encrypt_key.key_len = key_len; 1157 encrypt_key.key_index = key_index; 1158 1159 if (kp && kp->cipher == WLAN_CIPHER_SUITE_AES_CMAC) 1160 encrypt_key.is_igtk_key = true; 1161 1162 if (!disable) { 1163 if (key_len) 1164 memcpy(encrypt_key.key_material, key, key_len); 1165 else 1166 encrypt_key.is_current_wep_key = true; 1167 1168 if (mac_addr) 1169 memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN); 1170 if (kp && kp->seq && kp->seq_len) { 1171 memcpy(encrypt_key.pn, kp->seq, kp->seq_len); 1172 encrypt_key.pn_len = kp->seq_len; 1173 encrypt_key.is_rx_seq_valid = true; 1174 } 1175 } else { 1176 encrypt_key.key_disable = true; 1177 if (mac_addr) 1178 memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN); 1179 } 1180 1181 return mwifiex_sec_ioctl_encrypt_key(priv, &encrypt_key); 1182 } 1183 1184 /* 1185 * Sends IOCTL request to get extended version. 1186 * 1187 * This function allocates the IOCTL request buffer, fills it 1188 * with requisite parameters and calls the IOCTL handler. 1189 */ 1190 int 1191 mwifiex_get_ver_ext(struct mwifiex_private *priv, u32 version_str_sel) 1192 { 1193 struct mwifiex_ver_ext ver_ext; 1194 1195 memset(&ver_ext, 0, sizeof(ver_ext)); 1196 ver_ext.version_str_sel = version_str_sel; 1197 if (mwifiex_send_cmd(priv, HostCmd_CMD_VERSION_EXT, 1198 HostCmd_ACT_GEN_GET, 0, &ver_ext, true)) 1199 return -1; 1200 1201 return 0; 1202 } 1203 1204 int 1205 mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action, 1206 struct ieee80211_channel *chan, 1207 unsigned int duration) 1208 { 1209 struct host_cmd_ds_remain_on_chan roc_cfg; 1210 u8 sc; 1211 1212 memset(&roc_cfg, 0, sizeof(roc_cfg)); 1213 roc_cfg.action = cpu_to_le16(action); 1214 if (action == HostCmd_ACT_GEN_SET) { 1215 roc_cfg.band_cfg = chan->band; 1216 sc = mwifiex_chan_type_to_sec_chan_offset(NL80211_CHAN_NO_HT); 1217 roc_cfg.band_cfg |= (sc << 2); 1218 1219 roc_cfg.channel = 1220 ieee80211_frequency_to_channel(chan->center_freq); 1221 roc_cfg.duration = cpu_to_le32(duration); 1222 } 1223 if (mwifiex_send_cmd(priv, HostCmd_CMD_REMAIN_ON_CHAN, 1224 action, 0, &roc_cfg, true)) { 1225 mwifiex_dbg(priv->adapter, ERROR, 1226 "failed to remain on channel\n"); 1227 return -1; 1228 } 1229 1230 return roc_cfg.status; 1231 } 1232 1233 /* 1234 * Sends IOCTL request to get statistics information. 1235 * 1236 * This function allocates the IOCTL request buffer, fills it 1237 * with requisite parameters and calls the IOCTL handler. 1238 */ 1239 int 1240 mwifiex_get_stats_info(struct mwifiex_private *priv, 1241 struct mwifiex_ds_get_stats *log) 1242 { 1243 return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_GET_LOG, 1244 HostCmd_ACT_GEN_GET, 0, log, true); 1245 } 1246 1247 /* 1248 * IOCTL request handler to read/write register. 1249 * 1250 * This function prepares the correct firmware command and 1251 * issues it. 1252 * 1253 * Access to the following registers are supported - 1254 * - MAC 1255 * - BBP 1256 * - RF 1257 * - PMIC 1258 * - CAU 1259 */ 1260 static int mwifiex_reg_mem_ioctl_reg_rw(struct mwifiex_private *priv, 1261 struct mwifiex_ds_reg_rw *reg_rw, 1262 u16 action) 1263 { 1264 u16 cmd_no; 1265 1266 switch (reg_rw->type) { 1267 case MWIFIEX_REG_MAC: 1268 cmd_no = HostCmd_CMD_MAC_REG_ACCESS; 1269 break; 1270 case MWIFIEX_REG_BBP: 1271 cmd_no = HostCmd_CMD_BBP_REG_ACCESS; 1272 break; 1273 case MWIFIEX_REG_RF: 1274 cmd_no = HostCmd_CMD_RF_REG_ACCESS; 1275 break; 1276 case MWIFIEX_REG_PMIC: 1277 cmd_no = HostCmd_CMD_PMIC_REG_ACCESS; 1278 break; 1279 case MWIFIEX_REG_CAU: 1280 cmd_no = HostCmd_CMD_CAU_REG_ACCESS; 1281 break; 1282 default: 1283 return -1; 1284 } 1285 1286 return mwifiex_send_cmd(priv, cmd_no, action, 0, reg_rw, true); 1287 } 1288 1289 /* 1290 * Sends IOCTL request to write to a register. 1291 * 1292 * This function allocates the IOCTL request buffer, fills it 1293 * with requisite parameters and calls the IOCTL handler. 1294 */ 1295 int 1296 mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type, 1297 u32 reg_offset, u32 reg_value) 1298 { 1299 struct mwifiex_ds_reg_rw reg_rw; 1300 1301 reg_rw.type = reg_type; 1302 reg_rw.offset = reg_offset; 1303 reg_rw.value = reg_value; 1304 1305 return mwifiex_reg_mem_ioctl_reg_rw(priv, ®_rw, HostCmd_ACT_GEN_SET); 1306 } 1307 1308 /* 1309 * Sends IOCTL request to read from a register. 1310 * 1311 * This function allocates the IOCTL request buffer, fills it 1312 * with requisite parameters and calls the IOCTL handler. 1313 */ 1314 int 1315 mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type, 1316 u32 reg_offset, u32 *value) 1317 { 1318 int ret; 1319 struct mwifiex_ds_reg_rw reg_rw; 1320 1321 reg_rw.type = reg_type; 1322 reg_rw.offset = reg_offset; 1323 ret = mwifiex_reg_mem_ioctl_reg_rw(priv, ®_rw, HostCmd_ACT_GEN_GET); 1324 1325 if (ret) 1326 goto done; 1327 1328 *value = reg_rw.value; 1329 1330 done: 1331 return ret; 1332 } 1333 1334 /* 1335 * Sends IOCTL request to read from EEPROM. 1336 * 1337 * This function allocates the IOCTL request buffer, fills it 1338 * with requisite parameters and calls the IOCTL handler. 1339 */ 1340 int 1341 mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes, 1342 u8 *value) 1343 { 1344 int ret; 1345 struct mwifiex_ds_read_eeprom rd_eeprom; 1346 1347 rd_eeprom.offset = offset; 1348 rd_eeprom.byte_count = bytes; 1349 1350 /* Send request to firmware */ 1351 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_EEPROM_ACCESS, 1352 HostCmd_ACT_GEN_GET, 0, &rd_eeprom, true); 1353 1354 if (!ret) 1355 memcpy(value, rd_eeprom.value, min((u16)MAX_EEPROM_DATA, 1356 rd_eeprom.byte_count)); 1357 return ret; 1358 } 1359 1360 /* 1361 * This function sets a generic IE. In addition to generic IE, it can 1362 * also handle WPA, WPA2 and WAPI IEs. 1363 */ 1364 static int 1365 mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr, 1366 u16 ie_len) 1367 { 1368 struct ieee_types_vendor_header *pvendor_ie; 1369 static const u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 }; 1370 static const u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 }; 1371 u16 unparsed_len = ie_len, cur_ie_len; 1372 1373 /* If the passed length is zero, reset the buffer */ 1374 if (!ie_len) { 1375 priv->gen_ie_buf_len = 0; 1376 priv->wps.session_enable = false; 1377 return 0; 1378 } else if (!ie_data_ptr || 1379 ie_len <= sizeof(struct ieee_types_header)) { 1380 return -1; 1381 } 1382 pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr; 1383 1384 while (pvendor_ie) { 1385 cur_ie_len = pvendor_ie->len + sizeof(struct ieee_types_header); 1386 1387 if (pvendor_ie->element_id == WLAN_EID_RSN) { 1388 /* IE is a WPA/WPA2 IE so call set_wpa function */ 1389 mwifiex_set_wpa_ie(priv, (u8 *)pvendor_ie, cur_ie_len); 1390 priv->wps.session_enable = false; 1391 goto next_ie; 1392 } 1393 1394 if (pvendor_ie->element_id == WLAN_EID_BSS_AC_ACCESS_DELAY) { 1395 /* IE is a WAPI IE so call set_wapi function */ 1396 mwifiex_set_wapi_ie(priv, (u8 *)pvendor_ie, 1397 cur_ie_len); 1398 goto next_ie; 1399 } 1400 1401 if (pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC) { 1402 /* Test to see if it is a WPA IE, if not, then 1403 * it is a gen IE 1404 */ 1405 if (!memcmp(&pvendor_ie->oui, wpa_oui, 1406 sizeof(wpa_oui))) { 1407 /* IE is a WPA/WPA2 IE so call set_wpa function 1408 */ 1409 mwifiex_set_wpa_ie(priv, (u8 *)pvendor_ie, 1410 cur_ie_len); 1411 priv->wps.session_enable = false; 1412 goto next_ie; 1413 } 1414 1415 if (!memcmp(&pvendor_ie->oui, wps_oui, 1416 sizeof(wps_oui))) { 1417 /* Test to see if it is a WPS IE, 1418 * if so, enable wps session flag 1419 */ 1420 priv->wps.session_enable = true; 1421 mwifiex_dbg(priv->adapter, MSG, 1422 "WPS Session Enabled.\n"); 1423 mwifiex_set_wps_ie(priv, (u8 *)pvendor_ie, 1424 cur_ie_len); 1425 goto next_ie; 1426 } 1427 } 1428 1429 /* Saved in gen_ie, such as P2P IE.etc.*/ 1430 1431 /* Verify that the passed length is not larger than the 1432 * available space remaining in the buffer 1433 */ 1434 if (cur_ie_len < 1435 (sizeof(priv->gen_ie_buf) - priv->gen_ie_buf_len)) { 1436 /* Append the passed data to the end 1437 * of the genIeBuffer 1438 */ 1439 memcpy(priv->gen_ie_buf + priv->gen_ie_buf_len, 1440 (u8 *)pvendor_ie, cur_ie_len); 1441 /* Increment the stored buffer length by the 1442 * size passed 1443 */ 1444 priv->gen_ie_buf_len += cur_ie_len; 1445 } 1446 1447 next_ie: 1448 unparsed_len -= cur_ie_len; 1449 1450 if (unparsed_len <= sizeof(struct ieee_types_header)) 1451 pvendor_ie = NULL; 1452 else 1453 pvendor_ie = (struct ieee_types_vendor_header *) 1454 (((u8 *)pvendor_ie) + cur_ie_len); 1455 } 1456 1457 return 0; 1458 } 1459 1460 /* 1461 * IOCTL request handler to set/get generic IE. 1462 * 1463 * In addition to various generic IEs, this function can also be 1464 * used to set the ARP filter. 1465 */ 1466 static int mwifiex_misc_ioctl_gen_ie(struct mwifiex_private *priv, 1467 struct mwifiex_ds_misc_gen_ie *gen_ie, 1468 u16 action) 1469 { 1470 struct mwifiex_adapter *adapter = priv->adapter; 1471 1472 switch (gen_ie->type) { 1473 case MWIFIEX_IE_TYPE_GEN_IE: 1474 if (action == HostCmd_ACT_GEN_GET) { 1475 gen_ie->len = priv->wpa_ie_len; 1476 memcpy(gen_ie->ie_data, priv->wpa_ie, gen_ie->len); 1477 } else { 1478 mwifiex_set_gen_ie_helper(priv, gen_ie->ie_data, 1479 (u16) gen_ie->len); 1480 } 1481 break; 1482 case MWIFIEX_IE_TYPE_ARP_FILTER: 1483 memset(adapter->arp_filter, 0, sizeof(adapter->arp_filter)); 1484 if (gen_ie->len > ARP_FILTER_MAX_BUF_SIZE) { 1485 adapter->arp_filter_size = 0; 1486 mwifiex_dbg(adapter, ERROR, 1487 "invalid ARP filter size\n"); 1488 return -1; 1489 } else { 1490 memcpy(adapter->arp_filter, gen_ie->ie_data, 1491 gen_ie->len); 1492 adapter->arp_filter_size = gen_ie->len; 1493 } 1494 break; 1495 default: 1496 mwifiex_dbg(adapter, ERROR, "invalid IE type\n"); 1497 return -1; 1498 } 1499 return 0; 1500 } 1501 1502 /* 1503 * Sends IOCTL request to set a generic IE. 1504 * 1505 * This function allocates the IOCTL request buffer, fills it 1506 * with requisite parameters and calls the IOCTL handler. 1507 */ 1508 int 1509 mwifiex_set_gen_ie(struct mwifiex_private *priv, const u8 *ie, int ie_len) 1510 { 1511 struct mwifiex_ds_misc_gen_ie gen_ie; 1512 1513 if (ie_len > IEEE_MAX_IE_SIZE) 1514 return -EFAULT; 1515 1516 gen_ie.type = MWIFIEX_IE_TYPE_GEN_IE; 1517 gen_ie.len = ie_len; 1518 memcpy(gen_ie.ie_data, ie, ie_len); 1519 if (mwifiex_misc_ioctl_gen_ie(priv, &gen_ie, HostCmd_ACT_GEN_SET)) 1520 return -EFAULT; 1521 1522 return 0; 1523 } 1524 1525 /* This function get Host Sleep wake up reason. 1526 * 1527 */ 1528 int mwifiex_get_wakeup_reason(struct mwifiex_private *priv, u16 action, 1529 int cmd_type, 1530 struct mwifiex_ds_wakeup_reason *wakeup_reason) 1531 { 1532 int status = 0; 1533 1534 status = mwifiex_send_cmd(priv, HostCmd_CMD_HS_WAKEUP_REASON, 1535 HostCmd_ACT_GEN_GET, 0, wakeup_reason, 1536 cmd_type == MWIFIEX_SYNC_CMD); 1537 1538 return status; 1539 } 1540 1541 int mwifiex_get_chan_info(struct mwifiex_private *priv, 1542 struct mwifiex_channel_band *channel_band) 1543 { 1544 int status = 0; 1545 1546 status = mwifiex_send_cmd(priv, HostCmd_CMD_STA_CONFIGURE, 1547 HostCmd_ACT_GEN_GET, 0, channel_band, 1548 MWIFIEX_SYNC_CMD); 1549 1550 return status; 1551 } 1552