1498 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * NXP Wireless LAN device driver: functions for station ioctl4 *5 * Copyright 2011-2020 NXP6 */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 17static int disconnect_on_suspend;18module_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 for24 * size, and the calling function must ensure enough memory is25 * available.26 */27int 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 pending43 * request after waking up, in case of errors.44 */45int 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 and71 * issues it to set the multicast list.72 *73 * This function can be used to enable promiscuous mode, or enable all74 * multicast packets, or to enable selective multicast.75 */76int 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 provided125 * information.126 * beacon_ie buffer is allocated in this function. It is caller's127 * responsibility to free the memory.128 */129int 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 else170 bss_desc->bss_mode = NL80211_IFTYPE_STATION;171 172 /* Disable 11ac by default. Enable it only where there173 * exist VHT_CAP IE in AP beacon174 */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 183void mwifiex_dnld_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 193static int mwifiex_process_country_ie(struct mwifiex_private *priv,194 struct cfg80211_bss *bss)195{196 const u8 *country_ie;197 u8 country_ie_len;198 struct mwifiex_802_11d_domain_reg *domain_info =199 &priv->adapter->domain_reg;200 201 rcu_read_lock();202 country_ie = ieee80211_bss_get_ie(bss, WLAN_EID_COUNTRY);203 if (!country_ie) {204 rcu_read_unlock();205 return 0;206 }207 208 country_ie_len = country_ie[1];209 if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) {210 rcu_read_unlock();211 return 0;212 }213 214 if (!strncmp(priv->adapter->country_code, &country_ie[2], 2)) {215 rcu_read_unlock();216 mwifiex_dbg(priv->adapter, INFO,217 "11D: skip setting domain info in FW\n");218 return 0;219 }220 221 if (country_ie_len >222 (IEEE80211_COUNTRY_STRING_LEN + MWIFIEX_MAX_TRIPLET_802_11D)) {223 rcu_read_unlock();224 mwifiex_dbg(priv->adapter, ERROR,225 "11D: country_ie_len overflow!, deauth AP\n");226 return -EINVAL;227 }228 229 memcpy(priv->adapter->country_code, &country_ie[2], 2);230 231 domain_info->country_code[0] = country_ie[2];232 domain_info->country_code[1] = country_ie[3];233 domain_info->country_code[2] = ' ';234 235 country_ie_len -= IEEE80211_COUNTRY_STRING_LEN;236 237 domain_info->no_of_triplet =238 country_ie_len / sizeof(struct ieee80211_country_ie_triplet);239 240 memcpy((u8 *)domain_info->triplet,241 &country_ie[2] + IEEE80211_COUNTRY_STRING_LEN, country_ie_len);242 243 rcu_read_unlock();244 245 if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,246 HostCmd_ACT_GEN_SET, 0, NULL, false)) {247 mwifiex_dbg(priv->adapter, ERROR,248 "11D: setting domain info in FW fail\n");249 return -1;250 }251 252 mwifiex_dnld_txpwr_table(priv);253 254 return 0;255}256 257/*258 * In Ad-Hoc mode, the IBSS is created if not found in scan list.259 * In both Ad-Hoc and infra mode, an deauthentication is performed260 * first.261 */262int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,263 struct cfg80211_ssid *req_ssid)264{265 int ret;266 struct mwifiex_adapter *adapter = priv->adapter;267 struct mwifiex_bssdescriptor *bss_desc = NULL;268 269 priv->scan_block = false;270 271 if (bss) {272 if (adapter->region_code == 0x00 &&273 mwifiex_process_country_ie(priv, bss))274 return -EINVAL;275 276 /* Allocate and fill new bss descriptor */277 bss_desc = kzalloc(sizeof(struct mwifiex_bssdescriptor),278 GFP_KERNEL);279 if (!bss_desc)280 return -ENOMEM;281 282 ret = mwifiex_fill_new_bss_desc(priv, bss, bss_desc);283 if (ret)284 goto done;285 }286 287 if (priv->bss_mode == NL80211_IFTYPE_STATION ||288 priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) {289 u8 config_bands;290 291 if (!bss_desc)292 return -1;293 294 if (mwifiex_band_to_radio_type(bss_desc->bss_band) ==295 HostCmd_SCAN_RADIO_TYPE_BG) {296 config_bands = BAND_B | BAND_G | BAND_GN;297 } else {298 config_bands = BAND_A | BAND_AN;299 if (adapter->fw_bands & BAND_AAC)300 config_bands |= BAND_AAC;301 }302 303 if (!((config_bands | adapter->fw_bands) & ~adapter->fw_bands))304 adapter->config_bands = config_bands;305 306 ret = mwifiex_check_network_compatibility(priv, bss_desc);307 if (ret)308 goto done;309 310 if (mwifiex_11h_get_csa_closed_channel(priv) ==311 (u8)bss_desc->channel) {312 mwifiex_dbg(adapter, ERROR,313 "Attempt to reconnect on csa closed chan(%d)\n",314 bss_desc->channel);315 ret = -1;316 goto done;317 }318 319 mwifiex_dbg(adapter, INFO,320 "info: SSID found in scan list ...\t"321 "associating...\n");322 323 mwifiex_stop_net_dev_queue(priv->netdev, adapter);324 if (netif_carrier_ok(priv->netdev))325 netif_carrier_off(priv->netdev);326 327 /* Clear any past association response stored for328 * application retrieval */329 priv->assoc_rsp_size = 0;330 ret = mwifiex_associate(priv, bss_desc);331 332 /* If auth type is auto and association fails using open mode,333 * try to connect using shared mode */334 if (ret == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG &&335 priv->sec_info.is_authtype_auto &&336 priv->sec_info.wep_enabled) {337 priv->sec_info.authentication_mode =338 NL80211_AUTHTYPE_SHARED_KEY;339 ret = mwifiex_associate(priv, bss_desc);340 }341 342 if (bss && !priv->adapter->host_mlme_enabled)343 cfg80211_put_bss(priv->adapter->wiphy, bss);344 } else {345 /* Adhoc mode */346 /* If the requested SSID matches current SSID, return */347 if (bss_desc && bss_desc->ssid.ssid_len &&348 cfg80211_ssid_eq(&priv->curr_bss_params.bss_descriptor.ssid,349 &bss_desc->ssid)) {350 ret = 0;351 goto done;352 }353 354 priv->adhoc_is_link_sensed = false;355 356 ret = mwifiex_check_network_compatibility(priv, bss_desc);357 358 mwifiex_stop_net_dev_queue(priv->netdev, adapter);359 if (netif_carrier_ok(priv->netdev))360 netif_carrier_off(priv->netdev);361 362 if (!ret) {363 mwifiex_dbg(adapter, INFO,364 "info: network found in scan\t"365 " list. Joining...\n");366 ret = mwifiex_adhoc_join(priv, bss_desc);367 if (bss)368 cfg80211_put_bss(priv->adapter->wiphy, bss);369 } else {370 mwifiex_dbg(adapter, INFO,371 "info: Network not found in\t"372 "the list, creating adhoc with ssid = %s\n",373 req_ssid->ssid);374 ret = mwifiex_adhoc_start(priv, req_ssid);375 }376 }377 378done:379 /* beacon_ie buffer was allocated in function380 * mwifiex_fill_new_bss_desc(). Free it now.381 */382 if (bss_desc)383 kfree(bss_desc->beacon_buf);384 kfree(bss_desc);385 386 if (ret < 0)387 priv->attempted_bss_desc = NULL;388 389 return ret;390}391 392/*393 * IOCTL request handler to set host sleep configuration.394 *395 * This function prepares the correct firmware command and396 * issues it.397 */398int mwifiex_set_hs_params(struct mwifiex_private *priv, u16 action,399 int cmd_type, struct mwifiex_ds_hs_cfg *hs_cfg)400 401{402 struct mwifiex_adapter *adapter = priv->adapter;403 int status = 0;404 u32 prev_cond = 0;405 406 if (!hs_cfg)407 return -ENOMEM;408 409 switch (action) {410 case HostCmd_ACT_GEN_SET:411 if (adapter->pps_uapsd_mode) {412 mwifiex_dbg(adapter, INFO,413 "info: Host Sleep IOCTL\t"414 "is blocked in UAPSD/PPS mode\n");415 status = -1;416 break;417 }418 if (hs_cfg->is_invoke_hostcmd) {419 if (hs_cfg->conditions == HS_CFG_CANCEL) {420 if (!test_bit(MWIFIEX_IS_HS_CONFIGURED,421 &adapter->work_flags))422 /* Already cancelled */423 break;424 /* Save previous condition */425 prev_cond = le32_to_cpu(adapter->hs_cfg426 .conditions);427 adapter->hs_cfg.conditions =428 cpu_to_le32(hs_cfg->conditions);429 } else if (hs_cfg->conditions) {430 adapter->hs_cfg.conditions =431 cpu_to_le32(hs_cfg->conditions);432 adapter->hs_cfg.gpio = (u8)hs_cfg->gpio;433 if (hs_cfg->gap)434 adapter->hs_cfg.gap = (u8)hs_cfg->gap;435 } else if (adapter->hs_cfg.conditions ==436 cpu_to_le32(HS_CFG_CANCEL)) {437 /* Return failure if no parameters for HS438 enable */439 status = -1;440 break;441 }442 443 status = mwifiex_send_cmd(priv,444 HostCmd_CMD_802_11_HS_CFG_ENH,445 HostCmd_ACT_GEN_SET, 0,446 &adapter->hs_cfg,447 cmd_type == MWIFIEX_SYNC_CMD);448 449 if (hs_cfg->conditions == HS_CFG_CANCEL)450 /* Restore previous condition */451 adapter->hs_cfg.conditions =452 cpu_to_le32(prev_cond);453 } else {454 adapter->hs_cfg.conditions =455 cpu_to_le32(hs_cfg->conditions);456 adapter->hs_cfg.gpio = (u8)hs_cfg->gpio;457 adapter->hs_cfg.gap = (u8)hs_cfg->gap;458 }459 break;460 case HostCmd_ACT_GEN_GET:461 hs_cfg->conditions = le32_to_cpu(adapter->hs_cfg.conditions);462 hs_cfg->gpio = adapter->hs_cfg.gpio;463 hs_cfg->gap = adapter->hs_cfg.gap;464 break;465 default:466 status = -1;467 break;468 }469 470 return status;471}472 473/*474 * Sends IOCTL request to cancel the existing Host Sleep configuration.475 *476 * This function allocates the IOCTL request buffer, fills it477 * with requisite parameters and calls the IOCTL handler.478 */479int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type)480{481 struct mwifiex_ds_hs_cfg hscfg;482 483 hscfg.conditions = HS_CFG_CANCEL;484 hscfg.is_invoke_hostcmd = true;485 486 return mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,487 cmd_type, &hscfg);488}489EXPORT_SYMBOL_GPL(mwifiex_cancel_hs);490 491/*492 * Sends IOCTL request to cancel the existing Host Sleep configuration.493 *494 * This function allocates the IOCTL request buffer, fills it495 * with requisite parameters and calls the IOCTL handler.496 */497int mwifiex_enable_hs(struct mwifiex_adapter *adapter)498{499 struct mwifiex_ds_hs_cfg hscfg;500 struct mwifiex_private *priv;501 int i;502 503 if (disconnect_on_suspend) {504 for (i = 0; i < adapter->priv_num; i++) {505 priv = adapter->priv[i];506 mwifiex_deauthenticate(priv, NULL);507 }508 }509 510 priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);511 512 if (priv && priv->sched_scanning) {513#ifdef CONFIG_PM514 if (priv->wdev.wiphy->wowlan_config &&515 !priv->wdev.wiphy->wowlan_config->nd_config) {516#endif517 mwifiex_dbg(adapter, CMD, "aborting bgscan!\n");518 mwifiex_stop_bg_scan(priv);519 cfg80211_sched_scan_stopped(priv->wdev.wiphy, 0);520#ifdef CONFIG_PM521 }522#endif523 }524 525 if (adapter->hs_activated) {526 mwifiex_dbg(adapter, CMD,527 "cmd: HS Already activated\n");528 return true;529 }530 531 adapter->hs_activate_wait_q_woken = false;532 533 memset(&hscfg, 0, sizeof(hscfg));534 hscfg.is_invoke_hostcmd = true;535 536 set_bit(MWIFIEX_IS_HS_ENABLING, &adapter->work_flags);537 mwifiex_cancel_all_pending_cmd(adapter);538 539 if (mwifiex_set_hs_params(mwifiex_get_priv(adapter,540 MWIFIEX_BSS_ROLE_STA),541 HostCmd_ACT_GEN_SET, MWIFIEX_SYNC_CMD,542 &hscfg)) {543 mwifiex_dbg(adapter, ERROR,544 "IOCTL request HS enable failed\n");545 return false;546 }547 548 if (wait_event_interruptible_timeout(adapter->hs_activate_wait_q,549 adapter->hs_activate_wait_q_woken,550 (10 * HZ)) <= 0) {551 mwifiex_dbg(adapter, ERROR,552 "hs_activate_wait_q terminated\n");553 return false;554 }555 556 return true;557}558EXPORT_SYMBOL_GPL(mwifiex_enable_hs);559 560/*561 * IOCTL request handler to get BSS information.562 *563 * This function collates the information from different driver structures564 * to send to the user.565 */566int mwifiex_get_bss_info(struct mwifiex_private *priv,567 struct mwifiex_bss_info *info)568{569 struct mwifiex_adapter *adapter = priv->adapter;570 struct mwifiex_bssdescriptor *bss_desc;571 572 if (!info)573 return -1;574 575 bss_desc = &priv->curr_bss_params.bss_descriptor;576 577 info->bss_mode = priv->bss_mode;578 579 memcpy(&info->ssid, &bss_desc->ssid, sizeof(struct cfg80211_ssid));580 581 memcpy(&info->bssid, &bss_desc->mac_address, ETH_ALEN);582 583 info->bss_chan = bss_desc->channel;584 585 memcpy(info->country_code, adapter->country_code,586 IEEE80211_COUNTRY_STRING_LEN);587 588 info->media_connected = priv->media_connected;589 590 info->max_power_level = priv->max_tx_power_level;591 info->min_power_level = priv->min_tx_power_level;592 593 info->adhoc_state = priv->adhoc_state;594 595 info->bcn_nf_last = priv->bcn_nf_last;596 597 if (priv->sec_info.wep_enabled)598 info->wep_status = true;599 else600 info->wep_status = false;601 602 info->is_hs_configured = test_bit(MWIFIEX_IS_HS_CONFIGURED,603 &adapter->work_flags);604 info->is_deep_sleep = adapter->is_deep_sleep;605 606 return 0;607}608 609/*610 * The function disables auto deep sleep mode.611 */612int mwifiex_disable_auto_ds(struct mwifiex_private *priv)613{614 struct mwifiex_ds_auto_ds auto_ds = {615 .auto_ds = DEEP_SLEEP_OFF,616 };617 618 return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,619 DIS_AUTO_PS, BITMAP_AUTO_DS, &auto_ds, true);620}621EXPORT_SYMBOL_GPL(mwifiex_disable_auto_ds);622 623/*624 * Sends IOCTL request to get the data rate.625 *626 * This function allocates the IOCTL request buffer, fills it627 * with requisite parameters and calls the IOCTL handler.628 */629int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, u32 *rate)630{631 int ret;632 633 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_TX_RATE_QUERY,634 HostCmd_ACT_GEN_GET, 0, NULL, true);635 636 if (!ret) {637 if (priv->is_data_rate_auto)638 *rate = mwifiex_index_to_data_rate(priv, priv->tx_rate,639 priv->tx_htinfo);640 else641 *rate = priv->data_rate;642 }643 644 return ret;645}646 647/*648 * IOCTL request handler to set tx power configuration.649 *650 * This function prepares the correct firmware command and651 * issues it.652 *653 * For non-auto power mode, all the following power groups are set -654 * - Modulation class HR/DSSS655 * - Modulation class OFDM656 * - Modulation class HTBW20657 * - Modulation class HTBW40658 */659int mwifiex_set_tx_power(struct mwifiex_private *priv,660 struct mwifiex_power_cfg *power_cfg)661{662 int ret;663 struct host_cmd_ds_txpwr_cfg *txp_cfg;664 struct mwifiex_types_power_group *pg_tlv;665 struct mwifiex_power_group *pg;666 u8 *buf;667 u16 dbm = 0;668 669 if (!power_cfg->is_power_auto) {670 dbm = (u16) power_cfg->power_level;671 if ((dbm < priv->min_tx_power_level) ||672 (dbm > priv->max_tx_power_level)) {673 mwifiex_dbg(priv->adapter, ERROR,674 "txpower value %d dBm\t"675 "is out of range (%d dBm-%d dBm)\n",676 dbm, priv->min_tx_power_level,677 priv->max_tx_power_level);678 return -1;679 }680 }681 buf = kzalloc(MWIFIEX_SIZE_OF_CMD_BUFFER, GFP_KERNEL);682 if (!buf)683 return -ENOMEM;684 685 txp_cfg = (struct host_cmd_ds_txpwr_cfg *) buf;686 txp_cfg->action = cpu_to_le16(HostCmd_ACT_GEN_SET);687 if (!power_cfg->is_power_auto) {688 u16 dbm_min = power_cfg->is_power_fixed ?689 dbm : priv->min_tx_power_level;690 691 txp_cfg->mode = cpu_to_le32(1);692 pg_tlv = (struct mwifiex_types_power_group *)693 (buf + sizeof(struct host_cmd_ds_txpwr_cfg));694 pg_tlv->type = cpu_to_le16(TLV_TYPE_POWER_GROUP);695 pg_tlv->length =696 cpu_to_le16(4 * sizeof(struct mwifiex_power_group));697 pg = (struct mwifiex_power_group *)698 (buf + sizeof(struct host_cmd_ds_txpwr_cfg)699 + sizeof(struct mwifiex_types_power_group));700 /* Power group for modulation class HR/DSSS */701 pg->first_rate_code = 0x00;702 pg->last_rate_code = 0x03;703 pg->modulation_class = MOD_CLASS_HR_DSSS;704 pg->power_step = 0;705 pg->power_min = (s8) dbm_min;706 pg->power_max = (s8) dbm;707 pg++;708 /* Power group for modulation class OFDM */709 pg->first_rate_code = 0x00;710 pg->last_rate_code = 0x07;711 pg->modulation_class = MOD_CLASS_OFDM;712 pg->power_step = 0;713 pg->power_min = (s8) dbm_min;714 pg->power_max = (s8) dbm;715 pg++;716 /* Power group for modulation class HTBW20 */717 pg->first_rate_code = 0x00;718 pg->last_rate_code = 0x20;719 pg->modulation_class = MOD_CLASS_HT;720 pg->power_step = 0;721 pg->power_min = (s8) dbm_min;722 pg->power_max = (s8) dbm;723 pg->ht_bandwidth = HT_BW_20;724 pg++;725 /* Power group for modulation class HTBW40 */726 pg->first_rate_code = 0x00;727 pg->last_rate_code = 0x20;728 pg->modulation_class = MOD_CLASS_HT;729 pg->power_step = 0;730 pg->power_min = (s8) dbm_min;731 pg->power_max = (s8) dbm;732 pg->ht_bandwidth = HT_BW_40;733 }734 ret = mwifiex_send_cmd(priv, HostCmd_CMD_TXPWR_CFG,735 HostCmd_ACT_GEN_SET, 0, buf, true);736 737 kfree(buf);738 return ret;739}740 741/*742 * IOCTL request handler to get power save mode.743 *744 * This function prepares the correct firmware command and745 * issues it.746 */747int mwifiex_drv_set_power(struct mwifiex_private *priv, u32 *ps_mode)748{749 int ret;750 struct mwifiex_adapter *adapter = priv->adapter;751 u16 sub_cmd;752 753 if (*ps_mode)754 adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;755 else756 adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM;757 sub_cmd = (*ps_mode) ? EN_AUTO_PS : DIS_AUTO_PS;758 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,759 sub_cmd, BITMAP_STA_PS, NULL, true);760 if ((!ret) && (sub_cmd == DIS_AUTO_PS))761 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_PS_MODE_ENH,762 GET_PS, 0, NULL, false);763 764 return ret;765}766 767/*768 * IOCTL request handler to set/reset WPA IE.769 *770 * The supplied WPA IE is treated as a opaque buffer. Only the first field771 * is checked to determine WPA version. If buffer length is zero, the existing772 * WPA IE is reset.773 */774static int mwifiex_set_wpa_ie(struct mwifiex_private *priv,775 u8 *ie_data_ptr, u16 ie_len)776{777 if (ie_len) {778 if (ie_len > sizeof(priv->wpa_ie)) {779 mwifiex_dbg(priv->adapter, ERROR,780 "failed to copy WPA IE, too big\n");781 return -1;782 }783 memcpy(priv->wpa_ie, ie_data_ptr, ie_len);784 priv->wpa_ie_len = ie_len;785 mwifiex_dbg(priv->adapter, CMD,786 "cmd: Set Wpa_ie_len=%d IE=%#x\n",787 priv->wpa_ie_len, priv->wpa_ie[0]);788 789 if (priv->wpa_ie[0] == WLAN_EID_VENDOR_SPECIFIC) {790 priv->sec_info.wpa_enabled = true;791 } else if (priv->wpa_ie[0] == WLAN_EID_RSN) {792 priv->sec_info.wpa2_enabled = true;793 } else {794 priv->sec_info.wpa_enabled = false;795 priv->sec_info.wpa2_enabled = false;796 }797 } else {798 memset(priv->wpa_ie, 0, sizeof(priv->wpa_ie));799 priv->wpa_ie_len = 0;800 mwifiex_dbg(priv->adapter, INFO,801 "info: reset wpa_ie_len=%d IE=%#x\n",802 priv->wpa_ie_len, priv->wpa_ie[0]);803 priv->sec_info.wpa_enabled = false;804 priv->sec_info.wpa2_enabled = false;805 }806 807 return 0;808}809 810/*811 * IOCTL request handler to set/reset WAPI IE.812 *813 * The supplied WAPI IE is treated as a opaque buffer. Only the first field814 * is checked to internally enable WAPI. If buffer length is zero, the existing815 * WAPI IE is reset.816 */817static int mwifiex_set_wapi_ie(struct mwifiex_private *priv,818 u8 *ie_data_ptr, u16 ie_len)819{820 if (ie_len) {821 if (ie_len > sizeof(priv->wapi_ie)) {822 mwifiex_dbg(priv->adapter, ERROR,823 "info: failed to copy WAPI IE, too big\n");824 return -1;825 }826 memcpy(priv->wapi_ie, ie_data_ptr, ie_len);827 priv->wapi_ie_len = ie_len;828 mwifiex_dbg(priv->adapter, CMD,829 "cmd: Set wapi_ie_len=%d IE=%#x\n",830 priv->wapi_ie_len, priv->wapi_ie[0]);831 832 if (priv->wapi_ie[0] == WLAN_EID_BSS_AC_ACCESS_DELAY)833 priv->sec_info.wapi_enabled = true;834 } else {835 memset(priv->wapi_ie, 0, sizeof(priv->wapi_ie));836 priv->wapi_ie_len = ie_len;837 mwifiex_dbg(priv->adapter, INFO,838 "info: Reset wapi_ie_len=%d IE=%#x\n",839 priv->wapi_ie_len, priv->wapi_ie[0]);840 priv->sec_info.wapi_enabled = false;841 }842 return 0;843}844 845/*846 * IOCTL request handler to set/reset WPS IE.847 *848 * The supplied WPS IE is treated as a opaque buffer. Only the first field849 * is checked to internally enable WPS. If buffer length is zero, the existing850 * WPS IE is reset.851 */852static int mwifiex_set_wps_ie(struct mwifiex_private *priv,853 u8 *ie_data_ptr, u16 ie_len)854{855 if (ie_len) {856 if (ie_len > MWIFIEX_MAX_VSIE_LEN) {857 mwifiex_dbg(priv->adapter, ERROR,858 "info: failed to copy WPS IE, too big\n");859 return -1;860 }861 862 priv->wps_ie = kzalloc(MWIFIEX_MAX_VSIE_LEN, GFP_KERNEL);863 if (!priv->wps_ie)864 return -ENOMEM;865 866 memcpy(priv->wps_ie, ie_data_ptr, ie_len);867 priv->wps_ie_len = ie_len;868 mwifiex_dbg(priv->adapter, CMD,869 "cmd: Set wps_ie_len=%d IE=%#x\n",870 priv->wps_ie_len, priv->wps_ie[0]);871 } else {872 kfree(priv->wps_ie);873 priv->wps_ie_len = ie_len;874 mwifiex_dbg(priv->adapter, INFO,875 "info: Reset wps_ie_len=%d\n", priv->wps_ie_len);876 }877 return 0;878}879 880/*881 * IOCTL request handler to set WAPI key.882 *883 * This function prepares the correct firmware command and884 * issues it.885 */886static int mwifiex_sec_ioctl_set_wapi_key(struct mwifiex_private *priv,887 struct mwifiex_ds_encrypt_key *encrypt_key)888{889 890 return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,891 HostCmd_ACT_GEN_SET, KEY_INFO_ENABLED,892 encrypt_key, true);893}894 895/*896 * IOCTL request handler to set WEP network key.897 *898 * This function prepares the correct firmware command and899 * issues it, after validation checks.900 */901static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,902 struct mwifiex_ds_encrypt_key *encrypt_key)903{904 struct mwifiex_adapter *adapter = priv->adapter;905 int ret;906 struct mwifiex_wep_key *wep_key;907 int index;908 909 if (priv->wep_key_curr_index >= NUM_WEP_KEYS)910 priv->wep_key_curr_index = 0;911 wep_key = &priv->wep_key[priv->wep_key_curr_index];912 index = encrypt_key->key_index;913 if (encrypt_key->key_disable) {914 priv->sec_info.wep_enabled = 0;915 } else if (!encrypt_key->key_len) {916 /* Copy the required key as the current key */917 wep_key = &priv->wep_key[index];918 if (!wep_key->key_length) {919 mwifiex_dbg(adapter, ERROR,920 "key not set, so cannot enable it\n");921 return -1;922 }923 924 if (adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2) {925 memcpy(encrypt_key->key_material,926 wep_key->key_material, wep_key->key_length);927 encrypt_key->key_len = wep_key->key_length;928 }929 930 priv->wep_key_curr_index = (u16) index;931 priv->sec_info.wep_enabled = 1;932 } else {933 wep_key = &priv->wep_key[index];934 memset(wep_key, 0, sizeof(struct mwifiex_wep_key));935 /* Copy the key in the driver */936 memcpy(wep_key->key_material,937 encrypt_key->key_material,938 encrypt_key->key_len);939 wep_key->key_index = index;940 wep_key->key_length = encrypt_key->key_len;941 priv->sec_info.wep_enabled = 1;942 }943 if (wep_key->key_length) {944 void *enc_key;945 946 if (encrypt_key->key_disable) {947 memset(&priv->wep_key[index], 0,948 sizeof(struct mwifiex_wep_key));949 goto done;950 }951 952 if (adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2)953 enc_key = encrypt_key;954 else955 enc_key = NULL;956 957 /* Send request to firmware */958 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,959 HostCmd_ACT_GEN_SET, 0, enc_key, false);960 if (ret)961 return ret;962 }963 964done:965 if (priv->sec_info.wep_enabled)966 priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;967 else968 priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;969 970 ret = mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,971 HostCmd_ACT_GEN_SET, 0,972 &priv->curr_pkt_filter, true);973 974 return ret;975}976 977/*978 * IOCTL request handler to set WPA key.979 *980 * This function prepares the correct firmware command and981 * issues it, after validation checks.982 *983 * Current driver only supports key length of up to 32 bytes.984 *985 * This function can also be used to disable a currently set key.986 */987static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private *priv,988 struct mwifiex_ds_encrypt_key *encrypt_key)989{990 int ret;991 u8 remove_key = false;992 struct host_cmd_ds_802_11_key_material *ibss_key;993 994 /* Current driver only supports key length of up to 32 bytes */995 if (encrypt_key->key_len > WLAN_MAX_KEY_LEN) {996 mwifiex_dbg(priv->adapter, ERROR,997 "key length too long\n");998 return -1;999 }1000 1001 if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {1002 /*1003 * IBSS/WPA-None uses only one key (Group) for both receiving1004 * and sending unicast and multicast packets.1005 */1006 /* Send the key as PTK to firmware */1007 encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST;1008 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,1009 HostCmd_ACT_GEN_SET,1010 KEY_INFO_ENABLED, encrypt_key, false);1011 if (ret)1012 return ret;1013 1014 ibss_key = &priv->aes_key;1015 memset(ibss_key, 0,1016 sizeof(struct host_cmd_ds_802_11_key_material));1017 /* Copy the key in the driver */1018 memcpy(ibss_key->key_param_set.key, encrypt_key->key_material,1019 encrypt_key->key_len);1020 memcpy(&ibss_key->key_param_set.key_len, &encrypt_key->key_len,1021 sizeof(ibss_key->key_param_set.key_len));1022 ibss_key->key_param_set.key_type_id1023 = cpu_to_le16(KEY_TYPE_ID_TKIP);1024 ibss_key->key_param_set.key_info = cpu_to_le16(KEY_ENABLED);1025 1026 /* Send the key as GTK to firmware */1027 encrypt_key->key_index = ~MWIFIEX_KEY_INDEX_UNICAST;1028 }1029 1030 if (!encrypt_key->key_index)1031 encrypt_key->key_index = MWIFIEX_KEY_INDEX_UNICAST;1032 1033 if (remove_key)1034 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,1035 HostCmd_ACT_GEN_SET,1036 !KEY_INFO_ENABLED, encrypt_key, true);1037 else1038 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_KEY_MATERIAL,1039 HostCmd_ACT_GEN_SET,1040 KEY_INFO_ENABLED, encrypt_key, true);1041 1042 return ret;1043}1044 1045/*1046 * IOCTL request handler to set/get network keys.1047 *1048 * This is a generic key handling function which supports WEP, WPA1049 * and WAPI.1050 */1051static int1052mwifiex_sec_ioctl_encrypt_key(struct mwifiex_private *priv,1053 struct mwifiex_ds_encrypt_key *encrypt_key)1054{1055 int status;1056 1057 if (encrypt_key->is_wapi_key)1058 status = mwifiex_sec_ioctl_set_wapi_key(priv, encrypt_key);1059 else if (encrypt_key->key_len > WLAN_KEY_LEN_WEP104)1060 status = mwifiex_sec_ioctl_set_wpa_key(priv, encrypt_key);1061 else1062 status = mwifiex_sec_ioctl_set_wep_key(priv, encrypt_key);1063 return status;1064}1065 1066/*1067 * This function returns the driver version.1068 */1069int1070mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version,1071 int max_len)1072{1073 union {1074 __le32 l;1075 u8 c[4];1076 } ver;1077 char fw_ver[32];1078 1079 ver.l = cpu_to_le32(adapter->fw_release_number);1080 sprintf(fw_ver, "%u.%u.%u.p%u", ver.c[2], ver.c[1], ver.c[0], ver.c[3]);1081 1082 snprintf(version, max_len, driver_version, fw_ver);1083 1084 mwifiex_dbg(adapter, MSG, "info: MWIFIEX VERSION: %s\n", version);1085 1086 return 0;1087}1088 1089/*1090 * Sends IOCTL request to set encoding parameters.1091 *1092 * This function allocates the IOCTL request buffer, fills it1093 * with requisite parameters and calls the IOCTL handler.1094 */1095int mwifiex_set_encode(struct mwifiex_private *priv, struct key_params *kp,1096 const u8 *key, int key_len, u8 key_index,1097 const u8 *mac_addr, int disable)1098{1099 struct mwifiex_ds_encrypt_key encrypt_key;1100 1101 memset(&encrypt_key, 0, sizeof(encrypt_key));1102 encrypt_key.key_len = key_len;1103 encrypt_key.key_index = key_index;1104 1105 if (kp && kp->cipher == WLAN_CIPHER_SUITE_AES_CMAC)1106 encrypt_key.is_igtk_key = true;1107 1108 if (!disable) {1109 if (key_len)1110 memcpy(encrypt_key.key_material, key, key_len);1111 else1112 encrypt_key.is_current_wep_key = true;1113 1114 if (mac_addr)1115 memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN);1116 if (kp && kp->seq && kp->seq_len) {1117 memcpy(encrypt_key.pn, kp->seq, kp->seq_len);1118 encrypt_key.pn_len = kp->seq_len;1119 encrypt_key.is_rx_seq_valid = true;1120 }1121 } else {1122 encrypt_key.key_disable = true;1123 if (mac_addr)1124 memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN);1125 }1126 1127 return mwifiex_sec_ioctl_encrypt_key(priv, &encrypt_key);1128}1129 1130/*1131 * Sends IOCTL request to get extended version.1132 *1133 * This function allocates the IOCTL request buffer, fills it1134 * with requisite parameters and calls the IOCTL handler.1135 */1136int1137mwifiex_get_ver_ext(struct mwifiex_private *priv, u32 version_str_sel)1138{1139 struct mwifiex_ver_ext ver_ext;1140 1141 memset(&ver_ext, 0, sizeof(ver_ext));1142 ver_ext.version_str_sel = version_str_sel;1143 if (mwifiex_send_cmd(priv, HostCmd_CMD_VERSION_EXT,1144 HostCmd_ACT_GEN_GET, 0, &ver_ext, true))1145 return -1;1146 1147 return 0;1148}1149 1150int1151mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action,1152 struct ieee80211_channel *chan,1153 unsigned int duration)1154{1155 struct host_cmd_ds_remain_on_chan roc_cfg;1156 u8 sc;1157 1158 memset(&roc_cfg, 0, sizeof(roc_cfg));1159 roc_cfg.action = cpu_to_le16(action);1160 if (action == HostCmd_ACT_GEN_SET) {1161 roc_cfg.band_cfg = chan->band;1162 sc = mwifiex_chan_type_to_sec_chan_offset(NL80211_CHAN_NO_HT);1163 roc_cfg.band_cfg |= (sc << 2);1164 1165 roc_cfg.channel =1166 ieee80211_frequency_to_channel(chan->center_freq);1167 roc_cfg.duration = cpu_to_le32(duration);1168 }1169 if (mwifiex_send_cmd(priv, HostCmd_CMD_REMAIN_ON_CHAN,1170 action, 0, &roc_cfg, true)) {1171 mwifiex_dbg(priv->adapter, ERROR,1172 "failed to remain on channel\n");1173 return -1;1174 }1175 1176 return roc_cfg.status;1177}1178 1179/*1180 * Sends IOCTL request to get statistics information.1181 *1182 * This function allocates the IOCTL request buffer, fills it1183 * with requisite parameters and calls the IOCTL handler.1184 */1185int1186mwifiex_get_stats_info(struct mwifiex_private *priv,1187 struct mwifiex_ds_get_stats *log)1188{1189 return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_GET_LOG,1190 HostCmd_ACT_GEN_GET, 0, log, true);1191}1192 1193/*1194 * IOCTL request handler to read/write register.1195 *1196 * This function prepares the correct firmware command and1197 * issues it.1198 *1199 * Access to the following registers are supported -1200 * - MAC1201 * - BBP1202 * - RF1203 * - PMIC1204 * - CAU1205 */1206static int mwifiex_reg_mem_ioctl_reg_rw(struct mwifiex_private *priv,1207 struct mwifiex_ds_reg_rw *reg_rw,1208 u16 action)1209{1210 u16 cmd_no;1211 1212 switch (reg_rw->type) {1213 case MWIFIEX_REG_MAC:1214 cmd_no = HostCmd_CMD_MAC_REG_ACCESS;1215 break;1216 case MWIFIEX_REG_BBP:1217 cmd_no = HostCmd_CMD_BBP_REG_ACCESS;1218 break;1219 case MWIFIEX_REG_RF:1220 cmd_no = HostCmd_CMD_RF_REG_ACCESS;1221 break;1222 case MWIFIEX_REG_PMIC:1223 cmd_no = HostCmd_CMD_PMIC_REG_ACCESS;1224 break;1225 case MWIFIEX_REG_CAU:1226 cmd_no = HostCmd_CMD_CAU_REG_ACCESS;1227 break;1228 default:1229 return -1;1230 }1231 1232 return mwifiex_send_cmd(priv, cmd_no, action, 0, reg_rw, true);1233}1234 1235/*1236 * Sends IOCTL request to write to a register.1237 *1238 * This function allocates the IOCTL request buffer, fills it1239 * with requisite parameters and calls the IOCTL handler.1240 */1241int1242mwifiex_reg_write(struct mwifiex_private *priv, u32 reg_type,1243 u32 reg_offset, u32 reg_value)1244{1245 struct mwifiex_ds_reg_rw reg_rw;1246 1247 reg_rw.type = reg_type;1248 reg_rw.offset = reg_offset;1249 reg_rw.value = reg_value;1250 1251 return mwifiex_reg_mem_ioctl_reg_rw(priv, ®_rw, HostCmd_ACT_GEN_SET);1252}1253 1254/*1255 * Sends IOCTL request to read from a register.1256 *1257 * This function allocates the IOCTL request buffer, fills it1258 * with requisite parameters and calls the IOCTL handler.1259 */1260int1261mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type,1262 u32 reg_offset, u32 *value)1263{1264 int ret;1265 struct mwifiex_ds_reg_rw reg_rw;1266 1267 reg_rw.type = reg_type;1268 reg_rw.offset = reg_offset;1269 ret = mwifiex_reg_mem_ioctl_reg_rw(priv, ®_rw, HostCmd_ACT_GEN_GET);1270 1271 if (ret)1272 goto done;1273 1274 *value = reg_rw.value;1275 1276done:1277 return ret;1278}1279 1280/*1281 * Sends IOCTL request to read from EEPROM.1282 *1283 * This function allocates the IOCTL request buffer, fills it1284 * with requisite parameters and calls the IOCTL handler.1285 */1286int1287mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes,1288 u8 *value)1289{1290 int ret;1291 struct mwifiex_ds_read_eeprom rd_eeprom;1292 1293 rd_eeprom.offset = offset;1294 rd_eeprom.byte_count = bytes;1295 1296 /* Send request to firmware */1297 ret = mwifiex_send_cmd(priv, HostCmd_CMD_802_11_EEPROM_ACCESS,1298 HostCmd_ACT_GEN_GET, 0, &rd_eeprom, true);1299 1300 if (!ret)1301 memcpy(value, rd_eeprom.value, min((u16)MAX_EEPROM_DATA,1302 rd_eeprom.byte_count));1303 return ret;1304}1305 1306/*1307 * This function sets a generic IE. In addition to generic IE, it can1308 * also handle WPA, WPA2 and WAPI IEs.1309 */1310static int1311mwifiex_set_gen_ie_helper(struct mwifiex_private *priv, u8 *ie_data_ptr,1312 u16 ie_len)1313{1314 struct ieee_types_vendor_header *pvendor_ie;1315 static const u8 wpa_oui[] = { 0x00, 0x50, 0xf2, 0x01 };1316 static const u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 };1317 u16 unparsed_len = ie_len, cur_ie_len;1318 1319 /* If the passed length is zero, reset the buffer */1320 if (!ie_len) {1321 priv->gen_ie_buf_len = 0;1322 priv->wps.session_enable = false;1323 return 0;1324 } else if (!ie_data_ptr ||1325 ie_len <= sizeof(struct ieee_types_header)) {1326 return -1;1327 }1328 pvendor_ie = (struct ieee_types_vendor_header *) ie_data_ptr;1329 1330 while (pvendor_ie) {1331 cur_ie_len = pvendor_ie->len + sizeof(struct ieee_types_header);1332 1333 if (pvendor_ie->element_id == WLAN_EID_RSN) {1334 /* IE is a WPA/WPA2 IE so call set_wpa function */1335 mwifiex_set_wpa_ie(priv, (u8 *)pvendor_ie, cur_ie_len);1336 priv->wps.session_enable = false;1337 goto next_ie;1338 }1339 1340 if (pvendor_ie->element_id == WLAN_EID_BSS_AC_ACCESS_DELAY) {1341 /* IE is a WAPI IE so call set_wapi function */1342 mwifiex_set_wapi_ie(priv, (u8 *)pvendor_ie,1343 cur_ie_len);1344 goto next_ie;1345 }1346 1347 if (pvendor_ie->element_id == WLAN_EID_VENDOR_SPECIFIC) {1348 /* Test to see if it is a WPA IE, if not, then1349 * it is a gen IE1350 */1351 if (!memcmp(&pvendor_ie->oui, wpa_oui,1352 sizeof(wpa_oui))) {1353 /* IE is a WPA/WPA2 IE so call set_wpa function1354 */1355 mwifiex_set_wpa_ie(priv, (u8 *)pvendor_ie,1356 cur_ie_len);1357 priv->wps.session_enable = false;1358 goto next_ie;1359 }1360 1361 if (!memcmp(&pvendor_ie->oui, wps_oui,1362 sizeof(wps_oui))) {1363 /* Test to see if it is a WPS IE,1364 * if so, enable wps session flag1365 */1366 priv->wps.session_enable = true;1367 mwifiex_dbg(priv->adapter, MSG,1368 "WPS Session Enabled.\n");1369 mwifiex_set_wps_ie(priv, (u8 *)pvendor_ie,1370 cur_ie_len);1371 goto next_ie;1372 }1373 }1374 1375 /* Saved in gen_ie, such as P2P IE.etc.*/1376 1377 /* Verify that the passed length is not larger than the1378 * available space remaining in the buffer1379 */1380 if (cur_ie_len <1381 (sizeof(priv->gen_ie_buf) - priv->gen_ie_buf_len)) {1382 /* Append the passed data to the end1383 * of the genIeBuffer1384 */1385 memcpy(priv->gen_ie_buf + priv->gen_ie_buf_len,1386 (u8 *)pvendor_ie, cur_ie_len);1387 /* Increment the stored buffer length by the1388 * size passed1389 */1390 priv->gen_ie_buf_len += cur_ie_len;1391 }1392 1393next_ie:1394 unparsed_len -= cur_ie_len;1395 1396 if (unparsed_len <= sizeof(struct ieee_types_header))1397 pvendor_ie = NULL;1398 else1399 pvendor_ie = (struct ieee_types_vendor_header *)1400 (((u8 *)pvendor_ie) + cur_ie_len);1401 }1402 1403 return 0;1404}1405 1406/*1407 * IOCTL request handler to set/get generic IE.1408 *1409 * In addition to various generic IEs, this function can also be1410 * used to set the ARP filter.1411 */1412static int mwifiex_misc_ioctl_gen_ie(struct mwifiex_private *priv,1413 struct mwifiex_ds_misc_gen_ie *gen_ie,1414 u16 action)1415{1416 struct mwifiex_adapter *adapter = priv->adapter;1417 1418 switch (gen_ie->type) {1419 case MWIFIEX_IE_TYPE_GEN_IE:1420 if (action == HostCmd_ACT_GEN_GET) {1421 gen_ie->len = priv->wpa_ie_len;1422 memcpy(gen_ie->ie_data, priv->wpa_ie, gen_ie->len);1423 } else {1424 mwifiex_set_gen_ie_helper(priv, gen_ie->ie_data,1425 (u16) gen_ie->len);1426 }1427 break;1428 case MWIFIEX_IE_TYPE_ARP_FILTER:1429 memset(adapter->arp_filter, 0, sizeof(adapter->arp_filter));1430 if (gen_ie->len > ARP_FILTER_MAX_BUF_SIZE) {1431 adapter->arp_filter_size = 0;1432 mwifiex_dbg(adapter, ERROR,1433 "invalid ARP filter size\n");1434 return -1;1435 } else {1436 memcpy(adapter->arp_filter, gen_ie->ie_data,1437 gen_ie->len);1438 adapter->arp_filter_size = gen_ie->len;1439 }1440 break;1441 default:1442 mwifiex_dbg(adapter, ERROR, "invalid IE type\n");1443 return -1;1444 }1445 return 0;1446}1447 1448/*1449 * Sends IOCTL request to set a generic IE.1450 *1451 * This function allocates the IOCTL request buffer, fills it1452 * with requisite parameters and calls the IOCTL handler.1453 */1454int1455mwifiex_set_gen_ie(struct mwifiex_private *priv, const u8 *ie, int ie_len)1456{1457 struct mwifiex_ds_misc_gen_ie gen_ie;1458 1459 if (ie_len > IEEE_MAX_IE_SIZE)1460 return -EFAULT;1461 1462 gen_ie.type = MWIFIEX_IE_TYPE_GEN_IE;1463 gen_ie.len = ie_len;1464 memcpy(gen_ie.ie_data, ie, ie_len);1465 if (mwifiex_misc_ioctl_gen_ie(priv, &gen_ie, HostCmd_ACT_GEN_SET))1466 return -EFAULT;1467 1468 return 0;1469}1470 1471/* This function get Host Sleep wake up reason.1472 *1473 */1474int mwifiex_get_wakeup_reason(struct mwifiex_private *priv, u16 action,1475 int cmd_type,1476 struct mwifiex_ds_wakeup_reason *wakeup_reason)1477{1478 int status = 0;1479 1480 status = mwifiex_send_cmd(priv, HostCmd_CMD_HS_WAKEUP_REASON,1481 HostCmd_ACT_GEN_GET, 0, wakeup_reason,1482 cmd_type == MWIFIEX_SYNC_CMD);1483 1484 return status;1485}1486 1487int mwifiex_get_chan_info(struct mwifiex_private *priv,1488 struct mwifiex_channel_band *channel_band)1489{1490 int status = 0;1491 1492 status = mwifiex_send_cmd(priv, HostCmd_CMD_STA_CONFIGURE,1493 HostCmd_ACT_GEN_GET, 0, channel_band,1494 MWIFIEX_SYNC_CMD);1495 1496 return status;1497}1498