From b5c77922776bc0d3cd5cb31c0794406638841013 Mon Sep 17 00:00:00 2001 From: Mohan T Date: Thu, 26 Apr 2012 10:53:57 +0530 Subject: net: wireless: sd8797: Marvell sd8797 Wi-Fi driver Initial commit for Marvell sd8797 Wi-Fi driver Package Ver: T3T-14.69.11.p111-M2614303_A0B0-MGPL Bug 954218 Change-Id: I76fcadb5cda054d1e489c4cff77a3c461bdac742 Signed-off-by: Mohan T Reviewed-on: http://git-master/r/97305 Reviewed-by: Bharat Nihalani --- drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c | 1263 ++++ drivers/net/wireless/sd8797/mlinux/moal_cfg80211.h | 195 + drivers/net/wireless/sd8797/mlinux/moal_debug.c | 674 ++ .../net/wireless/sd8797/mlinux/moal_eth_ioctl.c | 1143 ++++ .../net/wireless/sd8797/mlinux/moal_eth_ioctl.h | 69 + drivers/net/wireless/sd8797/mlinux/moal_ioctl.c | 4307 +++++++++++++ drivers/net/wireless/sd8797/mlinux/moal_main.c | 3773 +++++++++++ drivers/net/wireless/sd8797/mlinux/moal_main.h | 1510 +++++ drivers/net/wireless/sd8797/mlinux/moal_priv.c | 6596 ++++++++++++++++++++ drivers/net/wireless/sd8797/mlinux/moal_priv.h | 715 +++ drivers/net/wireless/sd8797/mlinux/moal_proc.c | 631 ++ drivers/net/wireless/sd8797/mlinux/moal_sdio.h | 140 + drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c | 728 +++ drivers/net/wireless/sd8797/mlinux/moal_shim.c | 1458 +++++ drivers/net/wireless/sd8797/mlinux/moal_shim.h | 95 + .../net/wireless/sd8797/mlinux/moal_sta_cfg80211.c | 2476 ++++++++ .../net/wireless/sd8797/mlinux/moal_sta_cfg80211.h | 41 + drivers/net/wireless/sd8797/mlinux/moal_uap.c | 2692 ++++++++ drivers/net/wireless/sd8797/mlinux/moal_uap.h | 410 ++ .../net/wireless/sd8797/mlinux/moal_uap_cfg80211.c | 1762 ++++++ .../net/wireless/sd8797/mlinux/moal_uap_cfg80211.h | 30 + drivers/net/wireless/sd8797/mlinux/moal_uap_priv.c | 175 + drivers/net/wireless/sd8797/mlinux/moal_uap_priv.h | 194 + drivers/net/wireless/sd8797/mlinux/moal_uap_wext.c | 1766 ++++++ drivers/net/wireless/sd8797/mlinux/moal_wext.c | 3048 +++++++++ drivers/net/wireless/sd8797/mlinux/moal_wext.h | 116 + 26 files changed, 36007 insertions(+) create mode 100644 drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c create mode 100644 drivers/net/wireless/sd8797/mlinux/moal_cfg80211.h create mode 100644 drivers/net/wireless/sd8797/mlinux/moal_debug.c create mode 100644 drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c create mode 100644 drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.h create mode 100644 drivers/net/wireless/sd8797/mlinux/moal_ioctl.c create mode 100644 drivers/net/wireless/sd8797/mlinux/moal_main.c create mode 100644 drivers/net/wireless/sd8797/mlinux/moal_main.h create mode 100644 drivers/net/wireless/sd8797/mlinux/moal_priv.c create mode 100644 drivers/net/wireless/sd8797/mlinux/moal_priv.h create mode 100644 drivers/net/wireless/sd8797/mlinux/moal_proc.c create mode 100644 drivers/net/wireless/sd8797/mlinux/moal_sdio.h create mode 100644 drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c create mode 100644 drivers/net/wireless/sd8797/mlinux/moal_shim.c create mode 100644 drivers/net/wireless/sd8797/mlinux/moal_shim.h create mode 100644 drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c create mode 100644 drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.h create mode 100644 drivers/net/wireless/sd8797/mlinux/moal_uap.c create mode 100644 drivers/net/wireless/sd8797/mlinux/moal_uap.h create mode 100644 drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.c create mode 100644 drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.h create mode 100644 drivers/net/wireless/sd8797/mlinux/moal_uap_priv.c create mode 100644 drivers/net/wireless/sd8797/mlinux/moal_uap_priv.h create mode 100644 drivers/net/wireless/sd8797/mlinux/moal_uap_wext.c create mode 100644 drivers/net/wireless/sd8797/mlinux/moal_wext.c create mode 100644 drivers/net/wireless/sd8797/mlinux/moal_wext.h (limited to 'drivers/net/wireless/sd8797/mlinux') diff --git a/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c b/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c new file mode 100644 index 000000000000..942fae4e991d --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c @@ -0,0 +1,1263 @@ +/** @file moal_cfg80211.c + * + * @brief This file contains the functions for CFG80211. + * + * Copyright (C) 2011-2012, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +#include "moal_cfg80211.h" +#ifdef UAP_CFG80211 +#ifdef UAP_SUPPORT +#include "moal_uap.h" +#endif +#endif + +/******************************************************** + Local Variables +********************************************************/ +/** Supported rates to be advertised to the cfg80211 */ +static struct ieee80211_rate cfg80211_rates[] = { + {.bitrate = 10,.hw_value = 2,}, + {.bitrate = 20,.hw_value = 4,}, + {.bitrate = 55,.hw_value = 11}, + {.bitrate = 110,.hw_value = 22,}, + {.bitrate = 220,.hw_value = 44,}, + {.bitrate = 60,.hw_value = 12,}, + {.bitrate = 90,.hw_value = 18,}, + {.bitrate = 120,.hw_value = 24,}, + {.bitrate = 180,.hw_value = 36,}, + {.bitrate = 240,.hw_value = 48,}, + {.bitrate = 360,.hw_value = 72,}, + {.bitrate = 480,.hw_value = 96,}, + {.bitrate = 540,.hw_value = 108,}, + {.bitrate = 720,.hw_value = 144,}, +}; + +/** Channel definitions for 2 GHz to be advertised to cfg80211 */ +static struct ieee80211_channel cfg80211_channels_2ghz[] = { + {.center_freq = 2412,.hw_value = 1,.max_power = 20}, + {.center_freq = 2417,.hw_value = 2,.max_power = 20}, + {.center_freq = 2422,.hw_value = 3,.max_power = 20}, + {.center_freq = 2427,.hw_value = 4,.max_power = 20}, + {.center_freq = 2432,.hw_value = 5,.max_power = 20}, + {.center_freq = 2437,.hw_value = 6,.max_power = 20}, + {.center_freq = 2442,.hw_value = 7,.max_power = 20}, + {.center_freq = 2447,.hw_value = 8,.max_power = 20}, + {.center_freq = 2452,.hw_value = 9,.max_power = 20}, + {.center_freq = 2457,.hw_value = 10,.max_power = 20}, + {.center_freq = 2462,.hw_value = 11,.max_power = 20}, + {.center_freq = 2467,.hw_value = 12,.max_power = 20}, + {.center_freq = 2472,.hw_value = 13,.max_power = 20}, + {.center_freq = 2484,.hw_value = 14,.max_power = 20}, +}; + +/** Channel definitions for 5 GHz to be advertised to cfg80211 */ +static struct ieee80211_channel cfg80211_channels_5ghz[] = { + {.center_freq = 5040,.hw_value = 8,.max_power = 20}, + {.center_freq = 5060,.hw_value = 12,.max_power = 20}, + {.center_freq = 5080,.hw_value = 16,.max_power = 20}, + {.center_freq = 5170,.hw_value = 34,.max_power = 20}, + {.center_freq = 5190,.hw_value = 38,.max_power = 20}, + {.center_freq = 5210,.hw_value = 42,.max_power = 20}, + {.center_freq = 5230,.hw_value = 46,.max_power = 20}, + {.center_freq = 5180,.hw_value = 36,.max_power = 20}, + {.center_freq = 5200,.hw_value = 40,.max_power = 20}, + {.center_freq = 5220,.hw_value = 44,.max_power = 20}, + {.center_freq = 5240,.hw_value = 48,.max_power = 20}, + {.center_freq = 5260,.hw_value = 52,.max_power = 20}, + {.center_freq = 5280,.hw_value = 56,.max_power = 20}, + {.center_freq = 5300,.hw_value = 60,.max_power = 20}, + {.center_freq = 5320,.hw_value = 64,.max_power = 20}, + {.center_freq = 5500,.hw_value = 100,.max_power = 20}, + {.center_freq = 5520,.hw_value = 104,.max_power = 20}, + {.center_freq = 5540,.hw_value = 108,.max_power = 20}, + {.center_freq = 5560,.hw_value = 112,.max_power = 20}, + {.center_freq = 5580,.hw_value = 116,.max_power = 20}, + {.center_freq = 5600,.hw_value = 120,.max_power = 20}, + {.center_freq = 5620,.hw_value = 124,.max_power = 20}, + {.center_freq = 5640,.hw_value = 128,.max_power = 20}, + {.center_freq = 5660,.hw_value = 132,.max_power = 20}, + {.center_freq = 5680,.hw_value = 136,.max_power = 20}, + {.center_freq = 5700,.hw_value = 140,.max_power = 20}, + {.center_freq = 5745,.hw_value = 149,.max_power = 20}, + {.center_freq = 5765,.hw_value = 153,.max_power = 20}, + {.center_freq = 5785,.hw_value = 157,.max_power = 20}, + {.center_freq = 5805,.hw_value = 161,.max_power = 20}, + {.center_freq = 5825,.hw_value = 165,.max_power = 20}, +}; + +/******************************************************** + Global Variables +********************************************************/ +extern int cfg80211_wext; + +struct ieee80211_supported_band cfg80211_band_2ghz = { + .channels = cfg80211_channels_2ghz, + .n_channels = ARRAY_SIZE(cfg80211_channels_2ghz), + .bitrates = cfg80211_rates, + .n_bitrates = ARRAY_SIZE(cfg80211_rates), +}; + +struct ieee80211_supported_band cfg80211_band_5ghz = { + .channels = cfg80211_channels_5ghz, + .n_channels = ARRAY_SIZE(cfg80211_channels_5ghz), + .bitrates = cfg80211_rates + 5, + .n_bitrates = ARRAY_SIZE(cfg80211_rates) - 5, +}; + +#ifndef WLAN_CIPHER_SUITE_SMS4 +#define WLAN_CIPHER_SUITE_SMS4 0x00000020 +#endif + +/* Supported crypto cipher suits to be advertised to cfg80211 */ +const u32 cfg80211_cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, + WLAN_CIPHER_SUITE_CCMP, + WLAN_CIPHER_SUITE_SMS4, +}; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) +#ifdef UAP_SUPPORT +/** Network device handlers for uAP */ +extern const struct net_device_ops woal_uap_netdev_ops; +#endif +#ifdef STA_SUPPORT +/** Network device handlers for STA */ +extern const struct net_device_ops woal_netdev_ops; +#endif +#endif + +/******************************************************** + Local Functions +********************************************************/ + +/******************************************************** + Global Functions +********************************************************/ +/** + * @brief Get the private structure from wiphy + * + * @param wiphy A pointer to wiphy structure + * + * @return Pointer to moal_private + */ +void * +woal_get_wiphy_priv(struct wiphy *wiphy) +{ + return (void *) (*(unsigned long *) wiphy_priv(wiphy)); +} + +/** + * @brief Set/Enable encryption key + * + * @param priv A pointer to moal_private structure + * @param is_enable_wep Enable WEP default key + * @param cipher Cipher suite selector + * @param key A pointer to key + * @param key_len Key length + * @param seq A pointer to sequence + * @param seq_len Sequence length + * @param key_index Key index + * @param addr Mac for which key is to be set + * @param disable Key disabled or not + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + */ +mlan_status +woal_cfg80211_set_key(moal_private * priv, t_u8 is_enable_wep, + t_u32 cipher, const t_u8 * key, int key_len, + const t_u8 * seq, int seq_len, t_u8 key_index, + const t_u8 * addr, int disable) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_sec_cfg *sec = NULL; + mlan_status ret = MLAN_STATUS_SUCCESS; + t_u8 bcast_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg)); + if (req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill request buffer */ + sec = (mlan_ds_sec_cfg *) req->pbuf; + sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY; + req->req_id = MLAN_IOCTL_SEC_CFG; + req->action = MLAN_ACT_SET; + + if (is_enable_wep) { + sec->param.encrypt_key.key_index = key_index; + sec->param.encrypt_key.is_current_wep_key = MTRUE; + } else if (!disable) { +#ifdef UAP_CFG80211 +#ifdef UAP_SUPPORT + if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) { + if (key && key_len) { + priv->key_len = key_len; + memcpy(priv->key_material, key, key_len); + priv->cipher = cipher; + priv->key_index = key_index; + } + if ((cipher == WLAN_CIPHER_SUITE_WEP40) || + (cipher == WLAN_CIPHER_SUITE_WEP104)) { + PRINTM(MIOCTL, "Set WEP key\n"); + ret = MLAN_STATUS_SUCCESS; + goto done; + } + } +#endif +#endif + if (cipher != WLAN_CIPHER_SUITE_WEP40 && + cipher != WLAN_CIPHER_SUITE_WEP104 && + cipher != WLAN_CIPHER_SUITE_TKIP && + cipher != WLAN_CIPHER_SUITE_SMS4 && + cipher != WLAN_CIPHER_SUITE_CCMP) { + PRINTM(MERROR, "Invalid cipher suite specified\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + sec->param.encrypt_key.key_index = key_index; + if (key && key_len) { + memcpy(sec->param.encrypt_key.key_material, key, key_len); + sec->param.encrypt_key.key_len = key_len; + } + /* Set WAPI key */ + if (cipher == WLAN_CIPHER_SUITE_SMS4) { + sec->param.encrypt_key.is_wapi_key = MTRUE; + if (seq_len) { + memcpy(sec->param.encrypt_key.pn, seq, PN_SIZE); + DBG_HEXDUMP(MCMD_D, "WAPI PN", sec->param.encrypt_key.pn, + seq_len); + } + } + if (cipher != WLAN_CIPHER_SUITE_WEP40 && + cipher != WLAN_CIPHER_SUITE_WEP104) { + if (addr) { + memcpy(sec->param.encrypt_key.mac_addr, addr, ETH_ALEN); + if (0 == + memcmp(sec->param.encrypt_key.mac_addr, bcast_addr, + ETH_ALEN)) + sec->param.encrypt_key.key_flags = KEY_FLAG_GROUP_KEY; + else + sec->param.encrypt_key.key_flags = KEY_FLAG_SET_TX_KEY; + } else { + memcpy(sec->param.encrypt_key.mac_addr, bcast_addr, ETH_ALEN); + sec->param.encrypt_key.key_flags = KEY_FLAG_GROUP_KEY; + } + if (seq && seq_len) { + memcpy(sec->param.encrypt_key.pn, seq, seq_len); + sec->param.encrypt_key.key_flags |= KEY_FLAG_RX_SEQ_VALID; + } + } + } else { + sec->param.encrypt_key.key_remove = MTRUE; + sec->param.encrypt_key.key_index = key_index; + sec->param.encrypt_key.key_flags = KEY_FLAG_REMOVE_KEY; + if (addr) + memcpy(sec->param.encrypt_key.mac_addr, addr, ETH_ALEN); + } + + /* Send IOCTL request to MLAN */ + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + done: + if (req && (ret != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Set/Enable the WEP key to driver + * + * @param priv A pointer to moal_private structure + * @param key A pointer to key data + * @param key_len Length of the key data + * @param index Key index + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +woal_cfg80211_set_wep_keys(moal_private * priv, const t_u8 * key, int key_len, + t_u8 index) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + t_u32 cipher = 0; + + ENTER(); + + if (key_len) { + if (key_len == 5) + cipher = WLAN_CIPHER_SUITE_WEP40; + else + cipher = WLAN_CIPHER_SUITE_WEP104; + ret = + woal_cfg80211_set_key(priv, 0, cipher, key, key_len, NULL, 0, index, + NULL, 0); + } else { + /* No key provided so it is enable key. We want to just set the + transmit key index */ + woal_cfg80211_set_key(priv, 1, cipher, key, key_len, NULL, 0, index, + NULL, 0); + } + + LEAVE(); + return ret; +} + +#if defined(WIFI_DIRECT_SUPPORT) +#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION +/** + * @brief set bss role + * + * @param priv A pointer to moal private structure + * @param action Action: set or get + * @param role A pointer to bss role + * + * @return 0 -- success, otherwise fail + */ +static int +woal_cfg80211_bss_role_cfg(moal_private * priv, t_u16 action, t_u8 * bss_role) +{ + int ret = 0; + mlan_ds_bss *bss = NULL; + mlan_ioctl_req *req = NULL; + struct net_device *dev = priv->netdev; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + bss = (mlan_ds_bss *) req->pbuf; + bss->sub_command = MLAN_OID_BSS_ROLE; + req->req_id = MLAN_IOCTL_BSS; + req->action = action; + bss->param.bss_role = *bss_role; + + if (req->action == MLAN_ACT_SET) { + /* Reset interface */ + woal_reset_intf(priv, MOAL_IOCTL_WAIT, MFALSE); + } + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + if (req->action == MLAN_ACT_GET) { + *bss_role = bss->param.bss_role; + } else { + /* Update moal_private */ + priv->bss_role = *bss_role; + if (priv->bss_type == MLAN_BSS_TYPE_UAP) + priv->bss_type = MLAN_BSS_TYPE_STA; + else if (priv->bss_type == MLAN_BSS_TYPE_STA) + priv->bss_type = MLAN_BSS_TYPE_UAP; + + /* Initialize private structures */ + woal_init_priv(priv, MOAL_IOCTL_WAIT); + + if (*bss_role == MLAN_BSS_ROLE_UAP) { + /* Switch: STA -> uAP */ + /* Setup the OS Interface to our functions */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) + dev->do_ioctl = woal_uap_do_ioctl; + dev->set_multicast_list = woal_uap_set_multicast_list; +#else + dev->netdev_ops = &woal_uap_netdev_ops; +#endif +#ifdef WIRELESS_EXT +#ifdef UAP_WEXT + if (IS_UAP_WEXT(cfg80211_wext)) { +#if WIRELESS_EXT < 21 + dev->get_wireless_stats = woal_get_uap_wireless_stats; +#endif + dev->wireless_handlers = + (struct iw_handler_def *) &woal_uap_handler_def; + init_waitqueue_head(&priv->w_stats_wait_q); + } +#endif /* UAP_WEXT */ +#endif /* WIRELESS_EXT */ + } else if (*bss_role == MLAN_BSS_ROLE_STA) { + /* Switch: uAP -> STA */ + /* Setup the OS Interface to our functions */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) + dev->do_ioctl = woal_do_ioctl; + dev->set_multicast_list = woal_set_multicast_list; +#else + dev->netdev_ops = &woal_netdev_ops; +#endif +#ifdef WIRELESS_EXT +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) { +#if WIRELESS_EXT < 21 + dev->get_wireless_stats = woal_get_wireless_stats; +#endif + dev->wireless_handlers = + (struct iw_handler_def *) &woal_handler_def; + init_waitqueue_head(&priv->w_stats_wait_q); + } +#endif /* STA_WEXT */ +#endif + } + /* Enable interfaces */ + netif_device_attach(dev); + woal_start_queue(dev); + } + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief initialize p2p client for wpa_supplicant + * + * @param priv A pointer to moal private structure + * + * @return 0 -- success, otherwise fail + */ +int +woal_cfg80211_init_p2p_client(moal_private * priv) +{ + int ret = MLAN_STATUS_SUCCESS; + t_u16 wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE; + t_u8 bss_role; + + ENTER(); + + /* bss type check */ + if (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) { + PRINTM(MERROR, "Unexpected bss type when init p2p client\n"); + ret = -EFAULT; + goto done; + } + + /* get the bss role */ + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_GET, &bss_role)) { + ret = -EFAULT; + goto done; + } + + if (bss_role != MLAN_BSS_ROLE_STA) { + bss_role = MLAN_BSS_ROLE_STA; + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_SET, &bss_role)) { + ret = -EFAULT; + goto done; + } + } + + wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE; + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_wifi_direct_mode_cfg(priv, + MLAN_ACT_SET, &wifi_direct_mode)) { + ret = -EFAULT; + goto done; + } + + /* first, init wifi direct to listen mode */ + wifi_direct_mode = WIFI_DIRECT_MODE_LISTEN; + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, + &wifi_direct_mode)) { + ret = -EFAULT; + goto done; + } + + /* second, init wifi direct client */ + wifi_direct_mode = WIFI_DIRECT_MODE_CLIENT; + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_wifi_direct_mode_cfg(priv, + MLAN_ACT_SET, &wifi_direct_mode)) { + ret = -EFAULT; + goto done; + } + done: + LEAVE(); + return ret; +} + +/** + * @brief initialize p2p GO for wpa_supplicant + * + * @param priv A pointer to moal private structure + * + * @return 0 -- success, otherwise fail + */ +int +woal_cfg80211_init_p2p_go(moal_private * priv) +{ + int ret = MLAN_STATUS_SUCCESS; + t_u16 wifi_direct_mode; + t_u8 bss_role; + + ENTER(); + + /* bss type check */ + if (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) { + PRINTM(MERROR, "Unexpected bss type when init p2p GO\n"); + ret = -EFAULT; + goto done; + } + + wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE; + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_wifi_direct_mode_cfg(priv, + MLAN_ACT_SET, &wifi_direct_mode)) { + ret = -EFAULT; + goto done; + } + + /* first, init wifi direct to listen mode */ + wifi_direct_mode = WIFI_DIRECT_MODE_LISTEN; + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, + &wifi_direct_mode)) { + ret = -EFAULT; + goto done; + } + + /* second, init wifi direct to GO mode */ + wifi_direct_mode = WIFI_DIRECT_MODE_GO; + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_wifi_direct_mode_cfg(priv, + MLAN_ACT_SET, &wifi_direct_mode)) { + ret = -EFAULT; + goto done; + } + + /* get the bss role, and set it to uAP */ + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_GET, &bss_role)) { + ret = -EFAULT; + goto done; + } + + if (bss_role != MLAN_BSS_ROLE_UAP) { + bss_role = MLAN_BSS_ROLE_UAP; + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_SET, &bss_role)) { + ret = -EFAULT; + goto done; + } + } + + done: + LEAVE(); + return ret; +} + +/** + * @brief reset bss role and wifi direct mode for wpa_supplicant + * + * @param priv A pointer to moal private structure + * + * @return 0 -- success, otherwise fail + */ +int +woal_cfg80211_deinit_p2p(moal_private * priv) +{ + int ret = MLAN_STATUS_SUCCESS; + t_u16 wifi_direct_mode; + t_u8 bss_role; + t_u8 channel_status; + + ENTER(); + + /* bss type check */ + if (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) { + PRINTM(MERROR, "Unexpected bss type when deinit p2p\n"); + ret = -EFAULT; + goto done; + } + + /* cancel previous remain on channel */ + if (priv->phandle->remain_on_channel) { + if (woal_cfg80211_remain_on_channel_cfg + (priv->wdev->wiphy, MOAL_IOCTL_WAIT, MTRUE, &channel_status, NULL, + 0, 0)) { + PRINTM(MERROR, "Fail to cancel remain on channel\n"); + ret = -EFAULT; + goto done; + } + if (priv->phandle->cookie) { + cfg80211_remain_on_channel_expired(priv->netdev, + priv->phandle->cookie, + &priv->phandle->chan, + priv->phandle->channel_type, + GFP_ATOMIC); + priv->phandle->cookie = 0; + } + priv->phandle->remain_on_channel = MFALSE; + } + + /* get the bss role */ + if (MLAN_STATUS_SUCCESS != woal_cfg80211_bss_role_cfg(priv, + MLAN_ACT_GET, + &bss_role)) { + ret = -EFAULT; + goto done; + } + + /* reset bss role */ + if (bss_role != MLAN_BSS_ROLE_STA) { + bss_role = MLAN_BSS_ROLE_STA; + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_bss_role_cfg(priv, MLAN_ACT_SET, &bss_role)) { + ret = -EFAULT; + goto done; + } + } + + wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE; + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_wifi_direct_mode_cfg(priv, + MLAN_ACT_SET, &wifi_direct_mode)) { + ret = -EFAULT; + goto done; + } + done: + LEAVE(); + return ret; +} +#endif /* KERNEL_VERSION */ +#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */ + +/** + * @brief Request the driver to change the interface type + * + * @param wiphy A pointer to wiphy structure + * @param dev A pointer to net_device structure + * @param type Virtual interface types + * @param flags Flags + * @param params A pointer to vif_params structure + * + * @return 0 -- success, otherwise fail + */ +int +woal_cfg80211_change_virtual_intf(struct wiphy *wiphy, + struct net_device *dev, + enum nl80211_iftype type, u32 * flags, + struct vif_params *params) +{ + int ret = 0; + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + mlan_ds_bss *bss = NULL; + mlan_ioctl_req *req = NULL; + + ENTER(); + + if (priv->wdev->iftype == type) { + PRINTM(MINFO, "Already set to required type\n"); + goto done; + } + PRINTM(MIOCTL, "change virturl intf=%d\n", type); +#if defined(WIFI_DIRECT_SUPPORT) +#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION + /** cancel previous remain on channel to avoid firmware hang */ + if (priv->phandle->remain_on_channel) { + t_u8 channel_status; + if (woal_cfg80211_remain_on_channel_cfg + (wiphy, MOAL_IOCTL_WAIT, MTRUE, &channel_status, NULL, 0, 0)) { + PRINTM(MERROR, "Fail to cancel remain on channel\n"); + ret = -EFAULT; + goto done; + } + if (priv->phandle->cookie) { + cfg80211_remain_on_channel_expired(priv->netdev, + priv->phandle->cookie, + &priv->phandle->chan, + priv->phandle->channel_type, + GFP_ATOMIC); + priv->phandle->cookie = 0; + } + priv->phandle->remain_on_channel = MFALSE; + } +#endif +#endif + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + bss = (mlan_ds_bss *) req->pbuf; + bss->sub_command = MLAN_OID_BSS_MODE; + req->req_id = MLAN_IOCTL_BSS; + req->action = MLAN_ACT_SET; + + switch (type) { + case NL80211_IFTYPE_ADHOC: + bss->param.bss_mode = MLAN_BSS_MODE_IBSS; + priv->wdev->iftype = NL80211_IFTYPE_ADHOC; + PRINTM(MINFO, "Setting interface type to adhoc\n"); + break; + case NL80211_IFTYPE_STATION: +#if defined(WIFI_DIRECT_SUPPORT) +#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION + if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT + && (priv->wdev->iftype == NL80211_IFTYPE_AP + || priv->wdev->iftype == NL80211_IFTYPE_P2P_GO + || priv->wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) { + /* if we support wifi direct && priv->bss_type == wifi_direct, and + currently the interface type is AP or GO or client, that means + wpa_supplicant deinit() wifi direct interface, so we should + deinit bss_role and wifi direct mode, for other bss_type, we + should not update bss_role and wifi direct mode */ + + if (MLAN_STATUS_SUCCESS != woal_cfg80211_deinit_p2p(priv)) { + ret = -EFAULT; + goto done; + } + } +#endif /* KERNEL_VERSION */ +#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */ + + bss->param.bss_mode = MLAN_BSS_MODE_INFRA; + priv->wdev->iftype = NL80211_IFTYPE_STATION; + PRINTM(MINFO, "Setting interface type to managed\n"); + break; +#if defined(WIFI_DIRECT_SUPPORT) +#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION + case NL80211_IFTYPE_P2P_CLIENT: + + if (MLAN_STATUS_SUCCESS != woal_cfg80211_init_p2p_client(priv)) { + ret = -EFAULT; + goto done; + } + + bss->param.bss_mode = MLAN_BSS_MODE_INFRA; + priv->wdev->iftype = NL80211_IFTYPE_P2P_CLIENT; + PRINTM(MINFO, "Setting interface type to P2P client\n"); + + break; +#endif /* KERNEL_VERSION */ +#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */ + case NL80211_IFTYPE_AP: +#if defined(WIFI_DIRECT_SUPPORT) +#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION + case NL80211_IFTYPE_P2P_GO: + if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) { + if (MLAN_STATUS_SUCCESS != woal_cfg80211_init_p2p_go(priv)) { + ret = -EFAULT; + goto done; + } + } + if (type == NL80211_IFTYPE_P2P_GO) + priv->wdev->iftype = NL80211_IFTYPE_P2P_GO; +#endif +#endif + if (type == NL80211_IFTYPE_AP) + priv->wdev->iftype = NL80211_IFTYPE_AP; + PRINTM(MINFO, "Setting interface type to P2P GO\n"); + + /* there is no need for P2P GO to set bss_mode */ + goto done; + + break; + + case NL80211_IFTYPE_UNSPECIFIED: + bss->param.bss_mode = MLAN_BSS_MODE_AUTO; + priv->wdev->iftype = NL80211_IFTYPE_STATION; + PRINTM(MINFO, "Setting interface type to auto\n"); + break; + default: + ret = -EINVAL; + break; + } + if (ret) + goto done; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + done: + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Request the driver to change the value of fragment + * threshold or rts threshold or retry limit + * + * @param wiphy A pointer to wiphy structure + * @param changed Change flags + * + * @return 0 -- success, otherwise fail + */ +int +woal_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); +#ifdef UAP_CFG80211 +#ifdef UAP_SUPPORT + mlan_uap_bss_param sys_cfg; +#endif +#endif + int frag_thr = wiphy->frag_threshold; + int rts_thr = wiphy->frag_threshold; + int retry = wiphy->retry_long; + + ENTER(); + + if (rts_thr == MLAN_FRAG_RTS_DISABLED) + rts_thr = MLAN_RTS_MAX_VALUE; + if (frag_thr == MLAN_FRAG_RTS_DISABLED) + frag_thr = MLAN_FRAG_MAX_VALUE; + +#ifdef UAP_CFG80211 +#ifdef UAP_SUPPORT + if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) { + /* Initialize the invalid values so that the correct values below are + downloaded to firmware */ + woal_set_sys_config_invalid_data(&sys_cfg); + sys_cfg.frag_threshold = frag_thr; + sys_cfg.rts_threshold = rts_thr; + sys_cfg.retry_limit = retry; + + if ((changed & WIPHY_PARAM_RTS_THRESHOLD) || + (changed & WIPHY_PARAM_FRAG_THRESHOLD) || + (changed & (WIPHY_PARAM_RETRY_LONG | WIPHY_PARAM_RETRY_SHORT))) { + if (woal_set_get_sys_config(priv, + MLAN_ACT_SET, MOAL_IOCTL_WAIT, + &sys_cfg)) + goto fail; + } + } +#endif +#endif + +#ifdef STA_CFG80211 +#ifdef STA_SUPPORT + if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) { + if (changed & WIPHY_PARAM_RTS_THRESHOLD) { + if (woal_set_get_rts(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, &rts_thr)) + goto fail; + } + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { + if (woal_set_get_frag + (priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, &frag_thr)) + goto fail; + } + if (changed & (WIPHY_PARAM_RETRY_LONG | WIPHY_PARAM_RETRY_SHORT)) + if (woal_set_get_retry(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, &retry)) + goto fail; + } +#endif +#endif + + LEAVE(); + return 0; + + fail: + PRINTM(MERROR, "Failed to change wiphy params %x\n", changed); + LEAVE(); + return -EFAULT; +} + +/** + * @brief Request the driver to add a key + * + * @param wiphy A pointer to wiphy structure + * @param netdev A pointer to net_device structure + * @param key_index Key index + * @param pairwise Flag to indicate pairwise or group (for kernel > 2.6.36) + * @param mac_addr MAC address (NULL for group key) + * @param params A pointer to key_params structure + * + * @return 0 -- success, otherwise fail + */ +int +woal_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev, + t_u8 key_index, +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36) || defined(COMPAT_WIRELESS) + bool pairwise, +#endif + const t_u8 * mac_addr, struct key_params *params) +{ + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + + ENTER(); + + if (woal_cfg80211_set_key(priv, 0, params->cipher, params->key, + params->key_len, params->seq, params->seq_len, + key_index, mac_addr, 0)) { + PRINTM(MERROR, "Error adding the crypto keys\n"); + LEAVE(); + return -EFAULT; + } + + PRINTM(MINFO, "Crypto keys added\n"); + + LEAVE(); + return 0; +} + +/** + * @brief Request the driver to delete a key + * + * @param wiphy A pointer to wiphy structure + * @param netdev A pointer to net_device structure + * @param key_index Key index + * @param pairwise Flag to indicate pairwise or group (for kernel > 2.6.36) + * @param mac_addr MAC address (NULL for group key) + * + * @return 0 -- success, otherwise fail + */ +int +woal_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev, + t_u8 key_index, +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36) || defined(COMPAT_WIRELESS) + bool pairwise, +#endif + const t_u8 * mac_addr) +{ + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + + ENTER(); + + if (woal_cfg80211_set_key(priv, 0, 0, NULL, 0, NULL, 0, key_index, + mac_addr, 1)) { + PRINTM(MERROR, "Error deleting the crypto keys\n"); + LEAVE(); + return -EFAULT; + } + + PRINTM(MINFO, "Crypto keys deleted\n"); + LEAVE(); + return 0; +} + +/** + * @brief Request to enable WEP key to driver + * + * @param wiphy A pointer to wiphy structure + * @param netdev A pointer to net_device structure + * @param key_index Key index + * @param ucast Unicast flag (for kernel > 2.6.37) + * @param mcast Multicast flag (for kernel > 2.6.37) + * + * @return 0 -- success, otherwise fail + */ +int +woal_cfg80211_set_default_key(struct wiphy *wiphy, + struct net_device *netdev, t_u8 key_index +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS) + , bool ucast, bool mcast +#endif + ) +{ + int ret = 0; + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + mlan_bss_info bss_info; + + ENTER(); + + woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info); + if (bss_info.wep_status) { + LEAVE(); + return ret; + } + + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_set_wep_keys(priv, NULL, 0, key_index)) { + ret = -EFAULT; + } + + LEAVE(); + return ret; +} + +/** + * @brief Request the driver to change the channel + * + * @param wiphy A pointer to wiphy structure + * @param chan A pointer to ieee80211_channel structure + * @param channel_type Channel type of nl80211_channel_type + * + * @return 0 -- success, otherwise fail + */ +int +woal_cfg80211_set_channel(struct wiphy *wiphy, +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) || defined(COMPAT_WIRELESS) + struct net_device *dev, +#endif + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) +{ + int ret = 0; + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + + ENTER(); +#ifdef STA_CFG80211 +#ifdef STA_SUPPORT + if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) { + if (priv->media_connected == MTRUE) { + PRINTM(MERROR, "This configuration is valid only when station " + "is not connected\n"); + LEAVE(); + return -EINVAL; + } + ret = woal_set_rf_channel(wiphy, chan, channel_type); + } +#endif +#endif + priv->channel = ieee80211_frequency_to_channel(chan->center_freq); + LEAVE(); + return ret; +} + +/** + * @brief register/unregister mgmt frame forwarding + * + * @param wiphy A pointer to wiphy structure + * @param dev A pointer to net_device structure + * @param frame_type Bit mask for mgmt frame type + * @param reg Register or unregister + * + * @return 0 -- success, otherwise fail + */ +void +woal_cfg80211_mgmt_frame_register(struct wiphy *wiphy, + struct net_device *dev, u16 frame_type, + bool reg) +{ + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + mlan_status status = MLAN_STATUS_SUCCESS; + t_u32 mgmt_subtype_mask = 0x0; + static t_u32 last_mgmt_subtype_mask = 0x0; + + ENTER(); +#ifdef UAP_SUPPORT + if ((priv->bss_type == MLAN_BSS_TYPE_UAP) && + (frame_type == IEEE80211_STYPE_PROBE_REQ)) { + LEAVE(); + return; + } +#endif + if (reg == MTRUE) { + /* set mgmt_subtype_mask based on origin value */ + last_mgmt_subtype_mask |= BIT(frame_type >> 4); + } else { + /* clear mgmt_subtype_mask */ + last_mgmt_subtype_mask &= ~BIT(frame_type >> 4); + } + mgmt_subtype_mask = last_mgmt_subtype_mask; + + /* Notify driver that a mgmt frame type was registered. Note that this + callback may not sleep, and cannot run concurrently with itself. */ + status = woal_reg_rx_mgmt_ind(priv, MLAN_ACT_SET, + &mgmt_subtype_mask, MOAL_NO_WAIT); + + LEAVE(); +} + +/** + * @brief tx mgmt frame + * + * @param wiphy A pointer to wiphy structure + * @param dev A pointer to net_device structure + * @param chan A pointer to ieee80211_channel structure + * @param offchan Off channel or not + * @param channel_type Channel type + * @param channel_type_valid Is channel type valid or not + * @param buf Frame buffer + * @param len Frame length + * @param cookie A pointer to frame cookie + * + * @return 0 -- success, otherwise fail + */ +int +woal_cfg80211_mgmt_tx(struct wiphy *wiphy, + struct net_device *dev, + struct ieee80211_channel *chan, bool offchan, + enum nl80211_channel_type channel_type, + bool channel_type_valid, unsigned int wait, + const u8 * buf, size_t len, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0) || defined(COMPAT_WIRELESS) + bool no_cck, +#endif + u64 * cookie) +{ + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + int ret = 0; + pmlan_buffer pmbuf = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + t_u16 packet_len = 0; + t_u8 addr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + t_u16 framectrl; + t_u32 pkt_type; + t_u32 tx_control; +#if defined(WIFI_DIRECT_SUPPORT) +#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION + t_u8 channel_status; + t_u32 duration; +#endif +#endif + + ENTER(); + + if (buf == NULL || len == 0) { + PRINTM(MERROR, "woal_cfg80211_mgmt_tx() corrupt data\n"); + ret = -EFAULT; + goto done; + } + + /* frame subtype == probe response, that means we are in listen phase, so + we should not call remain_on_channel_cfg because remain_on_channl + already handled it. frame subtype == action, that means we are in + PD/GO negotiation, so we should call remain_on_channel_cfg in order to + receive action frame from peer device */ + framectrl = ((const struct ieee80211_mgmt *) buf)->frame_control; + PRINTM(MIOCTL, "Mgmt: framectrl=0x%x\n", framectrl); +#if defined(WIFI_DIRECT_SUPPORT) +#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION + if ((priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) && + (framectrl == IEEE80211_STYPE_ACTION)) { +#define MGMT_TX_DEFAULT_WAIT_TIME 2000 + /** cancel previous remain on channel */ + if (priv->phandle->remain_on_channel) { + if (woal_cfg80211_remain_on_channel_cfg + (wiphy, MOAL_IOCTL_WAIT, MTRUE, &channel_status, NULL, 0, 0)) { + PRINTM(MERROR, "Fail to cancel remain on channel\n"); + ret = -EFAULT; + goto done; + } + if (priv->phandle->cookie) { + cfg80211_remain_on_channel_expired(priv->netdev, + priv->phandle->cookie, + &priv->phandle->chan, + priv->phandle->channel_type, + GFP_ATOMIC); + priv->phandle->cookie = 0; + } + priv->phandle->remain_on_channel = MFALSE; + } + duration = wait; + if (!wait) + duration = MGMT_TX_DEFAULT_WAIT_TIME; + if (channel_type_valid) + ret = + woal_cfg80211_remain_on_channel_cfg(wiphy, MOAL_IOCTL_WAIT, + MFALSE, &channel_status, + chan, channel_type, + duration); + else + ret = + woal_cfg80211_remain_on_channel_cfg(wiphy, MOAL_IOCTL_WAIT, + MFALSE, &channel_status, + chan, 0, duration); + if (ret) { + PRINTM(MERROR, "Fail to configure remain on channel\n"); + ret = -EFAULT; + goto done; + } + priv->phandle->remain_on_channel = MTRUE; + priv->phandle->channel_type = channel_type; + memcpy(&priv->phandle->chan, chan, sizeof(struct ieee80211_channel)); + PRINTM(MIOCTL, "Mgmt Tx: Set remain channel=%d\n", + ieee80211_frequency_to_channel(chan->center_freq)); + } +#endif +#endif +#define MRVL_PKT_TYPE_MGMT_FRAME 0xE5 + /* pkt_type + tx_control */ +#define HEADER_SIZE 8 + packet_len = (t_u16) len + MLAN_MAC_ADDR_LENGTH; + pmbuf = woal_alloc_mlan_buffer(priv->phandle, + MLAN_MIN_DATA_HEADER_LEN + HEADER_SIZE + + packet_len + sizeof(packet_len)); + if (!pmbuf) { + PRINTM(MERROR, "Fail to allocate mlan_buffer\n"); + ret = -ENOMEM; + goto done; + } + *cookie = random32() | 1; + pmbuf->data_offset = MLAN_MIN_DATA_HEADER_LEN; + pkt_type = MRVL_PKT_TYPE_MGMT_FRAME; + tx_control = 0; + /* Add pkt_type and tx_control */ + memcpy(pmbuf->pbuf + pmbuf->data_offset, &pkt_type, sizeof(pkt_type)); + memcpy(pmbuf->pbuf + pmbuf->data_offset + sizeof(pkt_type), &tx_control, + sizeof(tx_control)); + /* frmctl + durationid + addr1 + addr2 + addr3 + seqctl */ +#define PACKET_ADDR4_POS (2 + 2 + 6 + 6 + 6 + 2) + memcpy(pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE, &packet_len, + sizeof(packet_len)); + memcpy(pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE + sizeof(packet_len), + buf, PACKET_ADDR4_POS); + memcpy(pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE + sizeof(packet_len) + + PACKET_ADDR4_POS, addr, MLAN_MAC_ADDR_LENGTH); + memcpy(pmbuf->pbuf + pmbuf->data_offset + HEADER_SIZE + sizeof(packet_len) + + PACKET_ADDR4_POS + MLAN_MAC_ADDR_LENGTH, + buf + PACKET_ADDR4_POS, len - PACKET_ADDR4_POS); + + pmbuf->data_len = HEADER_SIZE + packet_len + sizeof(packet_len); + pmbuf->buf_type = MLAN_BUF_TYPE_RAW_DATA; + pmbuf->bss_index = priv->bss_index; + + status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf); + + switch (status) { + case MLAN_STATUS_PENDING: + atomic_inc(&priv->phandle->tx_pending); + queue_work(priv->phandle->workqueue, &priv->phandle->main_work); + + /* delay 20ms to guarantee the packet has been already tx'ed becuase if + we call cfg80211_mgmt_tx_status() immediately, then wpa_supplicant + will call cancel_remain_on_channel(), which may affect the mgmt + frame tx */ + mdelay(20); + + /* Notify the mgmt tx status */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS) + cfg80211_mgmt_tx_status(dev, *cookie, buf, len, true, GFP_ATOMIC); +#endif + break; + case MLAN_STATUS_SUCCESS: + woal_free_mlan_buffer(priv->phandle, pmbuf); + break; + case MLAN_STATUS_FAILURE: + default: + woal_free_mlan_buffer(priv->phandle, pmbuf); + ret = -EFAULT; + break; + } + + done: + LEAVE(); + return ret; +} diff --git a/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.h b/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.h new file mode 100644 index 000000000000..e1683ed08a89 --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.h @@ -0,0 +1,195 @@ +/** @file moal_cfg80211.h + * + * @brief This file contains the CFG80211 specific defines. + * + * Copyright (C) 2011-2012, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +#ifndef _MOAL_CFG80211_H_ +#define _MOAL_CFG80211_H_ + +#include "moal_main.h" + +/** RTS/FRAG disabled value */ +#define MLAN_FRAG_RTS_DISABLED (0xFFFFFFFF) + +#ifndef WLAN_CIPHER_SUITE_WAPI +#define WLAN_CIPHER_SUITE_WAPI 0x00000020 +#endif + +/* define for custom ie operation */ +#define MLAN_CUSTOM_IE_AUTO_IDX_MASK 0xffff +#define MLAN_CUSTOM_IE_DELETE_MASK 0x0 +#define TLV_TYPE_MGMT_IE 0x0169 +#define MGMT_MASK_ASSOC_REQ 0x01 +#define MGMT_MASK_REASSOC_REQ 0x04 +#define MGMT_MASK_ASSOC_RESP 0x02 +#define MGMT_MASK_REASSOC_RESP 0x08 +#define MGMT_MASK_PROBE_REQ 0x10 +#define MGMT_MASK_PROBE_RESP 0x20 +#define MGMT_MASK_BEACON 0x100 + +/** + * If multiple wiphys are registered e.g. a regular netdev with + * assigned ieee80211_ptr and you won't know whether it points + * to a wiphy your driver has registered or not. Assign this to + * something global to your driver to help determine whether + * you own this wiphy or not. + */ +static const void *const mrvl_wiphy_privid = &mrvl_wiphy_privid; + +/* Get the private structure from wiphy */ +void *woal_get_wiphy_priv(struct wiphy *wiphy); + +int woal_cfg80211_change_virtual_intf(struct wiphy *wiphy, + struct net_device *dev, + enum nl80211_iftype type, + u32 * flags, struct vif_params *params); + +int woal_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed); + +int woal_cfg80211_add_key(struct wiphy *wiphy, + struct net_device *dev, t_u8 key_index, +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36) || defined(COMPAT_WIRELESS) + bool pairwise, +#endif + const t_u8 * mac_addr, struct key_params *params); + +int woal_cfg80211_del_key(struct wiphy *wiphy, + struct net_device *dev, t_u8 key_index, +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,36) || defined(COMPAT_WIRELESS) + bool pairwise, +#endif + const t_u8 * mac_addr); + +#ifdef STA_CFG80211 +#ifdef STA_SUPPORT +int woal_set_rf_channel(struct wiphy *wiphy, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type); +mlan_status woal_inform_bss_from_scan_result(moal_private * priv, + mlan_802_11_ssid * ssid); +#endif +#endif + +int woal_cfg80211_set_channel(struct wiphy *wiphy, +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) || defined(COMPAT_WIRELESS) + struct net_device *dev, +#endif + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type); + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS) +int woal_cfg80211_set_default_key(struct wiphy *wiphy, + struct net_device *dev, t_u8 key_index, + bool ucast, bool mcast); +#else +int woal_cfg80211_set_default_key(struct wiphy *wiphy, + struct net_device *dev, t_u8 key_index); +#endif + +void woal_cfg80211_mgmt_frame_register(struct wiphy *wiphy, + struct net_device *dev, t_u16 frame_type, + bool reg); + +int woal_cfg80211_mgmt_tx(struct wiphy *wiphy, + struct net_device *dev, + struct ieee80211_channel *chan, bool offchan, + enum nl80211_channel_type channel_type, + bool channel_type_valid, unsigned int wait, + const u8 * buf, size_t len, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0) || defined(COMPAT_WIRELESS) + bool no_cck, +#endif + u64 * cookie); + +extern struct ieee80211_supported_band cfg80211_band_2ghz; +extern struct ieee80211_supported_band cfg80211_band_5ghz; +extern const u32 cfg80211_cipher_suites[10]; + +typedef struct _monitor_iface +{ + /* The priv data of interface on which the monitor iface is based */ + moal_private *priv; + struct wireless_dev wdev; + int radiotap_enabled; + /* The net_device on which the monitor iface is based. */ + struct net_device *base_ndev; + struct net_device *mon_ndev; + char ifname[IFNAMSIZ]; + int flag; +} monitor_iface; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS) +struct net_device *woal_cfg80211_add_virtual_intf(struct wiphy *wiphy, + char *name, + enum nl80211_iftype type, + u32 * flags, + struct vif_params *params); +#else +int woal_cfg80211_add_virtual_intf(struct wiphy *wiphy, + char *name, enum nl80211_iftype type, + u32 * flags, struct vif_params *params); +#endif +int woal_cfg80211_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev); + +#if defined(WIFI_DIRECT_SUPPORT) +/** Define kernel version for wifi direct */ +#if !defined(COMPAT_WIRELESS) +#define WIFI_DIRECT_KERNEL_VERSION KERNEL_VERSION(3,0,0) +#else +#define WIFI_DIRECT_KERNEL_VERSION KERNEL_VERSION(2,6,33) +#endif /* COMPAT_WIRELESS */ +#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION +/** Define for remain on channel duration timer */ +#define MAX_REMAIN_ON_CHANNEL_DURATION (1000 * 5) + +int woal_cfg80211_add_beacon(struct wiphy *wiphy, + struct net_device *dev, + struct beacon_parameters *params); + +int woal_cfg80211_set_beacon(struct wiphy *wiphy, + struct net_device *dev, + struct beacon_parameters *params); + +int woal_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev); + +int woal_cfg80211_init_p2p_client(moal_private * priv); + +int woal_cfg80211_init_p2p_go(moal_private * priv); + +int woal_cfg80211_deinit_p2p(moal_private * priv); + +int woal_cfg80211_remain_on_channel_cfg(struct wiphy *wiphy, + t_u8 wait_option, t_u8 remove, + t_u8 * status, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + t_u32 duration); +int woal_uap_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, + u8 * mac, struct station_info *stainfo); +#endif /* KERNEL_VERSION */ +#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */ + +int woal_cfg80211_mgmt_frame_ie(moal_private * priv, + const t_u8 * beacon_ies, size_t beacon_ies_len, + const t_u8 * proberesp_ies, + size_t proberesp_ies_len, + const t_u8 * assocresp_ies, + size_t assocresp_ies_len, + const t_u8 * probereq_ies, + size_t probereq_ies_len, t_u16 mask); +#endif /* _MOAL_CFG80211_H_ */ diff --git a/drivers/net/wireless/sd8797/mlinux/moal_debug.c b/drivers/net/wireless/sd8797/mlinux/moal_debug.c new file mode 100644 index 000000000000..fd74c3b5ae92 --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/moal_debug.c @@ -0,0 +1,674 @@ +/** @file moal_debug.c + * + * @brief This file contains functions for debug proc file. + * + * Copyright (C) 2008-2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +/******************************************************** +Change log: + 11/03/2008: initial version +********************************************************/ + +#include "moal_main.h" + +/******************************************************** + Global Variables +********************************************************/ +/** MLAN debug info */ +extern mlan_debug_info info; + +/******************************************************** + Local Variables +********************************************************/ +#ifdef CONFIG_PROC_FS + +/** Get info item size */ +#define item_size(n) (sizeof(info.n)) +/** Get info item address */ +#define item_addr(n) ((t_ptr) &(info.n)) + +/** Get moal_private member size */ +#define item_priv_size(n) (sizeof ((moal_private *)0)->n) +/** Get moal_private member address */ +#define item_priv_addr(n) ((t_ptr) &((moal_private *)0)->n) + +/** Get moal_handle member size */ +#define item_handle_size(n) (sizeof ((moal_handle *)0)->n) +/** Get moal_handle member address */ +#define item_handle_addr(n) ((t_ptr) &((moal_handle *)0)->n) + +#ifdef STA_SUPPORT +static struct debug_data items[] = { +#ifdef DEBUG_LEVEL1 + {"drvdbg", sizeof(drvdbg), (t_ptr) & drvdbg} + , +#endif + {"wmm_ac_vo", item_size(wmm_ac_vo), item_addr(wmm_ac_vo)} + , + {"wmm_ac_vi", item_size(wmm_ac_vi), item_addr(wmm_ac_vi)} + , + {"wmm_ac_be", item_size(wmm_ac_be), item_addr(wmm_ac_be)} + , + {"wmm_ac_bk", item_size(wmm_ac_bk), item_addr(wmm_ac_bk)} + , + {"max_tx_buf_size", item_size(max_tx_buf_size), item_addr(max_tx_buf_size)} + , + {"tx_buf_size", item_size(tx_buf_size), item_addr(tx_buf_size)} + , + {"curr_tx_buf_size", item_size(curr_tx_buf_size), + item_addr(curr_tx_buf_size)} + , + {"ps_mode", item_size(ps_mode), item_addr(ps_mode)} + , + {"ps_state", item_size(ps_state), item_addr(ps_state)} + , + {"is_deep_sleep", item_size(is_deep_sleep), item_addr(is_deep_sleep)} + , + {"wakeup_dev_req", item_size(pm_wakeup_card_req), + item_addr(pm_wakeup_card_req)} + , + {"wakeup_tries", item_size(pm_wakeup_fw_try), item_addr(pm_wakeup_fw_try)} + , + {"hs_configured", item_size(is_hs_configured), item_addr(is_hs_configured)} + , + {"hs_activated", item_size(hs_activated), item_addr(hs_activated)} + , + {"tx_pkts_queued", item_size(tx_pkts_queued), item_addr(tx_pkts_queued)} + , + {"pps_uapsd_mode", item_size(pps_uapsd_mode), item_addr(pps_uapsd_mode)} + , + {"sleep_pd", item_size(sleep_pd), item_addr(sleep_pd)} + , + {"qos_cfg", item_size(qos_cfg), item_addr(qos_cfg)} + , + {"tx_lock_flag", item_size(tx_lock_flag), item_addr(tx_lock_flag)} + , + {"port_open", item_size(port_open), item_addr(port_open)} + , + {"scan_processing", item_size(scan_processing), item_addr(scan_processing)} + , + {"num_tx_timeout", item_size(num_tx_timeout), item_addr(num_tx_timeout)} + , + {"num_cmd_timeout", item_size(num_cmd_timeout), item_addr(num_cmd_timeout)} + , + {"timeout_cmd_id", item_size(timeout_cmd_id), item_addr(timeout_cmd_id)} + , + {"timeout_cmd_act", item_size(timeout_cmd_act), item_addr(timeout_cmd_act)} + , + {"last_cmd_id", item_size(last_cmd_id), item_addr(last_cmd_id)} + , + {"last_cmd_act", item_size(last_cmd_act), item_addr(last_cmd_act)} + , + {"last_cmd_index", item_size(last_cmd_index), item_addr(last_cmd_index)} + , + {"last_cmd_resp_id", item_size(last_cmd_resp_id), + item_addr(last_cmd_resp_id)} + , + {"last_cmd_resp_index", item_size(last_cmd_resp_index), + item_addr(last_cmd_resp_index)} + , + {"last_event", item_size(last_event), item_addr(last_event)} + , + {"last_event_index", item_size(last_event_index), + item_addr(last_event_index)} + , + {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure), + item_addr(num_cmd_host_to_card_failure)} + , + {"num_cmd_sleep_cfm_fail", + item_size(num_cmd_sleep_cfm_host_to_card_failure), + item_addr(num_cmd_sleep_cfm_host_to_card_failure)} + , + {"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure), + item_addr(num_tx_host_to_card_failure)} + , + {"num_cmdevt_c2h_fail", item_size(num_cmdevt_card_to_host_failure), + item_addr(num_cmdevt_card_to_host_failure)} + , + {"num_rx_c2h_fail", item_size(num_rx_card_to_host_failure), + item_addr(num_rx_card_to_host_failure)} + , + {"num_int_read_fail", item_size(num_int_read_failure), + item_addr(num_int_read_failure)} + , + {"last_int_status", item_size(last_int_status), item_addr(last_int_status)} + , + {"num_evt_deauth", item_size(num_event_deauth), item_addr(num_event_deauth)} + , + {"num_evt_disassoc", item_size(num_event_disassoc), + item_addr(num_event_disassoc)} + , + {"num_evt_link_lost", item_size(num_event_link_lost), + item_addr(num_event_link_lost)} + , + {"num_cmd_deauth", item_size(num_cmd_deauth), item_addr(num_cmd_deauth)} + , + {"num_cmd_assoc_ok", item_size(num_cmd_assoc_success), + item_addr(num_cmd_assoc_success)} + , + {"num_cmd_assoc_fail", item_size(num_cmd_assoc_failure), + item_addr(num_cmd_assoc_failure)} + , + {"cmd_sent", item_size(cmd_sent), item_addr(cmd_sent)} + , + {"data_sent", item_size(data_sent), item_addr(data_sent)} + , + {"mp_rd_bitmap", item_size(mp_rd_bitmap), item_addr(mp_rd_bitmap)} + , + {"curr_rd_port", item_size(curr_rd_port), item_addr(curr_rd_port)} + , + {"mp_wr_bitmap", item_size(mp_wr_bitmap), item_addr(mp_wr_bitmap)} + , + {"curr_wr_port", item_size(curr_wr_port), item_addr(curr_wr_port)} + , + {"cmd_resp_received", item_size(cmd_resp_received), + item_addr(cmd_resp_received)} + , + {"event_received", item_size(event_received), item_addr(event_received)} + , + + {"ioctl_pending", item_handle_size(ioctl_pending), + item_handle_addr(ioctl_pending)} + , + {"tx_pending", item_handle_size(tx_pending), item_handle_addr(tx_pending)} + , + {"rx_pending", item_handle_size(rx_pending), item_handle_addr(rx_pending)} + , + {"malloc_count", item_handle_size(malloc_count), + item_handle_addr(malloc_count)} + , + {"lock_count", item_handle_size(lock_count), item_handle_addr(lock_count)} + , + {"mbufalloc_count", item_handle_size(mbufalloc_count), + item_handle_addr(mbufalloc_count)} + , + {"main_state", item_handle_size(main_state), item_handle_addr(main_state)} + , +#ifdef SDIO_MMC_DEBUG + {"sdiocmd53w", item_handle_size(cmd53w), item_handle_addr(cmd53w)} + , + {"sdiocmd53r", item_handle_size(cmd53r), item_handle_addr(cmd53r)} + , +#endif +#if defined(SDIO_SUSPEND_RESUME) + {"hs_skip_count", item_handle_size(hs_skip_count), + item_handle_addr(hs_skip_count)} + , + {"hs_force_count", item_handle_size(hs_force_count), + item_handle_addr(hs_force_count)} + , +#endif +}; + +#endif + +#ifdef UAP_SUPPORT +static struct debug_data uap_items[] = { +#ifdef DEBUG_LEVEL1 + {"drvdbg", sizeof(drvdbg), (t_ptr) & drvdbg} + , +#endif + {"wmm_ac_vo", item_size(wmm_ac_vo), item_addr(wmm_ac_vo)} + , + {"wmm_ac_vi", item_size(wmm_ac_vi), item_addr(wmm_ac_vi)} + , + {"wmm_ac_be", item_size(wmm_ac_be), item_addr(wmm_ac_be)} + , + {"wmm_ac_bk", item_size(wmm_ac_bk), item_addr(wmm_ac_bk)} + , + {"max_tx_buf_size", item_size(max_tx_buf_size), item_addr(max_tx_buf_size)} + , + {"tx_buf_size", item_size(tx_buf_size), item_addr(tx_buf_size)} + , + {"curr_tx_buf_size", item_size(curr_tx_buf_size), + item_addr(curr_tx_buf_size)} + , + {"ps_mode", item_size(ps_mode), item_addr(ps_mode)} + , + {"ps_state", item_size(ps_state), item_addr(ps_state)} + , + {"wakeup_dev_req", item_size(pm_wakeup_card_req), + item_addr(pm_wakeup_card_req)} + , + {"wakeup_tries", item_size(pm_wakeup_fw_try), item_addr(pm_wakeup_fw_try)} + , + {"hs_configured", item_size(is_hs_configured), item_addr(is_hs_configured)} + , + {"hs_activated", item_size(hs_activated), item_addr(hs_activated)} + , + {"tx_pkts_queued", item_size(tx_pkts_queued), item_addr(tx_pkts_queued)} + , + {"num_bridge_pkts", item_size(num_bridge_pkts), item_addr(num_bridge_pkts)} + , + {"num_drop_pkts", item_size(num_drop_pkts), item_addr(num_drop_pkts)} + , + {"num_tx_timeout", item_size(num_tx_timeout), item_addr(num_tx_timeout)} + , + {"num_cmd_timeout", item_size(num_cmd_timeout), item_addr(num_cmd_timeout)} + , + {"timeout_cmd_id", item_size(timeout_cmd_id), item_addr(timeout_cmd_id)} + , + {"timeout_cmd_act", item_size(timeout_cmd_act), item_addr(timeout_cmd_act)} + , + {"last_cmd_id", item_size(last_cmd_id), item_addr(last_cmd_id)} + , + {"last_cmd_act", item_size(last_cmd_act), item_addr(last_cmd_act)} + , + {"last_cmd_index", item_size(last_cmd_index), item_addr(last_cmd_index)} + , + {"last_cmd_resp_id", item_size(last_cmd_resp_id), + item_addr(last_cmd_resp_id)} + , + {"last_cmd_resp_index", item_size(last_cmd_resp_index), + item_addr(last_cmd_resp_index)} + , + {"last_event", item_size(last_event), item_addr(last_event)} + , + {"last_event_index", item_size(last_event_index), + item_addr(last_event_index)} + , + {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure), + item_addr(num_cmd_host_to_card_failure)} + , + {"num_cmd_sleep_cfm_fail", + item_size(num_cmd_sleep_cfm_host_to_card_failure), + item_addr(num_cmd_sleep_cfm_host_to_card_failure)} + , + {"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure), + item_addr(num_tx_host_to_card_failure)} + , + {"num_cmdevt_c2h_fail", item_size(num_cmdevt_card_to_host_failure), + item_addr(num_cmdevt_card_to_host_failure)} + , + {"num_rx_c2h_fail", item_size(num_rx_card_to_host_failure), + item_addr(num_rx_card_to_host_failure)} + , + {"num_int_read_fail", item_size(num_int_read_failure), + item_addr(num_int_read_failure)} + , + {"last_int_status", item_size(last_int_status), item_addr(last_int_status)} + , + {"cmd_sent", item_size(cmd_sent), item_addr(cmd_sent)} + , + {"data_sent", item_size(data_sent), item_addr(data_sent)} + , + {"mp_rd_bitmap", item_size(mp_rd_bitmap), item_addr(mp_rd_bitmap)} + , + {"curr_rd_port", item_size(curr_rd_port), item_addr(curr_rd_port)} + , + {"mp_wr_bitmap", item_size(mp_wr_bitmap), item_addr(mp_wr_bitmap)} + , + {"curr_wr_port", item_size(curr_wr_port), item_addr(curr_wr_port)} + , + {"cmd_resp_received", item_size(cmd_resp_received), + item_addr(cmd_resp_received)} + , + {"event_received", item_size(event_received), item_addr(event_received)} + , + + {"ioctl_pending", item_handle_size(ioctl_pending), + item_handle_addr(ioctl_pending)} + , + {"tx_pending", item_handle_size(tx_pending), item_handle_addr(tx_pending)} + , + {"rx_pending", item_handle_size(rx_pending), item_handle_addr(rx_pending)} + , + {"malloc_count", item_handle_size(malloc_count), + item_handle_addr(malloc_count)} + , + {"lock_count", item_handle_size(lock_count), item_handle_addr(lock_count)} + , + {"mbufalloc_count", item_handle_size(mbufalloc_count), + item_handle_addr(mbufalloc_count)} + , + {"main_state", item_handle_size(main_state), item_handle_addr(main_state)} + , +#ifdef SDIO_MMC_DEBUG + {"sdiocmd53w", item_handle_size(cmd53w), item_handle_addr(cmd53w)} + , + {"sdiocmd53r", item_handle_size(cmd53r), item_handle_addr(cmd53r)} + , +#endif +#if defined(SDIO_SUSPEND_RESUME) + {"hs_skip_count", item_handle_size(hs_skip_count), + item_handle_addr(hs_skip_count)} + , + {"hs_force_count", item_handle_size(hs_force_count), + item_handle_addr(hs_force_count)} + , +#endif +}; +#endif /* UAP_SUPPORT */ + +/******************************************************** + Local Functions +********************************************************/ +/** + * @brief Proc read function + * + * @param page Pointer to buffer + * @param s Read data starting position + * @param off Offset + * @param cnt Counter + * @param eof End of file flag + * @param data Output data + * + * @return Number of output data or MLAN_STATUS_FAILURE + */ +static int +woal_debug_read(char *page, char **s, off_t off, int cnt, int *eof, void *data) +{ + int val = 0; + unsigned int i; + char *p = page; + struct debug_data *d = ((struct debug_data_priv *) data)->items; + moal_private *priv = ((struct debug_data_priv *) data)->priv; + + ENTER(); + + if (MODULE_GET == 0) { + LEAVE(); + return MLAN_STATUS_FAILURE; + } + + /* Get debug information */ + if (woal_get_debug_info(priv, MOAL_PROC_WAIT, &info)) { + *eof = 1; + goto exit; + } + for (i = 0; + i < (unsigned int) ((struct debug_data_priv *) data)->num_of_items; + i++) { + if (d[i].size == 1) + val = *((t_u8 *) d[i].addr); + else if (d[i].size == 2) + val = *((t_u16 *) d[i].addr); + else if (d[i].size == 4) + val = *((t_ptr *) d[i].addr); + else { + unsigned int j; + p += sprintf(p, "%s=", d[i].name); + for (j = 0; j < d[i].size; j += 2) { + val = *(t_u16 *) (d[i].addr + j); + p += sprintf(p, "0x%x ", val); + } + p += sprintf(p, "\n"); + continue; + } + if (strstr(d[i].name, "id") || strstr(d[i].name, "bitmap")) + p += sprintf(p, "%s=0x%x\n", d[i].name, val); + else + p += sprintf(p, "%s=%d\n", d[i].name, val); + } + if (info.tx_tbl_num) { + p += sprintf(p, "Tx BA stream table:\n"); + for (i = 0; i < info.tx_tbl_num; i++) { + p += sprintf(p, + "tid = %d, ra = %02x:%02x:%02x:%02x:%02x:%02x amsdu=%d\n", + (int) info.tx_tbl[i].tid, info.tx_tbl[i].ra[0], + info.tx_tbl[i].ra[1], info.tx_tbl[i].ra[2], + info.tx_tbl[i].ra[3], info.tx_tbl[i].ra[4], + info.tx_tbl[i].ra[5], (int) info.tx_tbl[i].amsdu); + } + } + if (info.rx_tbl_num) { + p += sprintf(p, "Rx reorder table:\n"); + for (i = 0; i < info.rx_tbl_num; i++) { + unsigned int j; + + p += sprintf(p, + "tid = %d, ta = %02x:%02x:%02x:%02x:%02x:%02x, start_win = %d, " + "win_size = %d, amsdu=%d\n", (int) info.rx_tbl[i].tid, + info.rx_tbl[i].ta[0], info.rx_tbl[i].ta[1], + info.rx_tbl[i].ta[2], info.rx_tbl[i].ta[3], + info.rx_tbl[i].ta[4], info.rx_tbl[i].ta[5], + (int) info.rx_tbl[i].start_win, + (int) info.rx_tbl[i].win_size, + (int) info.rx_tbl[i].amsdu); + p += sprintf(p, "buffer: "); + for (j = 0; j < info.rx_tbl[i].win_size; j++) { + if (info.rx_tbl[i].buffer[j] == MTRUE) + p += sprintf(p, "1 "); + else + p += sprintf(p, "0 "); + } + p += sprintf(p, "\n"); + } + } + exit: + MODULE_PUT; + LEAVE(); + return p - page; +} + +/** + * @brief Proc write function + * + * @param f File pointer + * @param buf Pointer to data buffer + * @param cnt Data number to write + * @param data Data to write + * + * @return Number of data or MLAN_STATUS_FAILURE + */ +static int +woal_debug_write(struct file *f, const char *buf, unsigned long cnt, void *data) +{ + int r, i; + char *pdata; + char *p; + char *p0; + char *p1; + char *p2; + struct debug_data *d = ((struct debug_data_priv *) data)->items; + moal_private *priv = ((struct debug_data_priv *) data)->priv; +#ifdef DEBUG_LEVEL1 + t_u32 last_drvdbg = drvdbg; +#endif + + ENTER(); + + if (MODULE_GET == 0) { + LEAVE(); + return MLAN_STATUS_FAILURE; + } + + pdata = (char *) kmalloc(cnt, GFP_KERNEL); + if (pdata == NULL) { + MODULE_PUT; + LEAVE(); + return 0; + } + + if (copy_from_user(pdata, buf, cnt)) { + PRINTM(MERROR, "Copy from user failed\n"); + kfree(pdata); + MODULE_PUT; + LEAVE(); + return 0; + } + + if (woal_get_debug_info(priv, MOAL_PROC_WAIT, &info)) { + kfree(pdata); + MODULE_PUT; + LEAVE(); + return 0; + } + + p0 = pdata; + for (i = 0; i < ((struct debug_data_priv *) data)->num_of_items; i++) { + do { + p = strstr(p0, d[i].name); + if (p == NULL) + break; + p1 = strchr(p, '\n'); + if (p1 == NULL) + break; + p0 = p1++; + p2 = strchr(p, '='); + if (!p2) + break; + p2++; + r = woal_string_to_number(p2); + if (d[i].size == 1) + *((t_u8 *) d[i].addr) = (t_u8) r; + else if (d[i].size == 2) + *((t_u16 *) d[i].addr) = (t_u16) r; + else if (d[i].size == 4) + *((t_ptr *) d[i].addr) = (t_ptr) r; + break; + } while (MTRUE); + } + kfree(pdata); + +#ifdef DEBUG_LEVEL1 + if (last_drvdbg != drvdbg) + woal_set_drvdbg(priv, drvdbg); +#endif + + /* Set debug information */ + if (woal_set_debug_info(priv, MOAL_PROC_WAIT, &info)) { + MODULE_PUT; + LEAVE(); + return 0; + } + + MODULE_PUT; + LEAVE(); + return cnt; +} + +/******************************************************** + Global Functions +********************************************************/ +/** + * @brief Create debug proc file + * + * @param priv A pointer to a moal_private structure + * + * @return N/A + */ +void +woal_debug_entry(moal_private * priv) +{ + struct proc_dir_entry *r; + + ENTER(); + + if (priv->proc_entry == NULL) { + LEAVE(); + return; + } +#ifdef STA_SUPPORT + if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) { + priv->items_priv.items = + (struct debug_data *) kmalloc(sizeof(items), GFP_KERNEL); + if (!priv->items_priv.items) { + PRINTM(MERROR, "Failed to allocate memory for debug data\n"); + LEAVE(); + return; + } + memcpy(priv->items_priv.items, items, sizeof(items)); + priv->items_priv.num_of_items = sizeof(items) / sizeof(items[0]); + } +#endif +#ifdef UAP_SUPPORT + if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) { + priv->items_priv.items = + (struct debug_data *) kmalloc(sizeof(uap_items), GFP_KERNEL); + if (!priv->items_priv.items) { + PRINTM(MERROR, "Failed to allocate memory for debug data\n"); + LEAVE(); + return; + } + memcpy(priv->items_priv.items, uap_items, sizeof(uap_items)); + priv->items_priv.num_of_items = + sizeof(uap_items) / sizeof(uap_items[0]); + } +#endif + priv->items_priv.priv = priv; + priv->items_priv.items[priv->items_priv.num_of_items - 1].addr += + (t_ptr) (priv->phandle); + priv->items_priv.items[priv->items_priv.num_of_items - 2].addr += + (t_ptr) (priv->phandle); + priv->items_priv.items[priv->items_priv.num_of_items - 3].addr += + (t_ptr) (priv->phandle); + priv->items_priv.items[priv->items_priv.num_of_items - 4].addr += + (t_ptr) (priv->phandle); + priv->items_priv.items[priv->items_priv.num_of_items - 5].addr += + (t_ptr) (priv->phandle); + priv->items_priv.items[priv->items_priv.num_of_items - 6].addr += + (t_ptr) (priv->phandle); + priv->items_priv.items[priv->items_priv.num_of_items - 7].addr += + (t_ptr) (priv->phandle); +#ifdef SDIO_MMC_DEBUG + priv->items_priv.items[priv->items_priv.num_of_items - 8].addr += + (t_ptr) (priv->phandle); + priv->items_priv.items[priv->items_priv.num_of_items - 9].addr += + (t_ptr) (priv->phandle); +#ifdef SDIO_SUSPEND_RESUME + priv->items_priv.items[priv->items_priv.num_of_items - 10].addr += + (t_ptr) (priv->phandle); + priv->items_priv.items[priv->items_priv.num_of_items - 11].addr += + (t_ptr) (priv->phandle); +#endif +#else +#if defined(SDIO_SUSPEND_RESUME) + priv->items_priv.items[priv->items_priv.num_of_items - 8].addr += + (t_ptr) (priv->phandle); + priv->items_priv.items[priv->items_priv.num_of_items - 9].addr += + (t_ptr) (priv->phandle); +#endif +#endif + + /* Create proc entry */ + r = create_proc_entry("debug", 0644, priv->proc_entry); + if (r == NULL) { + LEAVE(); + return; + } + r->data = &priv->items_priv; + r->read_proc = woal_debug_read; + r->write_proc = woal_debug_write; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) + r->owner = THIS_MODULE; +#endif + + LEAVE(); +} + +/** + * @brief Remove proc file + * + * @param priv A pointer to a moal_private structure + * + * @return N/A + */ +void +woal_debug_remove(moal_private * priv) +{ + ENTER(); + + if (priv->items_priv.items) + kfree(priv->items_priv.items); + /* Remove proc entry */ + remove_proc_entry("debug", priv->proc_entry); + + LEAVE(); +} +#endif diff --git a/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c b/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c new file mode 100644 index 000000000000..984400cd532f --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c @@ -0,0 +1,1143 @@ +/** @file moal_eth_ioctl.c + * + * @brief This file contains private ioctl functions + * + * Copyright (C) 2012, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +/************************************************************************ +Change log: + 01/05/2012: initial version +************************************************************************/ + +#include "moal_main.h" +#include "moal_eth_ioctl.h" +#include "mlan_ioctl.h" +#if defined(STA_WEXT) || defined(UAP_WEXT) +#include "moal_priv.h" +#endif + +#if defined(STA_CFG80211) && defined(UAP_CFG80211) +#include "moal_cfg80211.h" +#endif +#ifdef UAP_SUPPORT +#include "moal_uap.h" +#endif +/******************************************************** + Local Variables +********************************************************/ + +/** Marvell private command identifier string */ +#define CMD_MARVELL "MRVL_CMD" + +/** Private command: Version */ +#define PRIV_CMD_VERSION "version" +/** Private command: Band cfg */ +#define PRIV_CMD_BANDCFG "bandcfg" +/** Private command: Host cmd */ +#define PRIV_CMD_HOSTCMD "hostcmd" +/** Private command: HT Tx Cfg */ +#define PRIV_CMD_HTTXCFG "httxcfg" +#define PRIV_CMD_DATARATE "getdatarate" +#define PRIV_CMD_TXRATECFG "txratecfg" + +/** Bands supported in Infra mode */ +static t_u8 SupportedInfraBand[] = { + BAND_B, + BAND_B | BAND_G, BAND_G, + BAND_GN, BAND_B | BAND_G | BAND_GN, BAND_G | BAND_GN, + BAND_A, BAND_B | BAND_A, BAND_B | BAND_G | BAND_A, BAND_G | BAND_A, + BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN, + BAND_A | BAND_G | BAND_AN | BAND_GN, BAND_A | BAND_AN, +}; + +/** Bands supported in Ad-Hoc mode */ +static t_u8 SupportedAdhocBand[] = { + BAND_B, BAND_B | BAND_G, BAND_G, + BAND_GN, BAND_B | BAND_G | BAND_GN, BAND_G | BAND_GN, + BAND_A, + BAND_AN, BAND_A | BAND_AN, +}; + +/******************************************************** + Global Variables +********************************************************/ + +/******************************************************** + Local Functions +********************************************************/ +/** + * @brief Parse a string to extract arguments + * + * @param pos Pointer to the arguments string + * @param data Pointer to the arguments buffer + * @param len Pointer to the number of arguments extracted + * + * @return MLAN_STATUS_SUCCESS + * + * N.B. No boundary check is done on 'data'. The caller must ensure there + * are enough space for all extracted arguments. + */ +mlan_status +parse_arguments(t_u8 * pos, int *data, int *user_data_len) +{ + unsigned int i, j, k; + char cdata[10]; + int is_hex = 0; + + memset(cdata, 0, sizeof(cdata)); + for (i = 0, j = 0, k = 0; i <= strlen(pos); i++) { + if ((k == 0) && (i <= (strlen(pos) - 2))) { + if ((pos[i] == '0') && (pos[i + 1] == 'x')) { + is_hex = 1; + i = i + 2; + } + } + if (pos[i] == '\0') { + if (is_hex) { + data[j] = woal_atox(cdata); + is_hex = 0; + } else { + woal_atoi(&data[j], cdata); + } + j++; + (*user_data_len)++; + k = 0; + memset(cdata, 0, sizeof(char) * 4); + break; + } else if (pos[i] == ' ') { + if (is_hex) { + data[j] = woal_atox(cdata); + is_hex = 0; + } else { + woal_atoi(&data[j], cdata); + } + j++; + (*user_data_len)++; + k = 0; + memset(cdata, 0, sizeof(char) * 4); + } else { + cdata[k] = pos[i]; + k++; + } + } + + return MLAN_STATUS_SUCCESS; +} + +#if defined(STA_CFG80211) && defined(UAP_CFG80211) +/** + * @brief Set wps & p2p ie in AP mode + * + * @param priv Pointer to priv stucture + * @param ie Pointer to ies data + * @param len Length of data + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + */ +mlan_status +woal_set_ap_wps_p2p_ie(moal_private * priv, t_u8 * ie, size_t len) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + t_u8 *pos = ie; + t_u32 ie_len; + + ENTER(); + + ie_len = len - 2; + if (ie_len <= 0 || ie_len > MAX_IE_SIZE) { + PRINTM(MERROR, "IE len error: %d\n", ie_len); + ret = -EFAULT; + goto done; + } + + /* Android cmd format: "SET_AP_WPS_P2P_IE 1" -- beacon IE + "SET_AP_WPS_P2P_IE 2" -- proberesp IE "SET_AP_WPS_P2P_IE 4" -- assocresp + IE */ + if (*pos == '1') { + PRINTM(MIOCTL, "Ignore set beacon ie\n"); + goto done; + } else if (*pos == '2') { + /* set the probe resp ies */ + pos += 2; + if (MLAN_STATUS_SUCCESS != woal_cfg80211_mgmt_frame_ie(priv, NULL, + 0, pos, ie_len, + NULL, 0, NULL, 0, + MGMT_MASK_PROBE_RESP)) + { + PRINTM(MERROR, "Failed to set probe resp ie\n"); + ret = -EFAULT; + goto done; + } + } else if (*pos == '4') { + /* set the assoc resp ies */ + pos += 2; + if (MLAN_STATUS_SUCCESS != woal_cfg80211_mgmt_frame_ie(priv, NULL, + 0, NULL, 0, pos, + ie_len, NULL, 0, + MGMT_MASK_ASSOC_RESP)) + { + PRINTM(MERROR, "Failed to set assoc resp ie\n"); + ret = -EFAULT; + goto done; + } + } + + done: + LEAVE(); + return ret; +} +#endif + +/** + * @brief Get Driver Version + * + * @param priv A pointer to moal_private structure + * @param respbuf A pointer to response buffer + * @param respbuflen Available length of response buffer + * + * @return Number of bytes written, negative for failure. + */ +int +woal_get_priv_driver_version(moal_private * priv, t_u8 * respbuf, + t_u32 respbuflen) +{ + int len = 0, ret = -1; + char buf[MLAN_MAX_VER_STR_LEN]; + + ENTER(); + + if (!respbuf) { + LEAVE(); + return 0; + } + + memset(buf, 0, sizeof(buf)); + + /* Get version string to local buffer */ + woal_get_version(priv->phandle, buf, sizeof(buf) - 1); + len = strlen(buf); + + if (len) { + /* Copy back the retrieved version string */ + PRINTM(MINFO, "MOAL VERSION: %s\n", buf); + ret = MIN(len, (respbuflen - 1)); + memcpy(respbuf, buf, ret); + } else { + ret = -1; + PRINTM(MERROR, "Get version failed!\n"); + } + + LEAVE(); + return ret; +} + +#ifdef WIFI_DIRECT_SUPPORT +/** + * @brief Hostcmd interface from application + * + * @param priv A pointer to moal_private structure + * @param respbuf A pointer to response buffer + * @param respbuflen Available length of response buffer + * + * @return Number of bytes written, negative for failure. + */ +int +woal_priv_hostcmd(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen) +{ + int ret = 0; + t_u8 *data_ptr; + t_u32 buf_len = 0; + HostCmd_Header cmd_header; + mlan_ioctl_req *req = NULL; + mlan_ds_misc_cfg *misc_cfg = NULL; + + ENTER(); + + data_ptr = respbuf + (strlen(CMD_MARVELL) + strlen(PRIV_CMD_HOSTCMD)); + buf_len = *((t_u32 *) data_ptr); + memcpy(&cmd_header, data_ptr + sizeof(buf_len), sizeof(HostCmd_Header)); + + PRINTM(MINFO, "Host command len = %d\n", woal_le16_to_cpu(cmd_header.size)); + if (woal_le16_to_cpu(cmd_header.size) > MLAN_SIZE_OF_CMD_BUFFER) { + LEAVE(); + return -EINVAL; + } + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto error; + } + misc_cfg = (mlan_ds_misc_cfg *) req->pbuf; + misc_cfg->sub_command = MLAN_OID_MISC_HOST_CMD; + req->req_id = MLAN_IOCTL_MISC_CFG; + req->action = MLAN_ACT_SET; + misc_cfg->param.hostcmd.len = woal_le16_to_cpu(cmd_header.size); + /* get the whole command */ + memcpy(misc_cfg->param.hostcmd.cmd, data_ptr + sizeof(buf_len), + misc_cfg->param.hostcmd.len); + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto error; + } + sprintf(respbuf, "OK"); + ret = 3; + + error: + if (req) + kfree(req); + + LEAVE(); + return ret; +} +#endif + +/** + * @brief Set/Get Band and Adhoc-band setting + * + * @param priv A pointer to moal_private structure + * @param respbuf A pointer to response buffer + * @param respbuflen Available length of response buffer + * + * @return Number of bytes written, negative for failure. + */ +int +woal_setget_priv_bandcfg(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen) +{ + int ret = 0; + unsigned int i; + int data[4]; + int user_data_len = 0; + t_u32 infra_band = 0; + t_u32 adhoc_band = 0; + t_u32 adhoc_channel = 0; + t_u32 adhoc_chan_bandwidth = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_radio_cfg *radio_cfg = NULL; + mlan_ds_band_cfg *band_cfg = NULL; + + ENTER(); + + if (strlen(respbuf) == (strlen(CMD_MARVELL) + strlen(PRIV_CMD_BANDCFG))) { + /* GET operation */ + user_data_len = 0; + } else { + /* SET operation */ + memset((char *) data, 0, sizeof(data)); + parse_arguments(respbuf + strlen(CMD_MARVELL) + + strlen(PRIV_CMD_BANDCFG), data, &user_data_len); + } + + if (sizeof(int) * user_data_len > sizeof(data)) { + PRINTM(MERROR, "Too many arguments\n"); + LEAVE(); + return -EINVAL; + } + + if (user_data_len > 0) { + if (priv->media_connected == MTRUE) { + LEAVE(); + return -EOPNOTSUPP; + } + } + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto error; + } + radio_cfg = (mlan_ds_radio_cfg *) req->pbuf; + radio_cfg->sub_command = MLAN_OID_BAND_CFG; + req->req_id = MLAN_IOCTL_RADIO_CFG; + + if (user_data_len == 0) { + /* Get config_bands, adhoc_start_band and adhoc_channel values from + MLAN */ + req->action = MLAN_ACT_GET; + } else { + /* To support only */ + infra_band = data[0]; + for (i = 0; i < sizeof(SupportedInfraBand); i++) + if (infra_band == SupportedInfraBand[i]) + break; + if (i == sizeof(SupportedInfraBand)) { + ret = -EINVAL; + goto error; + } + + /* Set Adhoc band */ + if (user_data_len >= 2) { + adhoc_band = data[1]; + for (i = 0; i < sizeof(SupportedAdhocBand); i++) + if (adhoc_band == SupportedAdhocBand[i]) + break; + if (i == sizeof(SupportedAdhocBand)) { + ret = -EINVAL; + goto error; + } + } + + /* Set Adhoc channel */ + if (user_data_len >= 3) { + adhoc_channel = data[2]; + if (adhoc_channel == 0) { + /* Check if specified adhoc channel is non-zero */ + ret = -EINVAL; + goto error; + } + } + if (user_data_len == 4) { + if (!(adhoc_band & (BAND_GN | BAND_AN))) { + PRINTM(MERROR, + "11n is not enabled for adhoc, can not set HT/VHT channel bandwidth\n"); + ret = -EINVAL; + goto error; + } + adhoc_chan_bandwidth = data[3]; + /* sanity test */ + if ((adhoc_chan_bandwidth != CHANNEL_BW_20MHZ) && + (adhoc_chan_bandwidth != CHANNEL_BW_40MHZ_ABOVE) && + (adhoc_chan_bandwidth != CHANNEL_BW_40MHZ_BELOW) + ) { + PRINTM(MERROR, + "Invalid secondary channel bandwidth, only allowed 0, 1, 3 or 4\n"); + ret = -EINVAL; + goto error; + } + + } + /* Set config_bands and adhoc_start_band values to MLAN */ + req->action = MLAN_ACT_SET; + radio_cfg->param.band_cfg.config_bands = infra_band; + radio_cfg->param.band_cfg.adhoc_start_band = adhoc_band; + radio_cfg->param.band_cfg.adhoc_channel = adhoc_channel; + radio_cfg->param.band_cfg.sec_chan_offset = adhoc_chan_bandwidth; + } + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto error; + } + + band_cfg = (mlan_ds_band_cfg *) respbuf; + + memcpy(band_cfg, &radio_cfg->param.band_cfg, sizeof(mlan_ds_band_cfg)); + + ret = sizeof(mlan_ds_band_cfg); + + error: + if (req) + kfree(req); + + LEAVE(); + return ret; +} + +/** + * @brief Set/Get 11n configurations + * + * @param priv A pointer to moal_private structure + * @param respbuf A pointer to response buffer + * @param respbuflen Available length of response buffer + * + * @return Number of bytes written, negative for failure. + */ +int +woal_setget_priv_httxcfg(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen) +{ + int data[2]; + mlan_ioctl_req *req = NULL; + mlan_ds_11n_cfg *cfg_11n = NULL; + int ret = 0; + int user_data_len = 0; + + ENTER(); + + if (strlen(respbuf) == (strlen(CMD_MARVELL) + strlen(PRIV_CMD_HTTXCFG))) { + /* GET operation */ + user_data_len = 0; + } else { + /* SET operation */ + memset((char *) data, 0, sizeof(data)); + parse_arguments(respbuf + strlen(CMD_MARVELL) + + strlen(PRIV_CMD_HTTXCFG), data, &user_data_len); + } + + if (user_data_len > 2) { + PRINTM(MERROR, "Invalid number of arguments\n"); + ret = -EINVAL; + goto done; + } + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + cfg_11n = (mlan_ds_11n_cfg *) req->pbuf; + cfg_11n->sub_command = MLAN_OID_11N_CFG_TX; + req->req_id = MLAN_IOCTL_11N_CFG; + + if (user_data_len == 0) { + /* Get 11n tx parameters from MLAN */ + req->action = MLAN_ACT_GET; + cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BG; + } else { + cfg_11n->param.tx_cfg.httxcap = data[0]; + PRINTM(MINFO, "SET: httxcap:0x%x\n", data[0]); + cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BOTH; + if (user_data_len == 2) { + if (data[1] != BAND_SELECT_BG && + data[1] != BAND_SELECT_A && data[1] != BAND_SELECT_BOTH) { + PRINTM(MERROR, "Invalid band selection\n"); + ret = -EINVAL; + goto done; + } + cfg_11n->param.tx_cfg.misc_cfg = data[1]; + PRINTM(MINFO, "SET: httxcap band:0x%x\n", data[1]); + } + /* Update 11n tx parameters in MLAN */ + req->action = MLAN_ACT_SET; + } + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + data[0] = cfg_11n->param.tx_cfg.httxcap; + + if (req->action == MLAN_ACT_GET) { + user_data_len = 1; + cfg_11n->param.tx_cfg.httxcap = 0; + cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_A; + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + if (cfg_11n->param.tx_cfg.httxcap != data[0]) { + user_data_len = 2; + data[1] = cfg_11n->param.tx_cfg.httxcap; + PRINTM(MINFO, "GET: httxcap for 2.4GHz:0x%x\n", data[0]); + PRINTM(MINFO, "GET: httxcap for 5GHz:0x%x\n", data[1]); + } else + PRINTM(MINFO, "GET: httxcap:0x%x\n", data[0]); + } + + sprintf(respbuf, "0x%x", data[0]); + ret = strlen(respbuf) + 1; + + done: + if (req) + kfree(req); + LEAVE(); + return ret; + +} + +/** + * @brief Set/Get 11AC configurations + * + * @param priv A pointer to moal_private structure + * @param respbuf A pointer to response buffer + * @param respbuflen Available length of response buffer + * + * @return Number of bytes written, negative for failure. + */ +int +woal_get_priv_datarate(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_rate *rate = NULL; + mlan_data_rate *data_rate = NULL; + int ret = 0; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + rate = (mlan_ds_rate *) req->pbuf; + rate->sub_command = MLAN_OID_GET_DATA_RATE; + req->req_id = MLAN_IOCTL_RATE; + req->action = MLAN_ACT_GET; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + data_rate = (mlan_data_rate *) respbuf; + + memcpy(data_rate, &rate->param.data_rate, sizeof(mlan_data_rate)); + + ret = sizeof(mlan_data_rate); + + done: + if (req) + kfree(req); + LEAVE(); + return ret; + +} + +/** + * @brief Set/Get tx rate configurations + * + * @param priv A pointer to moal_private structure + * @param respbuf A pointer to response buffer + * @param respbuflen Available length of response buffer + * + * @return Number of bytes written, negative for failure. + */ +int +woal_setget_priv_txratecfg(moal_private * priv, t_u8 * respbuf, + t_u32 respbuflen) +{ + t_u32 data[3]; + mlan_ioctl_req *req = NULL; + mlan_ds_rate *rate = NULL; + woal_tx_rate_cfg *ratecfg = NULL; + int ret = 0; + int user_data_len = 0; + + ENTER(); + + if (strlen(respbuf) == (strlen(CMD_MARVELL) + strlen(PRIV_CMD_TXRATECFG))) { + /* GET operation */ + user_data_len = 0; + } else { + /* SET operation */ + memset((char *) data, 0, sizeof(data)); + parse_arguments(respbuf + strlen(CMD_MARVELL) + + strlen(PRIV_CMD_TXRATECFG), data, &user_data_len); + } + + if (user_data_len >= 4) { + PRINTM(MERROR, "Invalid number of arguments\n"); + ret = -EINVAL; + goto done; + } + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + req->req_id = MLAN_IOCTL_RATE; + rate = (mlan_ds_rate *) req->pbuf; + rate->sub_command = MLAN_OID_RATE_CFG; + rate->param.rate_cfg.rate_type = MLAN_RATE_INDEX; + + if (user_data_len == 0) { + /* Get operation */ + req->action = MLAN_ACT_GET; + } else { + /* Set operation */ + req->action = MLAN_ACT_SET; + /* format */ + if ((data[0] != AUTO_RATE) && (data[0] >= 3)) { + PRINTM(MERROR, "Invalid format selection\n"); + ret = -EINVAL; + goto done; + } + if (data[0] == AUTO_RATE) { + /* auto */ + rate->param.rate_cfg.is_rate_auto = 1; + } else { + /* fixed rate */ + PRINTM(MINFO, "SET: txratefg format: 0x%x\n", data[0]); + if ((data[0] != AUTO_RATE) && (data[0] > MLAN_RATE_FORMAT_HT) + ) { + PRINTM(MERROR, "Invalid format selection\n"); + ret = -EINVAL; + goto done; + } + } + + if ((user_data_len >= 2) && (data[0] != AUTO_RATE)) { + PRINTM(MINFO, "SET: txratefg index: 0x%x\n", data[1]); + /* sanity check */ + if (((data[0] == MLAN_RATE_FORMAT_LG) && + (data[1] > MLAN_RATE_INDEX_OFDM7)) + || ((data[0] == MLAN_RATE_FORMAT_HT) && (data[1] != 32) && + (data[1] > 15)) + ) { + PRINTM(MERROR, "Invalid index selection\n"); + ret = -EINVAL; + goto done; + } + + PRINTM(MINFO, "SET: txratefg index: 0x%x\n", data[1]); + rate->param.rate_cfg.rate = data[1]; + + if (data[0] == MLAN_RATE_FORMAT_HT) { + rate->param.rate_cfg.rate = data[1] + MLAN_RATE_INDEX_MCS0; + } + } + + } + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + ratecfg = (woal_tx_rate_cfg *) respbuf; + if (rate->param.rate_cfg.is_rate_auto == MTRUE) { + ratecfg->rate_format = 0xFF; + } else { + /* fixed rate */ + if (rate->param.rate_cfg.rate < MLAN_RATE_INDEX_MCS0) { + ratecfg->rate_format = MLAN_RATE_FORMAT_LG; + ratecfg->rate_index = rate->param.rate_cfg.rate; + } else { + ratecfg->rate_format = MLAN_RATE_FORMAT_HT; + ratecfg->rate_index = + rate->param.rate_cfg.rate - MLAN_RATE_INDEX_MCS0; + } + } + + ret = sizeof(woal_tx_rate_cfg); + + done: + if (req) + kfree(req); + LEAVE(); + return ret; + +} + +/** + * @brief Set priv command for Android + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * + * @return 0 --success, otherwise fail + */ +int +woal_android_priv_cmd(struct net_device *dev, struct ifreq *req) +{ + int ret = 0; + android_wifi_priv_cmd priv_cmd; + moal_private *priv = (moal_private *) netdev_priv(dev); + char *buf = NULL; + char *pdata; +#ifdef STA_SUPPORT + int power_mode = 0; + int band = 0; + char *pband = NULL; + mlan_bss_info bss_info; + mlan_ds_get_signal signal; + mlan_rate_cfg_t rate; + t_u8 country_code[COUNTRY_CODE_LEN]; +#endif + int len = 0; + + ENTER(); + if (copy_from_user(&priv_cmd, req->ifr_data, sizeof(android_wifi_priv_cmd))) { + ret = -EFAULT; + goto done; + } + buf = kzalloc(priv_cmd.total_len, GFP_KERNEL); + if (!buf) { + PRINTM(MERROR, "%s: failed to allocate memory\n", __FUNCTION__); + ret = -ENOMEM; + goto done; + } + if (copy_from_user(buf, priv_cmd.buf, priv_cmd.total_len)) { + ret = -EFAULT; + goto done; + } + + PRINTM(MIOCTL, "Android priv cmd: [%s] on [%s]\n", buf, req->ifr_name); + + if (strncmp(buf, CMD_MARVELL, strlen(CMD_MARVELL)) == 0) { + /* This command has come from mlanutl app */ + + /* Check command */ + if (strnicmp + (buf + strlen(CMD_MARVELL), PRIV_CMD_VERSION, + strlen(PRIV_CMD_VERSION)) == 0) { + /* Get version */ + len = woal_get_priv_driver_version(priv, buf, priv_cmd.total_len); + goto handled; + } else + if (strnicmp + (buf + strlen(CMD_MARVELL), PRIV_CMD_BANDCFG, + strlen(PRIV_CMD_BANDCFG)) == 0) { + /* Set/Get band configuration */ + len = woal_setget_priv_bandcfg(priv, buf, priv_cmd.total_len); + goto handled; +#ifdef WIFI_DIRECT_SUPPORT + } else + if (strnicmp + (buf + strlen(CMD_MARVELL), PRIV_CMD_HOSTCMD, + strlen(PRIV_CMD_HOSTCMD)) == 0) { + /* hostcmd configuration */ + len = woal_priv_hostcmd(priv, buf, priv_cmd.total_len); + goto handled; +#endif + } else + if (strnicmp + (buf + strlen(CMD_MARVELL), PRIV_CMD_HTTXCFG, + strlen(PRIV_CMD_HTTXCFG)) == 0) { + /* Set/Get HT Tx configuration */ + len = woal_setget_priv_httxcfg(priv, buf, priv_cmd.total_len); + goto handled; + } else + if (strnicmp + (buf + strlen(CMD_MARVELL), PRIV_CMD_DATARATE, + strlen(PRIV_CMD_DATARATE)) == 0) { + /* Get data rate */ + len = woal_get_priv_datarate(priv, buf, priv_cmd.total_len); + goto handled; + } else + if (strnicmp + (buf + strlen(CMD_MARVELL), PRIV_CMD_TXRATECFG, + strlen(PRIV_CMD_TXRATECFG)) == 0) { + /* Set/Get tx rate cfg */ + len = woal_setget_priv_txratecfg(priv, buf, priv_cmd.total_len); + goto handled; + } else { + /* Fall through, after stripping off the custom header */ + buf += strlen(CMD_MARVELL); + } + } +#ifdef STA_SUPPORT + if (strncmp(buf, "RSSI", strlen("RSSI")) == 0) { + if (MLAN_STATUS_SUCCESS != woal_get_bss_info(priv, + MOAL_IOCTL_WAIT, + &bss_info)) { + ret = -EFAULT; + goto done; + } + if (bss_info.media_connected) { + if (MLAN_STATUS_SUCCESS != woal_get_signal_info(priv, + MOAL_IOCTL_WAIT, + &signal)) { + ret = -EFAULT; + goto done; + } + len = sprintf(buf, "%s rssi %d\n", bss_info.ssid.ssid, + signal.bcn_rssi_avg) + 1; + } else { + len = sprintf(buf, "OK\n") + 1; + } + } else if (strncmp(buf, "LINKSPEED", strlen("LINKSPEED")) == 0) { + if (MLAN_STATUS_SUCCESS != woal_set_get_data_rate(priv, MLAN_ACT_GET, + &rate)) { + ret = -EFAULT; + goto done; + } + PRINTM(MIOCTL, "tx rate=%d\n", (int) rate.rate); + len = + sprintf(buf, "LinkSpeed %d\n", (int) (rate.rate * 500000 / 1000000)) + + 1; + } else +#endif + if (strncmp(buf, "MACADDR", strlen("MACADDR")) == 0) { + len = sprintf(buf, "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n", + priv->current_addr[0], priv->current_addr[1], + priv->current_addr[2], priv->current_addr[3], + priv->current_addr[4], priv->current_addr[5]) + 1; + } +#ifdef STA_SUPPORT + else if (strncmp(buf, "GETPOWER", strlen("GETPOWER")) == 0) { + if (MLAN_STATUS_SUCCESS != woal_get_powermode(priv, &power_mode)) { + ret = -EFAULT; + goto done; + } + len = sprintf(buf, "powermode = %d\n", power_mode) + 1; + } else if (strncmp(buf, "SCAN-ACTIVE", strlen("SCAN-ACTIVE")) == 0) { + if (MLAN_STATUS_SUCCESS != woal_set_scan_type(priv, + MLAN_SCAN_TYPE_ACTIVE)) { + ret = -EFAULT; + goto done; + } + priv->scan_type = MLAN_SCAN_TYPE_ACTIVE; + PRINTM(MIOCTL, "Set Active Scan\n"); + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "SCAN-PASSIVE", strlen("SCAN-PASSIVE")) == 0) { + if (MLAN_STATUS_SUCCESS != woal_set_scan_type(priv, + MLAN_SCAN_TYPE_PASSIVE)) { + ret = -EFAULT; + goto done; + } + priv->scan_type = MLAN_SCAN_TYPE_PASSIVE; + PRINTM(MIOCTL, "Set Passive Scan\n"); + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "POWERMODE", strlen("POWERMODE")) == 0) { + pdata = buf + strlen("POWERMODE") + 1; + if (MLAN_STATUS_SUCCESS != woal_set_powermode(priv, pdata)) { + ret = -EFAULT; + goto done; + } + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "COUNTRY", strlen("COUNTRY")) == 0) { + memset(country_code, 0, sizeof(country_code)); + memcpy(country_code, buf + strlen("COUNTRY") + 1, + strlen(buf) - strlen("COUNTRY") - 1); + PRINTM(MIOCTL, "Set COUNTRY %s\n", country_code); + if (MLAN_STATUS_SUCCESS != woal_set_region_code(priv, country_code)) { + ret = -EFAULT; + goto done; + } + len = sprintf(buf, "OK\n") + 1; + } else if (memcmp(buf, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE) == 0) { + PRINTM(MIOCTL, "Set Combo Scan\n"); + if (MLAN_STATUS_SUCCESS != woal_set_combo_scan(priv, buf, + priv_cmd.total_len)) { + ret = -EFAULT; + goto done; + } + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "GETBAND", strlen("GETBAND")) == 0) { + if (MLAN_STATUS_SUCCESS != woal_get_band(priv, &band)) { + ret = -EFAULT; + goto done; + } + len = sprintf(buf, "Band %d\n", band) + 1; + } else if (strncmp(buf, "SETBAND", strlen("SETBAND")) == 0) { + pband = buf + strlen("SETBAND") + 1; + if (MLAN_STATUS_SUCCESS != woal_set_band(priv, pband)) { + ret = -EFAULT; + goto done; + } + len = sprintf(buf, "OK\n") + 1; + } +#endif + else if (strncmp(buf, "START", strlen("START")) == 0) { + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "STOP", strlen("STOP")) == 0) { + len = sprintf(buf, "OK\n") + 1; + } +#ifdef UAP_SUPPORT + else if (strncmp(buf, "AP_BSS_START", strlen("AP_BSS_START")) == 0) { + if ((ret == woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START))) + goto done; + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "AP_BSS_STOP", strlen("AP_BSS_STOP")) == 0) { + if ((ret == woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP))) + goto done; + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "AP_SET_CFG", strlen("AP_SET_CFG")) == 0) { + pdata = buf + strlen("AP_SET_CFG") + 1; + if ((ret = + woal_uap_set_ap_cfg(priv, pdata, + priv_cmd.used_len - strlen("AP_SET_CFG") - 1))) + goto done; + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "WL_FW_RELOAD", strlen("WL_FW_RELOAD")) == 0) { + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "AP_GET_STA_LIST", strlen("AP_GET_STA_LIST")) == 0) { + // TODO Add STA list support + len = sprintf(buf, "OK\n") + 1; + } +#endif + else if (strncmp(buf, "SETSUSPENDOPT", strlen("SETSUSPENDOPT")) == 0) { + /* it will be done by GUI */ + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0) { + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "BTCOEXSCAN-START", strlen("BTCOEXSCAN-START")) == + 0) { + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "BTCOEXSCAN-STOP", strlen("BTCOEXSCAN-STOP")) == 0) { + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "BTCOEXSCAN-START", strlen("BTCOEXSCAN-START")) == + 0) { + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "BTCOEXSCAN-STOP", strlen("BTCOEXSCAN-STOP")) == 0) { + len = sprintf(buf, "OK\n") + 1; + } +#ifdef STA_SUPPORT + else if (strncmp(buf, "BGSCAN-START", strlen("BGSCAN-START")) == 0) { + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "BGSCAN-CONFIG", strlen("BGSCAN-CONFIG")) == 0) { + if (MLAN_STATUS_SUCCESS != + woal_set_bg_scan(priv, buf, priv_cmd.total_len)) { + ret = -EFAULT; + goto done; + } + priv->bg_scan_start = MTRUE; + priv->bg_scan_reported = MFALSE; + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "BGSCAN-STOP", strlen("BGSCAN-STOP")) == 0) { + if (MLAN_STATUS_SUCCESS != woal_stop_bg_scan(priv)) { + ret = -EFAULT; + goto done; + } + priv->bg_scan_start = MFALSE; + priv->bg_scan_reported = MFALSE; + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "RXFILTER-START", strlen("RXFILTER-START")) == 0) { +#ifdef MEF_CFG_RX_FILTER + if ((ret = woal_set_rxfilter(priv, MTRUE))) { + goto done; + } +#endif + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "RXFILTER-STOP", strlen("RXFILTER-STOP")) == 0) { +#ifdef MEF_CFG_RX_FILTER + if ((ret = woal_set_rxfilter(priv, MFALSE))) { + goto done; + } +#endif + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "RXFILTER-ADD", strlen("RXFILTER-ADD")) == 0) { + pdata = buf + strlen("RXFILTER-ADD") + 1; + if (MLAN_STATUS_SUCCESS != woal_add_rxfilter(priv, pdata)) { + ret = -EFAULT; + goto done; + } + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "RXFILTER-REMOVE", strlen("RXFILTER-REMOVE")) == 0) { + pdata = buf + strlen("RXFILTER-REMOVE") + 1; + if (MLAN_STATUS_SUCCESS != woal_remove_rxfilter(priv, pdata)) { + ret = -EFAULT; + goto done; + } + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "QOSINFO", strlen("QOSINFO")) == 0) { + pdata = buf + strlen("QOSINFO") + 1; + if (MLAN_STATUS_SUCCESS != woal_set_qos_cfg(priv, pdata)) { + ret = -EFAULT; + goto done; + } + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "SLEEPPD", strlen("SLEEPPD")) == 0) { + pdata = buf + strlen("SLEEPPD") + 1; + if (MLAN_STATUS_SUCCESS != woal_set_sleeppd(priv, pdata)) { + ret = -EFAULT; + goto done; + } + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "SET_AP_WPS_P2P_IE", + strlen("SET_AP_WPS_P2P_IE")) == 0) { + pdata = buf + strlen("SET_AP_WPS_P2P_IE") + 1; + /* Android cmd format: "SET_AP_WPS_P2P_IE 1" -- beacon IE + "SET_AP_WPS_P2P_IE 2" -- proberesp IE "SET_AP_WPS_P2P_IE 4" -- + assocresp IE */ +#if defined(STA_CFG80211) && defined(UAP_CFG80211) + if (MLAN_STATUS_SUCCESS != woal_set_ap_wps_p2p_ie(priv, (t_u8 *) pdata, + priv_cmd.used_len - + strlen + ("SET_AP_WPS_P2P_IE") + - 1)) { + ret = -EFAULT; + goto done; + } +#endif + len = sprintf(buf, "OK\n") + 1; + } +#endif + else if (strncmp(buf, "P2P_DEV_ADDR", strlen("P2P_DEV_ADDR")) == 0) { + memset(buf, 0x0, priv_cmd.total_len); + memcpy(buf, priv->current_addr, ETH_ALEN); + len = ETH_ALEN; + } else if (strncmp(buf, ("P2P_GET_NOA"), strlen("P2P_GET_NOA")) == 0) { + /* TODO Just return '\0' */ + memset(buf, 0x0, priv_cmd.total_len); + *buf = 0; + len = 1; + } else { + PRINTM(MIOCTL, "Unknow PRIVATE command: %s, ignored\n", buf); + ret = -EFAULT; + goto done; + } + + handled: + PRINTM(MIOCTL, "PRIV Command return: %s, length=%d\n", buf, len); + + if (len > 0) { + priv_cmd.used_len = len; + if (copy_to_user(priv_cmd.buf, buf, len)) { + PRINTM(MERROR, "%s: failed to copy data to user buffer\n", + __FUNCTION__); + ret = -EFAULT; + } + } else { + ret = len; + } + + done: + if (buf) + kfree(buf); + LEAVE(); + return ret; +} + +/******************************************************** + Global Functions +********************************************************/ +/** + * @brief ioctl function - entry point + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @param cmd Command + * + * @return 0 --success, otherwise fail + */ +int +woal_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd) +{ + int ret = 0; + + ENTER(); + + PRINTM(MINFO, "woal_do_ioctl: ioctl cmd = 0x%x\n", cmd); + switch (cmd) { +#ifdef WIFI_DIRECT_SUPPORT + case WOAL_WIFIDIRECT_HOST_CMD: + ret = woal_hostcmd_ioctl(dev, req); + break; +#endif + case WOAL_CUSTOM_IE_CFG: + ret = woal_custom_ie_ioctl(dev, req); + break; + case WOAL_MGMT_FRAME_TX: + ret = woal_send_host_packet(dev, req); + break; + case WOAL_ANDROID_PRIV_CMD: + ret = woal_android_priv_cmd(dev, req); + break; + case WOAL_GET_BSS_TYPE: + ret = woal_get_bss_type(dev, req); + break; + default: +#if defined(STA_WEXT) +#ifdef STA_SUPPORT + ret = woal_wext_do_ioctl(dev, req, cmd); +#else + ret = -EINVAL; +#endif +#else + ret = -EINVAL; +#endif + break; + } + + LEAVE(); + return ret; +} diff --git a/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.h b/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.h new file mode 100644 index 000000000000..a1481e88ff21 --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.h @@ -0,0 +1,69 @@ +/** @file moal_eth_ioctl.h + * + * @brief This file contains definition for private IOCTL call. + * + * Copyright (C) 2012, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +/******************************************************** +Change log: + 01/05/2012: initial version +********************************************************/ + +#ifndef _WOAL_ETH_PRIV_H_ +#define _WOAL_ETH_PRIV_H_ + +#ifdef WIFI_DIRECT_SUPPORT +/** Private command ID to Host command */ +#define WOAL_WIFIDIRECT_HOST_CMD (SIOCDEVPRIVATE + 1) +#endif + +/** Private command ID to pass mgmt frame */ +#define WOAL_MGMT_FRAME_TX WOAL_MGMT_FRAME_TX_IOCTL + +/** Private command ID to pass custom IE list */ +#define WOAL_CUSTOM_IE_CFG (SIOCDEVPRIVATE + 13) + +/** Private command ID for Android ICS priv CMDs */ +#define WOAL_ANDROID_PRIV_CMD (SIOCDEVPRIVATE + 14) + +/** Private command ID to get BSS type */ +#define WOAL_GET_BSS_TYPE (SIOCDEVPRIVATE + 15) + +int woal_do_ioctl(struct net_device *dev, struct ifreq *req, int i); + +typedef struct _android_wifi_priv_cmd +{ + char *buf; + int used_len; + int total_len; +} android_wifi_priv_cmd; + +/** data structure for cmd txratecfg */ +typedef struct woal_priv_tx_rate_cfg +{ + /* LG rate: 0, HT rate: 1, VHT rate: 2 */ + t_u32 rate_format; + /** Rate/MCS index (0xFF: auto) */ + t_u32 rate_index; +} woal_tx_rate_cfg; + +mlan_status woal_set_ap_wps_p2p_ie(moal_private * priv, t_u8 * ie, size_t len); + +int woal_android_priv_cmd(struct net_device *dev, struct ifreq *req); + +#endif /* _WOAL_ETH_PRIV_H_ */ diff --git a/drivers/net/wireless/sd8797/mlinux/moal_ioctl.c b/drivers/net/wireless/sd8797/mlinux/moal_ioctl.c new file mode 100644 index 000000000000..7928d37ad015 --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/moal_ioctl.c @@ -0,0 +1,4307 @@ +/** @file moal_ioctl.c + * + * @brief This file contains ioctl function to MLAN + * + * Copyright (C) 2008-2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +/******************************************************** +Change log: + 10/21/2008: initial version +********************************************************/ + +#include "moal_main.h" +#include "moal_eth_ioctl.h" +#include "moal_sdio.h" +#ifdef UAP_SUPPORT +#include "moal_uap.h" +#endif + +#if defined(STA_CFG80211) || defined(UAP_CFG80211) +#include "moal_cfg80211.h" +#endif + +/******************************************************** + Local Variables +********************************************************/ +/* CAC Measure report default time 60 seconds */ +#define MEAS_REPORT_TIME 60*HZ +#define MRVL_TLV_HEADER_SIZE 4 +/* Marvell Channel config TLV ID */ +#define MRVL_CHANNELCONFIG_TLV_ID (0x0100 + 0x2a) // 0x012a + +typedef struct _hostcmd_header +{ + /** Command Header : Command */ + t_u16 command; + /** Command Header : Size */ + t_u16 size; + /** Command Header : Sequence number */ + t_u16 seq_num; + /** Command Header : Result */ + t_u16 result; + /** Command action */ + t_u16 action; +} hostcmd_header, *phostcmd_header; + +#ifdef STA_SUPPORT +/** Region code mapping */ +typedef struct _region_code_mapping_t +{ + /** Region */ + t_u8 region[COUNTRY_CODE_LEN]; + /** Code */ + t_u8 code; +} region_code_mapping_t; + +/** Region code mapping table */ +static region_code_mapping_t region_code_mapping[] = { + {"US ", 0x10}, /* US FCC */ + {"CA ", 0x20}, /* IC Canada */ + {"SG ", 0x10}, /* Singapore */ + {"EU ", 0x30}, /* ETSI */ + {"AU ", 0x30}, /* Australia */ + {"KR ", 0x30}, /* Republic Of Korea */ + {"FR ", 0x32}, /* France */ + {"CN ", 0x50}, /* China */ + {"JP ", 0xFF}, /* Japan special */ +}; +#endif + +/******************************************************** + Global Variables +********************************************************/ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) +#ifdef UAP_SUPPORT +/** Network device handlers for uAP */ +extern const struct net_device_ops woal_uap_netdev_ops; +#endif +#ifdef STA_SUPPORT +/** Network device handlers for STA */ +extern const struct net_device_ops woal_netdev_ops; +#endif +#endif +extern int cfg80211_wext; + +/******************************************************** + Local Functions +********************************************************/ +#ifdef STA_SUPPORT +/** + * @brief This function converts region string to region code + * + * @param region_string Region string + * + * @return Region code + */ +static t_u8 +region_string_2_region_code(char *region_string) +{ + t_u8 i; + t_u8 size = sizeof(region_code_mapping) / sizeof(region_code_mapping_t); + + ENTER(); + for (i = 0; i < size; i++) { + if (!memcmp(region_string, + region_code_mapping[i].region, strlen(region_string))) { + LEAVE(); + return (region_code_mapping[i].code); + } + } + /* Default is US */ + LEAVE(); + return (region_code_mapping[0].code); +} +#endif + +/** + * @brief Copy multicast table + * + * @param mlist A pointer to mlan_multicast_list structure + * @param dev A pointer to net_device structure + * + * @return Number of multicast addresses + */ +static inline int +woal_copy_mcast_addr(mlan_multicast_list * mlist, struct net_device *dev) +{ + int i = 0; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) + struct dev_mc_list *mcptr = dev->mc_list; +#else + struct netdev_hw_addr *mcptr = NULL; +#endif /* < 2.6.35 */ + + ENTER(); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) + for (i = 0; i < dev->mc_count && mcptr; i++) { + memcpy(&mlist->mac_list[i], mcptr->dmi_addr, ETH_ALEN); + mcptr = mcptr->next; + } +#else + netdev_for_each_mc_addr(mcptr, dev) + memcpy(&mlist->mac_list[i++], mcptr->addr, ETH_ALEN); +#endif /* < 2.6.35 */ + LEAVE(); + return i; +} + +/** + * @brief Fill in wait queue + * + * @param priv A pointer to moal_private structure + * @param wait A pointer to wait_queue structure + * @param wait_option Wait option + * + * @return N/A + */ +static inline void +woal_fill_wait_queue(moal_private * priv, wait_queue * wait, t_u8 wait_option) +{ + ENTER(); + wait->start_time = jiffies; + wait->condition = MFALSE; + switch (wait_option) { + case MOAL_NO_WAIT: + break; + case MOAL_IOCTL_WAIT: + wait->wait = &priv->ioctl_wait_q; + break; + case MOAL_CMD_WAIT: + wait->wait = &priv->cmd_wait_q; + break; + case MOAL_PROC_WAIT: + wait->wait = &priv->proc_wait_q; + break; +#if defined(STA_WEXT) || defined(UAP_WEXT) + case MOAL_WSTATS_WAIT: + if (IS_STA_OR_UAP_WEXT(cfg80211_wext)) + wait->wait = &priv->w_stats_wait_q; + break; +#endif + } + LEAVE(); + return; +} + +/** + * @brief Wait mlan ioctl complete + * + * @param priv A pointer to moal_private structure + * @param req A pointer to mlan_ioctl_req structure + * @param wait_option Wait option + * + * @return N/A + */ +static inline void +woal_wait_ioctl_complete(moal_private * priv, mlan_ioctl_req * req, + t_u8 wait_option) +{ + mlan_status status; + wait_queue *wait = (wait_queue *) req->reserved_1; + + ENTER(); + + switch (wait_option) { + case MOAL_NO_WAIT: + break; + case MOAL_IOCTL_WAIT: + wait_event_interruptible(priv->ioctl_wait_q, wait->condition); + break; + case MOAL_CMD_WAIT: + wait_event_interruptible(priv->cmd_wait_q, wait->condition); + break; + case MOAL_PROC_WAIT: + wait_event_interruptible(priv->proc_wait_q, wait->condition); + break; +#if defined(STA_WEXT) || defined(UAP_WEXT) + case MOAL_WSTATS_WAIT: + if (IS_STA_OR_UAP_WEXT(cfg80211_wext)) + wait_event_interruptible(priv->w_stats_wait_q, wait->condition); + break; +#endif + } + if (wait->condition == MFALSE) { + req->action = MLAN_ACT_CANCEL; + status = mlan_ioctl(priv->phandle->pmlan_adapter, req); + PRINTM(MIOCTL, + "IOCTL cancel: id=0x%x, sub_id=0x%x, wait_option=%d, action=%d, status=%d\n", + req->req_id, (*(t_u32 *) req->pbuf), wait_option, + (int) req->action, status); + } + LEAVE(); + return; +} + +/** + * @brief CAC period block cmd handler + * + * @param priv A pointer to moal_private structure + * @param req A pointer to mlan_ioctl_req buffer + * + * @return MTRUE/MFALSE + */ +static inline t_bool +woal_cac_period_block_cmd(moal_private * priv, pmlan_ioctl_req req) +{ + mlan_status ret = MFALSE; + t_u32 sub_command; + + ENTER(); + if (req == NULL || req->pbuf == NULL) { + goto done; + } + + sub_command = *(t_u32 *) req->pbuf; + + switch (req->req_id) { + case MLAN_IOCTL_SCAN: + if (sub_command == MLAN_OID_SCAN_NORMAL || + sub_command == MLAN_OID_SCAN_SPECIFIC_SSID || + sub_command == MLAN_OID_SCAN_USER_CONFIG) { + ret = MTRUE; + } + break; + case MLAN_IOCTL_BSS: + if (sub_command == MLAN_OID_BSS_STOP || +#ifdef UAP_SUPPORT + sub_command == MLAN_OID_UAP_BSS_CONFIG || +#endif + sub_command == MLAN_OID_BSS_CHANNEL + /* sub_command == MLAN_OID_BSS_ROLE */ ) { + ret = MTRUE; + } + break; + case MLAN_IOCTL_RADIO_CFG: + if (sub_command == MLAN_OID_BAND_CFG) { + ret = MTRUE; + } + break; +#if defined(UAP_SUPPORT) + case MLAN_IOCTL_SNMP_MIB: + if (sub_command == MLAN_OID_SNMP_MIB_DOT11D || + sub_command == MLAN_OID_SNMP_MIB_DOT11H) { + ret = MTRUE; + } + break; +#endif + case MLAN_IOCTL_11D_CFG: +#ifdef STA_SUPPORT + if (sub_command == MLAN_OID_11D_CFG_ENABLE) { + ret = MTRUE; + } +#endif + if (sub_command == MLAN_OID_11D_DOMAIN_INFO) { + ret = MTRUE; + } + break; + case MLAN_IOCTL_MISC_CFG: + if (sub_command == MLAN_OID_MISC_REGION) { + ret = MTRUE; + } + if (sub_command == MLAN_OID_MISC_HOST_CMD) { + phostcmd_header phostcmd; + t_u8 *ptlv_buf; + t_u16 tag, length; + + phostcmd = + (phostcmd_header) ((pmlan_ds_misc_cfg) req->pbuf)->param. + hostcmd.cmd; + ptlv_buf = (t_u8 *) phostcmd + sizeof(hostcmd_header); + if (phostcmd->action == MLAN_ACT_SET) { + while (ptlv_buf < (t_u8 *) phostcmd + phostcmd->size) { + tag = *(t_u16 *) ptlv_buf; + length = *(t_u16 *) (ptlv_buf + 2); + /* Check Blocking TLV here, should add more... */ + if (tag == MRVL_CHANNELCONFIG_TLV_ID) { + ret = MTRUE; + break; + } + ptlv_buf += (length + MRVL_TLV_HEADER_SIZE); + } + } + } + break; + case MLAN_IOCTL_11H_CFG: + /* Prevent execute more than once */ + if (sub_command == MLAN_OID_11H_CHANNEL_CHECK) { + ret = MTRUE; + } + break; + default: + ret = MFALSE; + break; + } + + done: + LEAVE(); + return ret; +} + +/******************************************************** + Global Functions +********************************************************/ + +/** + * @brief Send ioctl request to MLAN + * + * @param priv A pointer to moal_private structure + * @param req A pointer to mlan_ioctl_req buffer + * @param wait_option Wait option (MOAL_WAIT or MOAL_NO_WAIT) + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_request_ioctl(moal_private * priv, mlan_ioctl_req * req, t_u8 wait_option) +{ + wait_queue *wait; + mlan_status status; + + ENTER(); + + if (priv->phandle->surprise_removed == MTRUE) { + PRINTM(MERROR, + "IOCTL is not allowed while the device is not present\n"); + LEAVE(); + return MLAN_STATUS_FAILURE; + } +#if defined(SDIO_SUSPEND_RESUME) + if (priv->phandle->is_suspended == MTRUE) { + PRINTM(MERROR, "IOCTL is not allowed while suspended\n"); + LEAVE(); + return MLAN_STATUS_FAILURE; + } +#endif + + /* For MLAN_OID_MISC_HOST_CMD, action is 0, "action set" is checked later */ + if ((req->action == MLAN_ACT_SET || req->action == 0) && + priv->phandle->cac_period == MTRUE) { + t_u32 sub_command; + /* CAC checking period left to complete jiffies */ + unsigned long cac_left_jiffies; + + sub_command = *(t_u32 *) req->pbuf; + + /* cac_left_jiffies will be negative if and only if * event + MLAN_EVENT_ID_DRV_MEAS_REPORT recieved from FW * after CAC measure + period ends, * usually this could be considered as a FW bug */ + cac_left_jiffies = MEAS_REPORT_TIME - + (jiffies - priv->phandle->meas_start_jiffies); +#ifdef DFS_TESTING_SUPPORT + if (priv->phandle->cac_period_jiffies) { + cac_left_jiffies = priv->phandle->cac_period_jiffies - + (jiffies - priv->phandle->meas_start_jiffies); + } +#endif + if (cac_left_jiffies < 0) { + /* Avoid driver hang in FW died during CAC measure period */ + priv->phandle->cac_period = MFALSE; + PRINTM(MERROR, + "CAC measure period spends longer than scheduled time " + "or meas done event never received\n"); + status = MLAN_STATUS_FAILURE; + goto done; + } + + /* Check BSS START first */ + if (sub_command == MLAN_OID_BSS_START) { + mlan_ds_bss *bss; + bss = (mlan_ds_bss *) req->pbuf; + /* + * Bss delay start after channel report received, + * not block the driver by delay executing. This is + * because a BSS_START cmd is always executed right + * after channel check issued. + */ + if (priv->phandle->delay_bss_start == MFALSE) { + PRINTM(MMSG, "Received BSS Start command during CAC period, " + "delay executing %ld seconds\n", cac_left_jiffies / HZ); + priv->phandle->delay_bss_start = MTRUE; + memcpy(&priv->phandle->delay_ssid_bssid, + &bss->param.ssid_bssid, sizeof(mlan_ssid_bssid)); + /* TODO: return success to allow the half below of routines of + which calling BSS start to execute */ + status = MLAN_STATUS_SUCCESS; + goto done; + } else { + /* TODO: not blocking it, just return failure */ + PRINTM(MMSG, "Only one BSS Start command allowed for delay " + "executing!\n"); + status = MLAN_STATUS_FAILURE; + goto done; + } + } + if (woal_cac_period_block_cmd(priv, req)) { + priv->phandle->meas_wait_q_woken = MFALSE; + PRINTM(MMSG, "CAC check is on going... Blocking Command" + " %ld seconds\n", cac_left_jiffies / HZ); + /* blocking timeout set to 1.5 * CAC checking period left time */ + wait_event_interruptible_timeout(priv->phandle->meas_wait_q, + priv->phandle->meas_wait_q_woken, + cac_left_jiffies * 3 / 2); + } + } else if (priv->phandle->cac_period) { + PRINTM(MINFO, "Operation during CAC check period.\n"); + } + wait = (wait_queue *) req->reserved_1; + req->bss_index = priv->bss_index; + if (wait_option) + woal_fill_wait_queue(priv, wait, wait_option); + else + req->reserved_1 = 0; + + /* Call MLAN ioctl handle */ + status = mlan_ioctl(priv->phandle->pmlan_adapter, req); + switch (status) { + case MLAN_STATUS_PENDING: + PRINTM(MIOCTL, + "IOCTL pending: %p id=0x%x, sub_id=0x%x wait_option=%d, action=%d\n", + req, req->req_id, (*(t_u32 *) req->pbuf), wait_option, + (int) req->action); + atomic_inc(&priv->phandle->ioctl_pending); + /* Status pending, wake up main process */ + queue_work(priv->phandle->workqueue, &priv->phandle->main_work); + + /* Wait for completion */ + if (wait_option) { + woal_wait_ioctl_complete(priv, req, wait_option); + status = wait->status; + } + break; + case MLAN_STATUS_SUCCESS: + case MLAN_STATUS_FAILURE: + case MLAN_STATUS_RESOURCE: + PRINTM(MIOCTL, + "IOCTL: %p id=0x%x, sub_id=0x%x wait_option=%d, action=%d status=%d\n", + req, req->req_id, (*(t_u32 *) req->pbuf), wait_option, + (int) req->action, status); + default: + break; + } + done: + LEAVE(); + return status; +} + +/** + * @brief Send set MAC address request to MLAN + * + * @param priv A pointer to moal_private structure + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_request_set_mac_address(moal_private * priv) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_bss *bss = NULL; + mlan_status status; + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + if (req == NULL) { + status = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill request buffer */ + bss = (mlan_ds_bss *) req->pbuf; + bss->sub_command = MLAN_OID_BSS_MAC_ADDR; + memcpy(&bss->param.mac_addr, priv->current_addr, + sizeof(mlan_802_11_mac_addr)); + req->req_id = MLAN_IOCTL_BSS; + req->action = MLAN_ACT_SET; + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, MOAL_CMD_WAIT); + if (status == MLAN_STATUS_SUCCESS) { + memcpy(priv->netdev->dev_addr, priv->current_addr, ETH_ALEN); +#if defined(STA_CFG80211) || defined(UAP_CFG80211) + if (IS_STA_OR_UAP_CFG80211(cfg80211_wext) && priv->wdev && + priv->wdev->wiphy) + memcpy(priv->wdev->wiphy->perm_addr, priv->current_addr, ETH_ALEN); +#endif + HEXDUMP("priv->MacAddr:", priv->current_addr, ETH_ALEN); + } else { + PRINTM(MERROR, "set mac address failed! status=%d, error_code=0x%x\n", + status, req->status_code); + } + done: + if (req) + kfree(req); + LEAVE(); + return status; +} + +/** + * @brief Send multicast list request to MLAN + * + * @param priv A pointer to moal_private structure + * @param dev A pointer to net_device structure + * + * @return N/A + */ +void +woal_request_set_multicast_list(moal_private * priv, struct net_device *dev) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_bss *bss = NULL; + mlan_status status; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) + int mc_count = dev->mc_count; +#else + int mc_count = netdev_mc_count(dev); +#endif + + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + if (req == NULL) { + PRINTM(MERROR, "%s:Fail to allocate ioctl req buffer\n", __FUNCTION__); + goto done; + } + + /* Fill request buffer */ + bss = (mlan_ds_bss *) req->pbuf; + bss->sub_command = MLAN_OID_BSS_MULTICAST_LIST; + req->req_id = MLAN_IOCTL_BSS; + req->action = MLAN_ACT_SET; + if (dev->flags & IFF_PROMISC) { + bss->param.multicast_list.mode = MLAN_PROMISC_MODE; + } else if (dev->flags & IFF_ALLMULTI || + mc_count > MLAN_MAX_MULTICAST_LIST_SIZE) { + bss->param.multicast_list.mode = MLAN_ALL_MULTI_MODE; + } else { + bss->param.multicast_list.mode = MLAN_MULTICAST_MODE; + if (mc_count) + bss->param.multicast_list.num_multicast_addr = + woal_copy_mcast_addr(&bss->param.multicast_list, dev); + } + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, MOAL_NO_WAIT); + if (status != MLAN_STATUS_PENDING) + kfree(req); + done: + LEAVE(); + return; +} + +/** + * @brief Send deauth command to MLAN + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * @param mac MAC address to deauthenticate + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_disconnect(moal_private * priv, t_u8 wait_option, t_u8 * mac) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_bss *bss = NULL; + mlan_status status; + + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + if (req == NULL) { + status = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill request buffer */ + bss = (mlan_ds_bss *) req->pbuf; + bss->sub_command = MLAN_OID_BSS_STOP; + if (mac) + memcpy((t_u8 *) & bss->param.bssid, mac, sizeof(mlan_802_11_mac_addr)); + req->req_id = MLAN_IOCTL_BSS; + req->action = MLAN_ACT_SET; + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, wait_option); + + done: + if (req) + kfree(req); +#ifdef REASSOCIATION + priv->reassoc_required = MFALSE; +#endif /* REASSOCIATION */ + LEAVE(); + return status; +} + +/** + * @brief Send bss_start command to MLAN + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * @param ssid_bssid A point to mlan_ssid_bssid structure + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_bss_start(moal_private * priv, t_u8 wait_option, + mlan_ssid_bssid * ssid_bssid) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_bss *bss = NULL; + mlan_status status; + + ENTER(); + + /* Stop the O.S. TX queue if needed */ + woal_stop_queue(priv->netdev); + + /* Allocate an IOCTL request buffer */ + req = (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + if (req == NULL) { + status = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill request buffer */ + bss = (mlan_ds_bss *) req->pbuf; + bss->sub_command = MLAN_OID_BSS_START; + if (ssid_bssid) + memcpy(&bss->param.ssid_bssid, ssid_bssid, sizeof(mlan_ssid_bssid)); + req->req_id = MLAN_IOCTL_BSS; + req->action = MLAN_ACT_SET; + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, wait_option); + + done: + if (req) + kfree(req); + LEAVE(); + return status; +} + +/** + * @brief Get BSS info + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * @param bss_info A pointer to mlan_bss_info structure + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_get_bss_info(moal_private * priv, t_u8 wait_option, + mlan_bss_info * bss_info) +{ + int ret = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_get_info *info = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + info = (mlan_ds_get_info *) req->pbuf; + info->sub_command = MLAN_OID_GET_BSS_INFO; + req->req_id = MLAN_IOCTL_GET_INFO; + req->action = MLAN_ACT_GET; + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, wait_option); + if (status == MLAN_STATUS_SUCCESS) { + if (bss_info) { + memcpy(bss_info, &info->param.bss_info, sizeof(mlan_bss_info)); + } + } + done: + if (req && (status != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return status; +} + +#ifdef STA_SUPPORT +/** + * @brief Set/Get retry count + * + * @param priv A pointer to moal_private structure + * @param action Action set or get + * @param wait_option Wait option + * @param value Retry value + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_set_get_retry(moal_private * priv, t_u32 action, + t_u8 wait_option, int *value) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_snmp_mib *mib = NULL; + mlan_status ret = MLAN_STATUS_SUCCESS; + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib)); + if (req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill request buffer */ + mib = (mlan_ds_snmp_mib *) req->pbuf; + mib->sub_command = MLAN_OID_SNMP_MIB_RETRY_COUNT; + req->req_id = MLAN_IOCTL_SNMP_MIB; + req->action = action; + + if (action == MLAN_ACT_SET) { + if (*value < MLAN_TX_RETRY_MIN || *value > MLAN_TX_RETRY_MAX) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + mib->param.retry_count = *value; + } + + /* Send IOCTL request to MLAN */ + ret = woal_request_ioctl(priv, req, wait_option); + if (ret == MLAN_STATUS_SUCCESS && action == MLAN_ACT_GET) { + *value = mib->param.retry_count; + } +#ifdef STA_CFG80211 + /* If set is invoked from other than iw i.e iwconfig, wiphy retry count + should be updated as well */ + if (IS_STA_CFG80211(cfg80211_wext) && + (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && (action == MLAN_ACT_SET)) { + priv->wdev->wiphy->retry_long = (t_u8) * value; + priv->wdev->wiphy->retry_short = (t_u8) * value; + } +#endif + + done: + if (req && (ret != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Set/Get RTS threshold + * + * @param priv A pointer to moal_private structure + * @param action Action set or get + * @param wait_option Wait option + * @param value RTS threshold value + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_set_get_rts(moal_private * priv, t_u32 action, + t_u8 wait_option, int *value) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_snmp_mib *mib = NULL; + mlan_status ret = MLAN_STATUS_SUCCESS; + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib)); + if (req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill request buffer */ + mib = (mlan_ds_snmp_mib *) req->pbuf; + mib->sub_command = MLAN_OID_SNMP_MIB_RTS_THRESHOLD; + req->req_id = MLAN_IOCTL_SNMP_MIB; + req->action = action; + + if (action == MLAN_ACT_SET) { + if (*value < MLAN_RTS_MIN_VALUE || *value > MLAN_RTS_MAX_VALUE) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + mib->param.rts_threshold = *value; + } + + /* Send IOCTL request to MLAN */ + ret = woal_request_ioctl(priv, req, wait_option); + if (ret == MLAN_STATUS_SUCCESS && action == MLAN_ACT_GET) { + *value = mib->param.rts_threshold; + } +#ifdef STA_CFG80211 + /* If set is invoked from other than iw i.e iwconfig, wiphy RTS threshold + should be updated as well */ + if (IS_STA_CFG80211(cfg80211_wext) && + (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && (action == MLAN_ACT_SET)) + priv->wdev->wiphy->rts_threshold = *value; +#endif + + done: + if (req && (ret != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Set/Get Fragment threshold + * + * @param priv A pointer to moal_private structure + * @param action Action set or get + * @param wait_option Wait option + * @param value Fragment threshold value + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_set_get_frag(moal_private * priv, t_u32 action, + t_u8 wait_option, int *value) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_snmp_mib *mib = NULL; + mlan_status ret = MLAN_STATUS_SUCCESS; + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib)); + if (req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill request buffer */ + mib = (mlan_ds_snmp_mib *) req->pbuf; + mib->sub_command = MLAN_OID_SNMP_MIB_FRAG_THRESHOLD; + req->req_id = MLAN_IOCTL_SNMP_MIB; + req->action = action; + + if (action == MLAN_ACT_SET) { + if (*value < MLAN_FRAG_MIN_VALUE || *value > MLAN_FRAG_MAX_VALUE) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + mib->param.frag_threshold = *value; + } + + /* Send IOCTL request to MLAN */ + ret = woal_request_ioctl(priv, req, wait_option); + if (ret == MLAN_STATUS_SUCCESS && action == MLAN_ACT_GET) { + *value = mib->param.frag_threshold; + } +#ifdef STA_CFG80211 + /* If set is invoked from other than iw i.e iwconfig, wiphy fragment + threshold should be updated as well */ + if (IS_STA_CFG80211(cfg80211_wext) && + (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && (action == MLAN_ACT_SET)) + priv->wdev->wiphy->frag_threshold = *value; +#endif + + done: + if (req && (ret != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Set/Get generic IE + * + * @param priv A pointer to moal_private structure + * @param action Action set or get + * @param ie Information element + * @param ie_len Length of the IE + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + */ +mlan_status +woal_set_get_gen_ie(moal_private * priv, t_u32 action, t_u8 * ie, int *ie_len) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_ds_misc_cfg *misc = NULL; + mlan_ioctl_req *req = NULL; + + ENTER(); + + if ((action == MLAN_ACT_GET) && (ie == NULL || ie_len == NULL)) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + if (action == MLAN_ACT_SET && *ie_len > MAX_IE_SIZE) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + misc = (mlan_ds_misc_cfg *) req->pbuf; + misc->sub_command = MLAN_OID_MISC_GEN_IE; + req->req_id = MLAN_IOCTL_MISC_CFG; + req->action = action; + misc->param.gen_ie.type = MLAN_IE_TYPE_GEN_IE; + + if (action == MLAN_ACT_SET) { + misc->param.gen_ie.len = *ie_len; + if (*ie_len) + memcpy(misc->param.gen_ie.ie_data, ie, *ie_len); + } + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + if (action == MLAN_ACT_GET) { + *ie_len = misc->param.gen_ie.len; + if (*ie_len) + memcpy(ie, misc->param.gen_ie.ie_data, *ie_len); + } + + done: + if (req) + kfree(req); + + LEAVE(); + return ret; +} + +/** + * @brief Set/Get TX power + * + * @param priv A pointer to moal_private structure + * @param action Action set or get + * @param power_cfg A pinter to mlan_power_cfg_t structure + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_set_get_tx_power(moal_private * priv, + t_u32 action, mlan_power_cfg_t * power_cfg) +{ + mlan_ds_power_cfg *pcfg = NULL; + mlan_ioctl_req *req = NULL; + mlan_status ret = MLAN_STATUS_SUCCESS; + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_power_cfg)); + if (req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + pcfg = (mlan_ds_power_cfg *) req->pbuf; + pcfg->sub_command = MLAN_OID_POWER_CFG; + req->req_id = MLAN_IOCTL_POWER_CFG; + req->action = action; + if (action == MLAN_ACT_SET && power_cfg) + memcpy(&pcfg->param.power_cfg, power_cfg, sizeof(mlan_power_cfg_t)); + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) + ret = MLAN_STATUS_FAILURE; + + if (ret == MLAN_STATUS_SUCCESS && power_cfg) + memcpy(power_cfg, &pcfg->param.power_cfg, sizeof(mlan_power_cfg_t)); + + done: + if (req && (ret != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Set/Get IEEE power management + * + * @param priv A pointer to moal_private structure + * @param action Action set or get + * @param disabled A pointer to disabled flag + * @param power_type IEEE power type + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + */ +mlan_status +woal_set_get_power_mgmt(moal_private * priv, + t_u32 action, int *disabled, int power_type) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_ioctl_req *req = NULL; + mlan_ds_pm_cfg *pm_cfg = NULL; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg)); + if (req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + pm_cfg = (mlan_ds_pm_cfg *) req->pbuf; + pm_cfg->sub_command = MLAN_OID_PM_CFG_IEEE_PS; + req->req_id = MLAN_IOCTL_PM_CFG; + req->action = action; + + if (action == MLAN_ACT_SET) { + PRINTM(MINFO, "PS_MODE set power disabled=%d power type=%#x\n", + *disabled, power_type); + if (*disabled) + pm_cfg->param.ps_mode = 0; + else { + /* Check not support case only (vwrq->disabled == FALSE) */ + if ((power_type & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { + PRINTM(MERROR, "Setting power timeout is not supported\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } else if ((power_type & IW_POWER_TYPE) == IW_POWER_PERIOD) { + PRINTM(MERROR, "Setting power period is not supported\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + pm_cfg->param.ps_mode = 1; + } + } + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + if (ret == MLAN_STATUS_SUCCESS && action == MLAN_ACT_GET) + *disabled = pm_cfg->param.ps_mode; + +#ifdef STA_CFG80211 + /* If set is invoked from other than iw i.e iwconfig, wiphy IEEE power save + mode should be updated */ + if (IS_STA_CFG80211(cfg80211_wext) && + (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && (action == MLAN_ACT_SET)) { + if (*disabled) + priv->wdev->ps = MFALSE; + else + priv->wdev->ps = MTRUE; + } +#endif + + done: + if (req) + kfree(req); + + LEAVE(); + return ret; +} + +/** + * @brief Set region code + * + * @param priv A pointer to moal_private structure + * @param region A pointer to region string + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail + */ +mlan_status +woal_set_region_code(moal_private * priv, char *region) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_ds_misc_cfg *cfg = NULL; + mlan_ioctl_req *req = NULL; + + ENTER(); + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + cfg = (mlan_ds_misc_cfg *) req->pbuf; + cfg->sub_command = MLAN_OID_MISC_REGION; + req->req_id = MLAN_IOCTL_MISC_CFG; + req->action = MLAN_ACT_SET; + cfg->param.region_code = region_string_2_region_code(region); + ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Set/Get data rate + * + * @param priv A pointer to moal_private structure + * @param action Action set or get + * @param datarate A pointer to mlan_rate_cfg_t structure + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + */ +mlan_status +woal_set_get_data_rate(moal_private * priv, + t_u8 action, mlan_rate_cfg_t * datarate) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_ds_rate *rate = NULL; + mlan_ioctl_req *req = NULL; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate)); + if (req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + rate = (mlan_ds_rate *) req->pbuf; + rate->param.rate_cfg.rate_type = MLAN_RATE_VALUE; + rate->sub_command = MLAN_OID_RATE_CFG; + req->req_id = MLAN_IOCTL_RATE; + req->action = action; + + if (datarate && (action == MLAN_ACT_SET)) + memcpy(&rate->param.rate_cfg, datarate, sizeof(mlan_rate_cfg_t)); + + if (MLAN_STATUS_SUCCESS == woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + if (datarate && (action == MLAN_ACT_GET)) + memcpy(datarate, &rate->param.rate_cfg, sizeof(mlan_rate_cfg_t)); + } else { + ret = MLAN_STATUS_FAILURE; + } + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} +#endif + +/** + * @brief Send get FW info request to MLAN + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * @param fw_info FW information + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_request_get_fw_info(moal_private * priv, t_u8 wait_option, + mlan_fw_info * fw_info) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_get_info *info; + mlan_status status; + ENTER(); + memset(priv->current_addr, 0xff, ETH_ALEN); + + /* Allocate an IOCTL request buffer */ + req = (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + if (req == NULL) { + status = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill request buffer */ + info = (mlan_ds_get_info *) req->pbuf; + req->req_id = MLAN_IOCTL_GET_INFO; + req->action = MLAN_ACT_GET; + info->sub_command = MLAN_OID_GET_FW_INFO; + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, wait_option); + if (status == MLAN_STATUS_SUCCESS) { + priv->phandle->fw_release_number = info->param.fw_info.fw_ver; + if (priv->current_addr[0] == 0xff) + memcpy(priv->current_addr, &info->param.fw_info.mac_addr, + sizeof(mlan_802_11_mac_addr)); + memcpy(priv->netdev->dev_addr, priv->current_addr, ETH_ALEN); +#if defined(STA_CFG80211) || defined(UAP_CFG80211) + if (IS_STA_OR_UAP_CFG80211(cfg80211_wext) && priv->wdev && + priv->wdev->wiphy) + memcpy(priv->wdev->wiphy->perm_addr, priv->current_addr, ETH_ALEN); +#endif + if (fw_info) + memcpy(fw_info, &info->param.fw_info, sizeof(mlan_fw_info)); + DBG_HEXDUMP(MCMD_D, "mac", priv->current_addr, 6); + } else + PRINTM(MERROR, "get fw info failed! status=%d, error_code=0x%x\n", + status, req->status_code); + done: + if (req) + kfree(req); + LEAVE(); + return status; +} + +#ifdef PROC_DEBUG +/** + * @brief Get debug info + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * @param debug_info A pointer to mlan_debug_info structure + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_get_debug_info(moal_private * priv, t_u8 wait_option, + mlan_debug_info * debug_info) +{ + int ret = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_get_info *info = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + info = (mlan_ds_get_info *) req->pbuf; + info->sub_command = MLAN_OID_GET_DEBUG_INFO; + req->req_id = MLAN_IOCTL_GET_INFO; + req->action = MLAN_ACT_GET; + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, wait_option); + if (status == MLAN_STATUS_SUCCESS) { + if (debug_info) { + memcpy(debug_info, &info->param.debug_info, + sizeof(mlan_debug_info)); + } + } + done: + if (req && (status != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return status; +} + +/** + * @brief Set debug info + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * @param debug_info A pointer to mlan_debug_info structure + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_set_debug_info(moal_private * priv, t_u8 wait_option, + mlan_debug_info * debug_info) +{ + int ret = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_get_info *info = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + + ENTER(); + + if (!debug_info) { + ret = -EINVAL; + LEAVE(); + return MLAN_STATUS_FAILURE; + } + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + info = (mlan_ds_get_info *) req->pbuf; + info->sub_command = MLAN_OID_GET_DEBUG_INFO; + memcpy(&info->param.debug_info, debug_info, sizeof(mlan_debug_info)); + req->req_id = MLAN_IOCTL_GET_INFO; + req->action = MLAN_ACT_SET; + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, wait_option); + done: + if (req && (status != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return status; +} +#endif /* PROC_DEBUG */ + +#if defined(STA_WEXT) || defined(UAP_WEXT) +/** + * @brief host command ioctl function + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * @return 0 --success, otherwise fail + */ +int +woal_host_command(moal_private * priv, struct iwreq *wrq) +{ + HostCmd_Header cmd_header; + int ret = 0; + mlan_ds_misc_cfg *misc = NULL; + mlan_ioctl_req *req = NULL; + + ENTER(); + + /* Sanity check */ + if (wrq->u.data.pointer == NULL) { + PRINTM(MERROR, "hostcmd IOCTL corrupt data\n"); + ret = -EINVAL; + goto done; + } + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + misc = (mlan_ds_misc_cfg *) req->pbuf; + memset(&cmd_header, 0, sizeof(cmd_header)); + + /* get command header */ + if (copy_from_user + (&cmd_header, wrq->u.data.pointer, sizeof(HostCmd_Header))) { + PRINTM(MERROR, "copy from user failed: Host command header\n"); + ret = -EFAULT; + goto done; + } + misc->param.hostcmd.len = woal_le16_to_cpu(cmd_header.size); + + PRINTM(MINFO, "Host command len = %u\n", misc->param.hostcmd.len); + + if (!misc->param.hostcmd.len || + misc->param.hostcmd.len > MLAN_SIZE_OF_CMD_BUFFER) { + PRINTM(MERROR, "Invalid data buffer length\n"); + ret = -EINVAL; + goto done; + } + + /* get the whole command from user */ + if (copy_from_user + (misc->param.hostcmd.cmd, wrq->u.data.pointer, + woal_le16_to_cpu(cmd_header.size))) { + PRINTM(MERROR, "copy from user failed\n"); + ret = -EFAULT; + goto done; + } + misc->sub_command = MLAN_OID_MISC_HOST_CMD; + req->req_id = MLAN_IOCTL_MISC_CFG; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + if (copy_to_user + (wrq->u.data.pointer, (t_u8 *) misc->param.hostcmd.cmd, + misc->param.hostcmd.len)) { + ret = -EFAULT; + goto done; + } + wrq->u.data.length = misc->param.hostcmd.len; + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} +#endif + +#if defined(WIFI_DIRECT_SUPPORT) || defined(UAP_SUPPORT) +/** + * @brief host command ioctl function + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +/********* format of ifr_data *************/ +/* buf_len + Hostcmd_body */ +/* buf_len: 4 bytes */ +/* the length of the buf which */ +/* can be used to return data */ +/* to application */ +/* Hostcmd_body */ +/*******************************************/ +int +woal_hostcmd_ioctl(struct net_device *dev, struct ifreq *req) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + t_u32 buf_len = 0; + HostCmd_Header cmd_header; + int ret = 0; + mlan_ds_misc_cfg *misc = NULL; + mlan_ioctl_req *ioctl_req = NULL; + + ENTER(); + + /* Sanity check */ + if (req->ifr_data == NULL) { + PRINTM(MERROR, "uap_hostcmd_ioctl() corrupt data\n"); + ret = -EFAULT; + goto done; + } + + if (copy_from_user(&buf_len, req->ifr_data, sizeof(buf_len))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + memset(&cmd_header, 0, sizeof(cmd_header)); + + /* get command header */ + if (copy_from_user + (&cmd_header, req->ifr_data + sizeof(buf_len), + sizeof(HostCmd_Header))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + PRINTM(MINFO, "Host command len = %d\n", woal_le16_to_cpu(cmd_header.size)); + + if (woal_le16_to_cpu(cmd_header.size) > MLAN_SIZE_OF_CMD_BUFFER) { + ret = -EINVAL; + goto done; + } + + ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (ioctl_req == NULL) { + ret = -ENOMEM; + goto done; + } + misc = (mlan_ds_misc_cfg *) ioctl_req->pbuf; + + misc->param.hostcmd.len = woal_le16_to_cpu(cmd_header.size); + + /* get the whole command from user */ + if (copy_from_user + (misc->param.hostcmd.cmd, req->ifr_data + sizeof(buf_len), + misc->param.hostcmd.len)) { + PRINTM(MERROR, "copy from user failed\n"); + ret = -EFAULT; + goto done; + } + misc->sub_command = MLAN_OID_MISC_HOST_CMD; + ioctl_req->req_id = MLAN_IOCTL_MISC_CFG; + + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + if (misc->param.hostcmd.len > buf_len) { + PRINTM(MERROR, "buf_len is too small, resp_len=%d, buf_len=%d\n", + (int) misc->param.hostcmd.len, (int) buf_len); + ret = -EFAULT; + goto done; + } + if (copy_to_user + (req->ifr_data + sizeof(buf_len), (t_u8 *) misc->param.hostcmd.cmd, + misc->param.hostcmd.len)) { + ret = -EFAULT; + goto done; + } + done: + if (ioctl_req) + kfree(ioctl_req); + LEAVE(); + return ret; +} +#endif + +/** + * @brief CUSTOM_IE ioctl handler + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +int +woal_custom_ie_ioctl(struct net_device *dev, struct ifreq *req) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_ioctl_req *ioctl_req = NULL; + mlan_ds_misc_cfg *misc = NULL; + mlan_ds_misc_custom_ie *custom_ie = NULL; + int ret = 0; + + ENTER(); + + /* Sanity check */ + if (req->ifr_data == NULL) { + PRINTM(MERROR, "woal_custom_ie_ioctl() corrupt data\n"); + ret = -EFAULT; + goto done; + } + + if (!(custom_ie = kmalloc(sizeof(mlan_ds_misc_custom_ie), GFP_KERNEL))) { + ret = -ENOMEM; + goto done; + } + memset(custom_ie, 0, sizeof(mlan_ds_misc_custom_ie)); + + if (copy_from_user + (custom_ie, req->ifr_data, sizeof(mlan_ds_misc_custom_ie))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (ioctl_req == NULL) { + ret = -ENOMEM; + goto done; + } + + misc = (mlan_ds_misc_cfg *) ioctl_req->pbuf; + misc->sub_command = MLAN_OID_MISC_CUSTOM_IE; + ioctl_req->req_id = MLAN_IOCTL_MISC_CFG; + if ((custom_ie->len == 0) || + (custom_ie->len == sizeof(custom_ie->ie_data_list[0].ie_index))) + ioctl_req->action = MLAN_ACT_GET; + else + ioctl_req->action = MLAN_ACT_SET; + + memcpy(&misc->param.cust_ie, custom_ie, sizeof(mlan_ds_misc_custom_ie)); + + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + if (ioctl_req->action == MLAN_ACT_GET) { + if (copy_to_user + (req->ifr_data, &misc->param.cust_ie, + sizeof(mlan_ds_misc_custom_ie))) { + PRINTM(MERROR, "Copy to user failed!\n"); + ret = -EFAULT; + goto done; + } + } else if (ioctl_req->status_code == MLAN_ERROR_IOCTL_FAIL) { + /* send a separate error code to indicate error from driver */ + ret = EFAULT; + } + + done: + if (ioctl_req) + kfree(ioctl_req); + if (custom_ie) + kfree(custom_ie); + LEAVE(); + return ret; +} + +/** + * @brief send raw data packet ioctl function + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +int +woal_send_host_packet(struct net_device *dev, struct ifreq *req) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + t_u32 packet_len = 0; + int ret = 0; + pmlan_buffer pmbuf = NULL; + mlan_status status; + + ENTER(); + + /* Sanity check */ + if (req->ifr_data == NULL) { + PRINTM(MERROR, "woal_send_host_packet() corrupt data\n"); + ret = -EFAULT; + goto done; + } + + if (copy_from_user(&packet_len, req->ifr_data, sizeof(packet_len))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } +#define PACKET_HEADER_LEN 8 + pmbuf = + woal_alloc_mlan_buffer(priv->phandle, + MLAN_MIN_DATA_HEADER_LEN + packet_len + + PACKET_HEADER_LEN); + if (!pmbuf) { + PRINTM(MERROR, "Fail to allocate mlan_buffer\n"); + ret = -ENOMEM; + goto done; + } + pmbuf->data_offset = MLAN_MIN_DATA_HEADER_LEN; + + /* get whole packet and header */ + if (copy_from_user + (pmbuf->pbuf + pmbuf->data_offset, req->ifr_data + sizeof(packet_len), + PACKET_HEADER_LEN + packet_len)) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + woal_free_mlan_buffer(priv->phandle, pmbuf); + goto done; + } + pmbuf->data_len = PACKET_HEADER_LEN + packet_len; + pmbuf->buf_type = MLAN_BUF_TYPE_RAW_DATA; + pmbuf->bss_index = priv->bss_index; + status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf); + switch (status) { + case MLAN_STATUS_PENDING: + atomic_inc(&priv->phandle->tx_pending); + queue_work(priv->phandle->workqueue, &priv->phandle->main_work); + break; + case MLAN_STATUS_SUCCESS: + woal_free_mlan_buffer(priv->phandle, pmbuf); + break; + case MLAN_STATUS_FAILURE: + default: + woal_free_mlan_buffer(priv->phandle, pmbuf); + ret = -EFAULT; + break; + } + done: + LEAVE(); + return ret; +} + +#if defined(UAP_WEXT) +/** + * @brief Set/Get CUSTOM_IE ioctl handler + * + * @param mask Mask to set or clear from caller + * @param ie IE buffer to set for beacon + * @param ie_len Length of the IE + * + * @return 0 --success, otherwise fail + */ +int +woal_set_get_custom_ie(moal_private * priv, t_u16 mask, t_u8 * ie, int ie_len) +{ + mlan_ioctl_req *ioctl_req = NULL; + mlan_ds_misc_cfg *misc = NULL; + mlan_ds_misc_custom_ie *misc_ie = NULL; + int ret = 0; + custom_ie *pcust_bcn_ie = NULL; + + ENTER(); + + ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (ioctl_req == NULL) { + LEAVE(); + return -ENOMEM; + } + + misc = (mlan_ds_misc_cfg *) ioctl_req->pbuf; + misc->sub_command = MLAN_OID_MISC_CUSTOM_IE; + ioctl_req->req_id = MLAN_IOCTL_MISC_CFG; + ioctl_req->action = MLAN_ACT_SET; + misc_ie = &misc->param.cust_ie; + +#ifndef TLV_TYPE_MGMT_IE +#define TLV_TYPE_MGMT_IE (0x169) +#endif + misc_ie->type = TLV_TYPE_MGMT_IE; + misc_ie->len = (sizeof(custom_ie) - MAX_IE_SIZE) + ie_len; + pcust_bcn_ie = misc_ie->ie_data_list; + pcust_bcn_ie->ie_index = 0xffff; + pcust_bcn_ie->mgmt_subtype_mask = mask; + pcust_bcn_ie->ie_length = ie_len; + memcpy(pcust_bcn_ie->ie_buffer, ie, ie_len); + + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + } + + if (ioctl_req) + kfree(ioctl_req); + LEAVE(); + return ret; +} +#endif /* defined(HOST_TXRX_MGMT_FRAME) && defined(UAP_WEXT) */ + +/** + * @brief ioctl function get BSS type + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +int +woal_get_bss_type(struct net_device *dev, struct ifreq *req) +{ + int ret = 0; + moal_private *priv = (moal_private *) netdev_priv(dev); + int bss_type; + + ENTER(); + + bss_type = (int) priv->bss_type; + if (copy_to_user(req->ifr_data, &bss_type, sizeof(int))) { + PRINTM(MINFO, "Copy to user failed!\n"); + ret = -EFAULT; + } + + LEAVE(); + return ret; +} + +#if defined(WIFI_DIRECT_SUPPORT) +#if defined(STA_SUPPORT) && defined(UAP_SUPPORT) +#if defined(STA_WEXT) || defined(UAP_WEXT) +/** + * @brief Set/Get BSS role + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +int +woal_set_get_bss_role(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + mlan_ds_bss *bss = NULL; + mlan_ioctl_req *req = NULL; + int bss_role = 0; + struct net_device *dev = priv->netdev; + + ENTER(); + + if (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) { + PRINTM(MWARN, "Command is not allowed for this interface\n"); + ret = -EPERM; + goto done; + } + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + bss = (mlan_ds_bss *) req->pbuf; + bss->sub_command = MLAN_OID_BSS_ROLE; + req->req_id = MLAN_IOCTL_BSS; + if (wrq->u.data.length) { + if (copy_from_user(&bss_role, wrq->u.data.pointer, sizeof(int))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + if (bss_role != MLAN_BSS_ROLE_STA && bss_role != MLAN_BSS_ROLE_UAP) { + PRINTM(MWARN, "Invalid BSS role\n"); + ret = -EINVAL; + goto done; + } + if (bss_role == GET_BSS_ROLE(priv)) { + PRINTM(MWARN, "Already BSS is in desired role\n"); + ret = -EINVAL; + goto done; + } + req->action = MLAN_ACT_SET; + bss->param.bss_role = (t_u8) bss_role; + } else { + req->action = MLAN_ACT_GET; + } + + if (req->action == MLAN_ACT_SET) { + /* Reset interface */ + woal_reset_intf(priv, MOAL_IOCTL_WAIT, MFALSE); + } + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + if (!wrq->u.data.length) { + bss_role = (int) bss->param.bss_role; + if (copy_to_user(wrq->u.data.pointer, &bss_role, sizeof(int))) { + ret = -EFAULT; + goto done; + } + wrq->u.data.length = 1; + } else { + /* Update moal_private */ + priv->bss_role = bss_role; + if (priv->bss_type == MLAN_BSS_TYPE_UAP) + priv->bss_type = MLAN_BSS_TYPE_STA; + else if (priv->bss_type == MLAN_BSS_TYPE_STA) + priv->bss_type = MLAN_BSS_TYPE_UAP; + + /* Initialize private structures */ + woal_init_priv(priv, MOAL_IOCTL_WAIT); + + if (bss_role == MLAN_BSS_ROLE_UAP) { + /* Switch: STA -> uAP */ + /* Setup the OS Interface to our functions */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) + dev->do_ioctl = woal_uap_do_ioctl; + dev->set_multicast_list = woal_uap_set_multicast_list; +#else + dev->netdev_ops = &woal_uap_netdev_ops; +#endif +#ifdef UAP_WEXT + if (IS_UAP_WEXT(cfg80211_wext)) { +#ifdef WIRELESS_EXT +#if WIRELESS_EXT < 21 + dev->get_wireless_stats = woal_get_uap_wireless_stats; +#endif + dev->wireless_handlers = + (struct iw_handler_def *) &woal_uap_handler_def; +#endif /* WIRELESS_EXT */ + init_waitqueue_head(&priv->w_stats_wait_q); + } +#endif /* UAP_WEXT */ + } else if (bss_role == MLAN_BSS_ROLE_STA) { + /* Switch: uAP -> STA */ + /* Setup the OS Interface to our functions */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) + dev->do_ioctl = woal_do_ioctl; + dev->set_multicast_list = woal_set_multicast_list; +#else + dev->netdev_ops = &woal_netdev_ops; +#endif +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) { +#ifdef WIRELESS_EXT +#if WIRELESS_EXT < 21 + dev->get_wireless_stats = woal_get_wireless_stats; +#endif + dev->wireless_handlers = + (struct iw_handler_def *) &woal_handler_def; +#endif + init_waitqueue_head(&priv->w_stats_wait_q); + } +#endif /* STA_WEXT */ + } + /* Enable interfaces */ + netif_device_attach(dev); + woal_start_queue(dev); + } + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} +#endif +#endif +#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */ + +/** + * @brief Get Host Sleep parameters + * + * @param priv A pointer to moal_private structure + * @param action Action: set or get + * @param wait_option Wait option (MOAL_WAIT or MOAL_NO_WAIT) + * @param hscfg A pointer to mlan_ds_hs_cfg structure + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_set_get_hs_params(moal_private * priv, t_u16 action, t_u8 wait_option, + mlan_ds_hs_cfg * hscfg) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_ds_pm_cfg *pmcfg = NULL; + mlan_ioctl_req *req = NULL; + + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + pmcfg = (mlan_ds_pm_cfg *) req->pbuf; + pmcfg->sub_command = MLAN_OID_PM_CFG_HS_CFG; + req->req_id = MLAN_IOCTL_PM_CFG; + req->action = action; + if (action == MLAN_ACT_SET) + memcpy(&pmcfg->param.hs_cfg, hscfg, sizeof(mlan_ds_hs_cfg)); + + /* Send IOCTL request to MLAN */ + ret = woal_request_ioctl(priv, req, wait_option); + if (ret == MLAN_STATUS_SUCCESS) { + if (hscfg && action == MLAN_ACT_GET) { + memcpy(hscfg, &pmcfg->param.hs_cfg, sizeof(mlan_ds_hs_cfg)); + } + } + done: + if (req && (ret != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Cancel Host Sleep configuration + * + * @param priv A pointer to moal_private structure + * @param wait_option wait option + * + * @return MLAN_STATUS_SUCCESS, MLAN_STATUS_PENDING, + * or MLAN_STATUS_FAILURE + */ +mlan_status +woal_cancel_hs(moal_private * priv, t_u8 wait_option) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_ds_hs_cfg hscfg; + + ENTER(); + + /* Cancel Host Sleep */ + hscfg.conditions = HOST_SLEEP_CFG_CANCEL; + hscfg.is_invoke_hostcmd = MTRUE; + ret = woal_set_get_hs_params(priv, MLAN_ACT_SET, wait_option, &hscfg); + + LEAVE(); + return ret; +} + +/** @brief This function enables the host sleep + * + * @param priv A Pointer to the moal_private structure + * @return MTRUE or MFALSE + */ +int +woal_enable_hs(moal_private * priv) +{ + mlan_ds_hs_cfg hscfg; + moal_handle *handle = NULL; + int hs_actived = MFALSE; + int timeout = 0; +#ifdef SDIO_SUSPEND_RESUME + mlan_ds_ps_info pm_info; +#endif + + ENTER(); + + if (priv == NULL) { + PRINTM(MERROR, "Invalid priv\n"); + goto done; + } + handle = priv->phandle; + if (handle->hs_activated == MTRUE) { + PRINTM(MIOCTL, "HS Already actived\n"); + hs_actived = MTRUE; + goto done; + } +#ifdef STA_SUPPORT + woal_reconfig_bgscan(priv->phandle); +#endif + /* Enable Host Sleep */ + handle->hs_activate_wait_q_woken = MFALSE; + memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg)); + hscfg.is_invoke_hostcmd = MTRUE; + if (woal_set_get_hs_params(priv, MLAN_ACT_SET, MOAL_NO_WAIT, &hscfg) == + MLAN_STATUS_FAILURE) { + PRINTM(MIOCTL, "IOCTL request HS enable failed\n"); + goto done; + } + timeout = wait_event_interruptible_timeout(handle->hs_activate_wait_q, + handle->hs_activate_wait_q_woken, + HS_ACTIVE_TIMEOUT); + sdio_claim_host(((struct sdio_mmc_card *) handle->card)->func); + if ((handle->hs_activated == MTRUE) || (handle->is_suspended == MTRUE)) { + PRINTM(MCMND, "suspend success! force=%u skip=%u\n", + handle->hs_force_count, handle->hs_skip_count); + hs_actived = MTRUE; + } +#ifdef SDIO_SUSPEND_RESUME + else { + handle->suspend_fail = MTRUE; + woal_get_pm_info(priv, &pm_info); + if (pm_info.is_suspend_allowed == MTRUE) { +#ifdef MMC_PM_FUNC_SUSPENDED + woal_wlan_is_suspended(priv->phandle); +#endif + handle->hs_force_count++; + PRINTM(MCMND, "suspend allowed! force=%u skip=%u\n", + handle->hs_force_count, handle->hs_skip_count); + hs_actived = MTRUE; + } + } +#endif /* SDIO_SUSPEND_RESUME */ + sdio_release_host(((struct sdio_mmc_card *) handle->card)->func); + if (hs_actived != MTRUE) { + handle->hs_skip_count++; +#ifdef SDIO_SUSPEND_RESUME + PRINTM(MCMND, "suspend skipped! timeout=%d allow=%d force=%u skip=%u\n", + timeout, (int) pm_info.is_suspend_allowed, + handle->hs_force_count, handle->hs_skip_count); +#else + PRINTM(MCMND, "suspend skipped! timeout=%d skip=%u\n", + timeout, handle->hs_skip_count); +#endif + woal_cancel_hs(priv, MOAL_NO_WAIT); + } + done: + LEAVE(); + return hs_actived; +} + +/** + * @brief This function send soft_reset command to firmware + * + * @param handle A pointer to moal_handle structure + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING on success, otherwise failure code + */ +mlan_status +woal_request_soft_reset(moal_handle * handle) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_ioctl_req *req = NULL; + mlan_ds_misc_cfg *misc = NULL; + + ENTER(); + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req) { + misc = (mlan_ds_misc_cfg *) req->pbuf; + misc->sub_command = MLAN_OID_MISC_SOFT_RESET; + req->req_id = MLAN_IOCTL_MISC_CFG; + req->action = MLAN_ACT_SET; + ret = + woal_request_ioctl(woal_get_priv(handle, MLAN_BSS_ROLE_ANY), req, + MOAL_PROC_WAIT); + } + + handle->surprise_removed = MTRUE; + woal_sched_timeout(5); + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Set wapi enable + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * @param enable MTRUE or MFALSE + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_set_wapi_enable(moal_private * priv, t_u8 wait_option, t_u32 enable) +{ + int ret = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_sec_cfg *sec = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + sec = (mlan_ds_sec_cfg *) req->pbuf; + sec->sub_command = MLAN_OID_SEC_CFG_WAPI_ENABLED; + req->req_id = MLAN_IOCTL_SEC_CFG; + req->action = MLAN_ACT_SET; + sec->param.wapi_enabled = enable; + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, wait_option); + done: + if (req && (status != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return status; +} + +/** + * @brief Get version + * + * @param handle A pointer to moal_handle structure + * @param version A pointer to version buffer + * @param max_len max length of version buffer + * + * @return N/A + */ +void +woal_get_version(moal_handle * handle, char *version, int max_len) +{ + union + { + t_u32 l; + t_u8 c[4]; + } ver; + char fw_ver[32]; + + ENTER(); + + ver.l = handle->fw_release_number; + snprintf(fw_ver, sizeof(fw_ver), "%u.%u.%u.p%u", + ver.c[2], ver.c[1], ver.c[0], ver.c[3]); + + snprintf(version, max_len, driver_version, fw_ver); + + LEAVE(); +} + +#if defined(STA_WEXT) || defined(UAP_WEXT) +/** + * @brief Get Driver Version + * + * @param priv A pointer to moal_private structure + * @param req A pointer to ifreq structure + * + * @return 0 --success, otherwise fail + */ +int +woal_get_driver_version(moal_private * priv, struct ifreq *req) +{ + struct iwreq *wrq = (struct iwreq *) req; + int len; + char buf[MLAN_MAX_VER_STR_LEN]; + ENTER(); + + woal_get_version(priv->phandle, buf, sizeof(buf) - 1); + + len = strlen(buf); + if (wrq->u.data.pointer) { + if (copy_to_user(wrq->u.data.pointer, buf, len)) { + PRINTM(MERROR, "Copy to user failed\n"); + LEAVE(); + return -EFAULT; + } + wrq->u.data.length = len; + } + PRINTM(MINFO, "MOAL VERSION: %s\n", buf); + LEAVE(); + return 0; +} + +/** + * @brief Get extended driver version + * + * @param priv A pointer to moal_private structure + * @param ireq A pointer to ifreq structure + * + * @return 0 --success, otherwise fail + */ +int +woal_get_driver_verext(moal_private * priv, struct ifreq *ireq) +{ + struct iwreq *wrq = (struct iwreq *) ireq; + mlan_ds_get_info *info = NULL; + mlan_ioctl_req *req = NULL; + int ret = 0; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info)); + if (req == NULL) { + LEAVE(); + return -ENOMEM; + } + + info = (mlan_ds_get_info *) req->pbuf; + info->sub_command = MLAN_OID_GET_VER_EXT; + req->req_id = MLAN_IOCTL_GET_INFO; + req->action = MLAN_ACT_GET; + + if (!wrq->u.data.flags) { + info->param.ver_ext.version_str_sel = + *((int *) (wrq->u.name + SUBCMD_OFFSET)); + } else { + if (copy_from_user + (&info->param.ver_ext.version_str_sel, wrq->u.data.pointer, + sizeof(info->param.ver_ext.version_str_sel))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } else { + if (((t_s32) (info->param.ver_ext.version_str_sel)) < 0) { + PRINTM(MERROR, "Invalid arguments!\n"); + ret = -EINVAL; + goto done; + } + } + } + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + if (wrq->u.data.pointer) { + if (copy_to_user(wrq->u.data.pointer, info->param.ver_ext.version_str, + strlen(info->param.ver_ext.version_str))) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + goto done; + } + wrq->u.data.length = strlen(info->param.ver_ext.version_str); + } + + PRINTM(MINFO, "MOAL EXTENDED VERSION: %s\n", + info->param.ver_ext.version_str); + done: + if (req) + kfree(req); + + LEAVE(); + return ret; +} +#endif + +#ifdef DEBUG_LEVEL1 +/** + * @brief Set driver debug bit masks to mlan in order to enhance performance + * + * @param priv A pointer to moal_private structure + * @param drvdbg Driver debug level + * + * @return 0 --success, otherwise fail + */ +int +woal_set_drvdbg(moal_private * priv, t_u32 drvdbg) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_misc_cfg *misc = NULL; + int ret = 0; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req == NULL) { + LEAVE(); + return -ENOMEM; + } + + misc = (mlan_ds_misc_cfg *) req->pbuf; + misc->sub_command = MLAN_OID_MISC_DRVDBG; + req->req_id = MLAN_IOCTL_MISC_CFG; + req->action = MLAN_ACT_SET; + misc->param.drvdbg = drvdbg; + + ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); + + if (req && (ret != MLAN_STATUS_PENDING)) + kfree(req); + + LEAVE(); + return ret; +} +#endif + +/** + * @brief Mgmt frame forward registration + * + * @param priv A pointer to moal_private structure + * @param action Action: set or get + * @param pmgmt_subtype_mask A Pointer to mgmt frame subtype mask + * @param wait_option wait option (MOAL_WAIT or MOAL_NO_WAIT) + * + * @return 0 --success, otherwise fail + */ +int +woal_reg_rx_mgmt_ind(moal_private * priv, t_u16 action, + t_u32 * pmgmt_subtype_mask, t_u8 wait_option) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_misc_cfg *misc = NULL; + int ret = 0; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req == NULL) { + LEAVE(); + return -ENOMEM; + } + + misc = (mlan_ds_misc_cfg *) req->pbuf; + misc->sub_command = MLAN_OID_MISC_RX_MGMT_IND; + req->req_id = MLAN_IOCTL_MISC_CFG; + req->action = action; + misc->param.mgmt_subtype_mask = *pmgmt_subtype_mask; + if (req->action == MLAN_ACT_SET) + memcpy(&misc->param.mgmt_subtype_mask, + pmgmt_subtype_mask, sizeof(misc->param.mgmt_subtype_mask)); + + ret = woal_request_ioctl(priv, req, wait_option); + + if (req->action == MLAN_ACT_GET) + memcpy(pmgmt_subtype_mask, &misc->param.mgmt_subtype_mask, + sizeof(misc->param.mgmt_subtype_mask)); + + if (req && (ret != MLAN_STATUS_PENDING)) + kfree(req); + + LEAVE(); + return ret; +} + +/** + * @brief Set/Get Transmit beamforming configuration + * + * @param priv A pointer to moal_private structure + * @param action Action: set or get + * @param tx_bf_cfg A pointer to tx_bf_cfg structure + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + */ +mlan_status +woal_set_get_tx_bf_cfg(moal_private * priv, t_u16 action, + mlan_ds_11n_tx_bf_cfg * tx_bf_cfg) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_ioctl_req *req = NULL; + mlan_ds_11n_cfg *bf_cfg = NULL; + + ENTER(); + + /* Sanity test */ + if (tx_bf_cfg == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); + if (req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill request buffer */ + bf_cfg = (mlan_ds_11n_cfg *) req->pbuf; + req->req_id = MLAN_IOCTL_11N_CFG; + bf_cfg->sub_command = MLAN_OID_11N_CFG_TX_BF_CFG; + + req->action = action; + memcpy(&bf_cfg->param.tx_bf, tx_bf_cfg, sizeof(mlan_ds_11n_tx_bf_cfg)); + + /* Send IOCTL request to MLAN */ + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + if (action == MLAN_ACT_GET) + memcpy(tx_bf_cfg, &bf_cfg->param.tx_bf, sizeof(mlan_ds_11n_tx_bf_cfg)); + + done: + LEAVE(); + return ret; +} + +/** + * @brief Handle ioctl resp + * + * @param priv Pointer to moal_private structure + * @param req Pointer to mlan_ioctl_req structure + * + * @return N/A + */ +void +woal_process_ioctl_resp(moal_private * priv, mlan_ioctl_req * req) +{ + ENTER(); + + if (priv == NULL) { + LEAVE(); + return; + } + switch (req->req_id) { + case MLAN_IOCTL_GET_INFO: +#ifdef STA_WEXT +#ifdef STA_SUPPORT + if (IS_STA_WEXT(cfg80211_wext) && + GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) + woal_ioctl_get_info_resp(priv, (mlan_ds_get_info *) req->pbuf); +#endif +#endif +#ifdef UAP_WEXT +#ifdef UAP_SUPPORT + if (IS_UAP_WEXT(cfg80211_wext) && + GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) + woal_ioctl_get_uap_info_resp(priv, (mlan_ds_get_info *) req->pbuf); +#endif +#endif + break; +#ifdef STA_WEXT +#ifdef STA_SUPPORT + case MLAN_IOCTL_BSS: + if (IS_STA_WEXT(cfg80211_wext) && + GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) + woal_ioctl_get_bss_resp(priv, (mlan_ds_bss *) req->pbuf); + break; +#endif +#endif + default: + break; + } + + LEAVE(); + return; +} + +/** + * @brief Get PM info + * + * @param priv A pointer to moal_private structure + * @param pm_info A pointer to mlan_ds_ps_info structure + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_get_pm_info(moal_private * priv, mlan_ds_ps_info * pm_info) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_ds_pm_cfg *pmcfg = NULL; + mlan_ioctl_req *req = NULL; + + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg)); + if (req == NULL) { + PRINTM(MERROR, "Fail to alloc mlan_ds_pm_cfg buffer\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill request buffer */ + pmcfg = (mlan_ds_pm_cfg *) req->pbuf; + pmcfg->sub_command = MLAN_OID_PM_INFO; + req->req_id = MLAN_IOCTL_PM_CFG; + req->action = MLAN_ACT_GET; + + /* Send IOCTL request to MLAN */ + ret = woal_request_ioctl(priv, req, MOAL_CMD_WAIT); + if (ret == MLAN_STATUS_SUCCESS) { + if (pm_info) { + memcpy(pm_info, &pmcfg->param.ps_info, sizeof(mlan_ds_ps_info)); + } + } + done: + if (req && (ret != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Set Deep Sleep + * + * @param priv Pointer to the moal_private driver data struct + * @param wait_option wait option + * @param bdeep_sleep TRUE--enalbe deepsleep, FALSE--disable deepsleep + * @param idletime Idle time for optimized PS API + * + * @return 0 --success, otherwise fail + */ +int +woal_set_deep_sleep(moal_private * priv, t_u8 wait_option, BOOLEAN bdeep_sleep, + t_u16 idletime) +{ + int ret = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_pm_cfg *pm = NULL; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg)); + if (req == NULL) { + LEAVE(); + return -ENOMEM; + } + pm = (mlan_ds_pm_cfg *) req->pbuf; + pm->sub_command = MLAN_OID_PM_CFG_DEEP_SLEEP; + req->req_id = MLAN_IOCTL_PM_CFG; + + req->action = MLAN_ACT_SET; + if (bdeep_sleep == MTRUE) { + PRINTM(MIOCTL, "Deep Sleep: sleep\n"); + pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_ON; + if (idletime) { + pm->param.auto_deep_sleep.idletime = idletime; + } + ret = woal_request_ioctl(priv, req, wait_option); + if (ret != MLAN_STATUS_SUCCESS && ret != MLAN_STATUS_PENDING) { + ret = -EFAULT; + goto done; + } + } else { + PRINTM(MIOCTL, "%lu : Deep Sleep: wakeup\n", jiffies); + pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_OFF; + ret = woal_request_ioctl(priv, req, wait_option); + if (ret != MLAN_STATUS_SUCCESS && ret != MLAN_STATUS_PENDING) { + ret = -EFAULT; + goto done; + } + } + done: + if (req && (ret != MLAN_STATUS_PENDING)) + kfree(req); + + LEAVE(); + return ret; +} + +/** + * @brief Cancel CAC period block + * + * @param priv A pointer to moal_private structure + * + * @return N/A + */ +void +woal_cancel_cac_block(moal_private * priv) +{ + ENTER(); + /* if during CAC period, wake up wait queue */ + if (priv->phandle->cac_period == MTRUE) { + priv->phandle->cac_period = MFALSE; + priv->phandle->meas_start_jiffies = 0; + if (priv->phandle->delay_bss_start == MTRUE) { + priv->phandle->delay_bss_start = MFALSE; + } + if (priv->phandle->meas_wait_q_woken == MFALSE) { + priv->phandle->meas_wait_q_woken = MTRUE; + wake_up_interruptible(&priv->phandle->meas_wait_q); + } + } + LEAVE(); +} + +/** MEAS report timeout value in seconds */ + +/** + * @brief Issue MLAN_OID_11H_CHANNEL_CHECK ioctl + * + * @param priv Pointer to the moal_private driver data struct + * + * @return 0 --success, otherwise fail + */ +int +woal_11h_channel_check_ioctl(moal_private * priv) +{ + int ret = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_11h_cfg *ds_11hcfg = NULL; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + ds_11hcfg = (mlan_ds_11h_cfg *) req->pbuf; + + ds_11hcfg->sub_command = MLAN_OID_11H_CHANNEL_CHECK; + req->req_id = MLAN_IOCTL_11H_CFG; + req->action = MLAN_ACT_SET; + /* Send Channel Check command and wait until the report is ready */ + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + /* set flag from here */ + priv->phandle->cac_period = MTRUE; + priv->phandle->meas_start_jiffies = jiffies; + + done: + if (req) + kfree(req); + + LEAVE(); + return ret; +} + +#if defined(WIFI_DIRECT_SUPPORT) +/** + * @brief set/get wifi direct mode + * + * @param priv A pointer to moal_private structure + * @param action set or get + * @param mode A pointer to wifi direct mode + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + */ +mlan_status +woal_cfg80211_wifi_direct_mode_cfg(moal_private * priv, t_u16 action, + t_u16 * mode) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_ioctl_req *req = NULL; + mlan_ds_bss *bss = NULL; + + ENTER(); + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + if (req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + bss = (mlan_ds_bss *) req->pbuf; + bss->sub_command = MLAN_OID_WIFI_DIRECT_MODE; + req->req_id = MLAN_IOCTL_BSS; + + req->action = action; + if (action == MLAN_ACT_SET) + bss->param.wfd_mode = *mode; + ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); + if (ret == MLAN_STATUS_SUCCESS) { + *mode = bss->param.wfd_mode; + PRINTM(MIOCTL, "ACT=%d, wifi_direct_mode=%d\n", action, *mode); + } + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief set remain channel + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * @param pchan A pointer to mlan_ds_remain_chan structure + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + */ +mlan_status +woal_set_remain_channel_ioctl(moal_private * priv, t_u8 wait_option, + mlan_ds_remain_chan * pchan) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_ioctl_req *req = NULL; + mlan_ds_radio_cfg *radio_cfg = NULL; + + ENTER(); + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg)); + if (req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + radio_cfg = (mlan_ds_radio_cfg *) req->pbuf; + radio_cfg->sub_command = MLAN_OID_REMAIN_CHAN_CFG; + req->req_id = MLAN_IOCTL_RADIO_CFG; + + req->action = MLAN_ACT_SET; + memcpy(&radio_cfg->param.remain_chan, pchan, sizeof(mlan_ds_remain_chan)); + ret = woal_request_ioctl(priv, req, wait_option); + if (ret == MLAN_STATUS_SUCCESS) { + memcpy(pchan, &radio_cfg->param.remain_chan, + sizeof(mlan_ds_remain_chan)); + } + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} +#endif /* WIFI_DIRECT_SUPPORT */ + +#ifdef STA_SUPPORT +/** + * @brief Get RSSI info + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * @param signal A pointer tp mlan_ds_get_signal structure + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_get_signal_info(moal_private * priv, t_u8 wait_option, + mlan_ds_get_signal * signal) +{ + int ret = 0; + mlan_ds_get_info *info = NULL; + mlan_ioctl_req *req = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + info = (mlan_ds_get_info *) req->pbuf; + info->sub_command = MLAN_OID_GET_SIGNAL; + info->param.signal.selector = ALL_RSSI_INFO_MASK; + req->req_id = MLAN_IOCTL_GET_INFO; + req->action = MLAN_ACT_GET; + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, wait_option); + if (status == MLAN_STATUS_SUCCESS) { + if (signal) + memcpy(signal, &info->param.signal, sizeof(mlan_ds_get_signal)); +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) { + if (info->param.signal.selector & BCN_RSSI_AVG_MASK) + priv->w_stats.qual.level = info->param.signal.bcn_rssi_avg; + if (info->param.signal.selector & BCN_NF_AVG_MASK) + priv->w_stats.qual.noise = info->param.signal.bcn_nf_avg; + } +#endif + } + done: + if (req && (status != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return status; +} + +/** + * @brief Get scan table + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * @param scan_resp A pointer to mlan_scan_resp structure + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_get_scan_table(moal_private * priv, t_u8 wait_option, + mlan_scan_resp * scan_resp) +{ + int ret = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_scan *scan = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + scan = (mlan_ds_scan *) req->pbuf; + scan->sub_command = MLAN_OID_SCAN_NORMAL; + req->req_id = MLAN_IOCTL_SCAN; + req->action = MLAN_ACT_GET; + memcpy((void *) &scan->param.scan_resp, (void *) scan_resp, + sizeof(mlan_scan_resp)); + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, wait_option); + if (status == MLAN_STATUS_SUCCESS) { + if (scan_resp) { + memcpy(scan_resp, &scan->param.scan_resp, sizeof(mlan_scan_resp)); + } + } + + done: + if (req && (status != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return status; +} + +/** + * @brief Request a scan + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * @param req_ssid A pointer to mlan_802_11_ssid structure + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + */ +mlan_status +woal_request_scan(moal_private * priv, + t_u8 wait_option, mlan_802_11_ssid * req_ssid) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + moal_handle *handle = priv->phandle; + mlan_ioctl_req *ioctl_req = NULL; + mlan_ds_scan *scan = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + ENTER(); + + if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->async_sem)) { + PRINTM(MERROR, "Acquire semaphore error, request_scan\n"); + LEAVE(); + return MLAN_STATUS_FAILURE; + } + handle->scan_pending_on_block = MTRUE; + + /* Allocate an IOCTL request buffer */ + ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan)); + if (ioctl_req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + scan = (mlan_ds_scan *) ioctl_req->pbuf; + + if (req_ssid && req_ssid->ssid_len != 0) { + /* Specific SSID scan */ + ioctl_req->req_id = MLAN_IOCTL_SCAN; + ioctl_req->action = MLAN_ACT_SET; + + scan->sub_command = MLAN_OID_SCAN_SPECIFIC_SSID; + + memcpy(scan->param.scan_req.scan_ssid.ssid, + req_ssid->ssid, MIN(MLAN_MAX_SSID_LENGTH, req_ssid->ssid_len)); + scan->param.scan_req.scan_ssid.ssid_len = + MIN(MLAN_MAX_SSID_LENGTH, req_ssid->ssid_len); + } else { + /* Normal scan */ + ioctl_req->req_id = MLAN_IOCTL_SCAN; + ioctl_req->action = MLAN_ACT_SET; + + scan->sub_command = MLAN_OID_SCAN_NORMAL; + } + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, ioctl_req, wait_option); + + if (status == MLAN_STATUS_FAILURE) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + done: + if ((ioctl_req) && (status != MLAN_STATUS_PENDING)) + kfree(ioctl_req); + + if (ret == MLAN_STATUS_FAILURE) { + handle->scan_pending_on_block = MFALSE; + MOAL_REL_SEMAPHORE(&handle->async_sem); + } + LEAVE(); + return ret; +} + +/** + * @brief Change Adhoc Channel + * + * @param priv A pointer to moal_private structure + * @param channel The channel to be set. + * + * @return MLAN_STATUS_SUCCESS--success, MLAN_STATUS_FAILURE--fail + */ +mlan_status +woal_change_adhoc_chan(moal_private * priv, int channel) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_bss_info bss_info; + mlan_ds_bss *bss = NULL; + mlan_ioctl_req *req = NULL; + + ENTER(); + + memset(&bss_info, 0, sizeof(bss_info)); + + /* Get BSS information */ + if (MLAN_STATUS_SUCCESS != + woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + if (bss_info.bss_mode == MLAN_BSS_MODE_INFRA) { + ret = MLAN_STATUS_SUCCESS; + goto done; + } + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + if (req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Get current channel */ + bss = (mlan_ds_bss *) req->pbuf; + bss->sub_command = MLAN_OID_IBSS_CHANNEL; + req->req_id = MLAN_IOCTL_BSS; + req->action = MLAN_ACT_GET; + + /* Send IOCTL request to MLAN */ + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + if (bss->param.bss_chan.channel == (unsigned int) channel) { + ret = MLAN_STATUS_SUCCESS; + goto done; + } + PRINTM(MINFO, "Updating Channel from %d to %d\n", + (int) bss->param.bss_chan.channel, channel); + + if (bss_info.media_connected != MTRUE) { + ret = MLAN_STATUS_SUCCESS; + goto done; + } + + /* Do disonnect */ + bss->sub_command = MLAN_OID_BSS_STOP; + memset((t_u8 *) & bss->param.bssid, 0, ETH_ALEN); + + /* Send IOCTL request to MLAN */ + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Do specific SSID scanning */ + if (MLAN_STATUS_SUCCESS != + woal_request_scan(priv, MOAL_IOCTL_WAIT, &bss_info.ssid)) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + /* Start/Join Adhoc network */ + bss->sub_command = MLAN_OID_BSS_START; + memset(&bss->param.ssid_bssid, 0, sizeof(mlan_ssid_bssid)); + memcpy(&bss->param.ssid_bssid.ssid, &bss_info.ssid, + sizeof(mlan_802_11_ssid)); + + /* Send IOCTL request to MLAN */ + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = MLAN_STATUS_FAILURE; + } + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Find the best network to associate + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * @param ssid_bssid A pointer to mlan_ssid_bssid structure + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_find_best_network(moal_private * priv, t_u8 wait_option, + mlan_ssid_bssid * ssid_bssid) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_bss *bss = NULL; + mlan_status ret = MLAN_STATUS_SUCCESS; + t_u8 *mac = 0; + + ENTER(); + + if (!ssid_bssid) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + if (req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill request buffer */ + bss = (mlan_ds_bss *) req->pbuf; + req->req_id = MLAN_IOCTL_BSS; + req->action = MLAN_ACT_GET; + bss->sub_command = MLAN_OID_BSS_FIND_BSS; + + memcpy(&bss->param.ssid_bssid, ssid_bssid, sizeof(mlan_ssid_bssid)); + + /* Send IOCTL request to MLAN */ + ret = woal_request_ioctl(priv, req, wait_option); + if (ret == MLAN_STATUS_SUCCESS) { + memcpy(ssid_bssid, &bss->param.ssid_bssid, sizeof(mlan_ssid_bssid)); + mac = (t_u8 *) & ssid_bssid->bssid; + PRINTM(MINFO, + "Find network: ssid=%s, %02x:%02x:%02x:%02x:%02x:%02x, idx=%d\n", + ssid_bssid->ssid.ssid, mac[0], mac[1], mac[2], mac[3], mac[4], + mac[5], (int) ssid_bssid->idx); + } + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Get authentication mode + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * @param auth_mode A pointer to authentication mode + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_get_auth_mode(moal_private * priv, t_u8 wait_option, t_u32 * auth_mode) +{ + int ret = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_sec_cfg *sec = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + sec = (mlan_ds_sec_cfg *) req->pbuf; + sec->sub_command = MLAN_OID_SEC_CFG_AUTH_MODE; + req->req_id = MLAN_IOCTL_SEC_CFG; + req->action = MLAN_ACT_GET; + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, wait_option); + if (status == MLAN_STATUS_SUCCESS && auth_mode) { + *auth_mode = sec->param.auth_mode; + } + done: + if (req && (status != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return status; +} + +/** + * @brief Get encrypt mode + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * @param encrypt_mode A pointer to encrypt mode + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_get_encrypt_mode(moal_private * priv, t_u8 wait_option, + t_u32 * encrypt_mode) +{ + int ret = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_sec_cfg *sec = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + sec = (mlan_ds_sec_cfg *) req->pbuf; + sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_MODE; + req->req_id = MLAN_IOCTL_SEC_CFG; + req->action = MLAN_ACT_GET; + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, wait_option); + if (status == MLAN_STATUS_SUCCESS && encrypt_mode) { + *encrypt_mode = sec->param.encrypt_mode; + } + done: + if (req && (status != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return status; +} + +/** + * @brief Get WPA enable + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * @param enable A pointer to wpa enable status + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_get_wpa_enable(moal_private * priv, t_u8 wait_option, t_u32 * enable) +{ + int ret = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_sec_cfg *sec = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + sec = (mlan_ds_sec_cfg *) req->pbuf; + sec->sub_command = MLAN_OID_SEC_CFG_WPA_ENABLED; + req->req_id = MLAN_IOCTL_SEC_CFG; + req->action = MLAN_ACT_GET; + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, wait_option); + if (status == MLAN_STATUS_SUCCESS && enable) { + *enable = sec->param.wpa_enabled; + } + done: + if (req && (status != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return status; +} + +/** + * @brief Set authentication mode + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * @param auth_mode Authentication mode + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_set_auth_mode(moal_private * priv, t_u8 wait_option, t_u32 auth_mode) +{ + int ret = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_sec_cfg *sec = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + sec = (mlan_ds_sec_cfg *) req->pbuf; + sec->sub_command = MLAN_OID_SEC_CFG_AUTH_MODE; + req->req_id = MLAN_IOCTL_SEC_CFG; + req->action = MLAN_ACT_SET; + sec->param.auth_mode = auth_mode; + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, wait_option); + done: + if (req && (status != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return status; +} + +/** + * @brief Set encrypt mode + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * @param encrypt_mode Encryption mode + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_set_encrypt_mode(moal_private * priv, t_u8 wait_option, t_u32 encrypt_mode) +{ + int ret = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_sec_cfg *sec = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + sec = (mlan_ds_sec_cfg *) req->pbuf; + sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_MODE; + req->req_id = MLAN_IOCTL_SEC_CFG; + req->action = MLAN_ACT_SET; + sec->param.encrypt_mode = encrypt_mode; + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, wait_option); + done: + if (req && (status != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return status; +} + +/** + * @brief Set wpa enable + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * @param enable MTRUE or MFALSE + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_set_wpa_enable(moal_private * priv, t_u8 wait_option, t_u32 enable) +{ + int ret = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_sec_cfg *sec = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + sec = (mlan_ds_sec_cfg *) req->pbuf; + sec->sub_command = MLAN_OID_SEC_CFG_WPA_ENABLED; + req->req_id = MLAN_IOCTL_SEC_CFG; + req->action = MLAN_ACT_SET; + sec->param.wpa_enabled = enable; + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, wait_option); + done: + if (req && (status != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return status; +} + +/** + * @brief enable wep key + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_enable_wep_key(moal_private * priv, t_u8 wait_option) +{ + int ret = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_sec_cfg *sec = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + sec = (mlan_ds_sec_cfg *) req->pbuf; + sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY; + req->req_id = MLAN_IOCTL_SEC_CFG; + req->action = MLAN_ACT_SET; + sec->param.encrypt_key.key_disable = MFALSE; + sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_DEFAULT; + sec->param.encrypt_key.is_current_wep_key = MTRUE; + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, wait_option); + done: + if (req && (status != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return status; +} + +/** + * @brief Request user scan + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * @param scan_cfg A pointer to wlan_user_scan_config structure + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + */ +mlan_status +woal_request_userscan(moal_private * priv, + t_u8 wait_option, wlan_user_scan_cfg * scan_cfg) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_ioctl_req *ioctl_req = NULL; + mlan_ds_scan *scan = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + moal_handle *handle = priv->phandle; + ENTER(); + + if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->async_sem)) { + PRINTM(MERROR, "Acquire semaphore error, request_scan\n"); + LEAVE(); + return MLAN_STATUS_FAILURE; + } + handle->scan_pending_on_block = MTRUE; + + /* Allocate an IOCTL request buffer */ + ioctl_req = + woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan) + + sizeof(wlan_user_scan_cfg)); + if (ioctl_req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + scan = (mlan_ds_scan *) ioctl_req->pbuf; + scan->sub_command = MLAN_OID_SCAN_USER_CONFIG; + ioctl_req->req_id = MLAN_IOCTL_SCAN; + ioctl_req->action = MLAN_ACT_SET; + memcpy(scan->param.user_scan.scan_cfg_buf, scan_cfg, + sizeof(wlan_user_scan_cfg)); + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, ioctl_req, wait_option); + if (status == MLAN_STATUS_FAILURE) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + done: + if ((ioctl_req) && (status != MLAN_STATUS_PENDING)) + kfree(ioctl_req); + + if (ret == MLAN_STATUS_FAILURE) { + handle->scan_pending_on_block = MFALSE; + MOAL_REL_SEMAPHORE(&handle->async_sem); + } + LEAVE(); + return ret; +} + +/** + * @brief set scan time + * + * @param priv A pointer to moal_private structure + * @param passive_scan_time passive scan time + * @param specific_scan_time specific scan time + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + */ +static mlan_status +woal_set_scan_time(moal_private * priv, t_u16 passive_scan_time, + t_u16 specific_scan_time) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_ds_scan *scan = NULL; + mlan_ioctl_req *req = NULL; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan)); + if (req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + scan = (mlan_ds_scan *) req->pbuf; + scan->sub_command = MLAN_OID_SCAN_CONFIG; + req->req_id = MLAN_IOCTL_SCAN; + req->action = MLAN_ACT_SET; + memset(&scan->param.scan_cfg, 0, sizeof(mlan_scan_cfg)); + scan->param.scan_cfg.scan_time.specific_scan_time = specific_scan_time; + scan->param.scan_cfg.scan_time.passive_scan_time = passive_scan_time; + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) + ret = MLAN_STATUS_FAILURE; + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief request scan + * + * @param priv A pointer to moal_private structure + * @param scan_cfg A pointer to wlan_user_scan_cfg structure + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + */ +mlan_status +woal_do_scan(moal_private * priv, wlan_user_scan_cfg * scan_cfg) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + moal_handle *handle = priv->phandle; + + ENTER(); + if (handle->scan_pending_on_block == MTRUE) { + PRINTM(MINFO, "scan already in processing...\n"); + LEAVE(); + return ret; + } +#ifdef REASSOCIATION + if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) { + PRINTM(MERROR, "Acquire semaphore error, woal_do_combo_scan\n"); + LEAVE(); + return -EBUSY; + } +#endif /* REASSOCIATION */ + priv->report_scan_result = MTRUE; + if (!scan_cfg) { + ret = woal_request_scan(priv, MOAL_NO_WAIT, NULL); + } else { + ret = woal_request_userscan(priv, MOAL_NO_WAIT, scan_cfg); + } +#ifdef REASSOCIATION + MOAL_REL_SEMAPHORE(&handle->reassoc_sem); +#endif + LEAVE(); + return ret; +} + +/** + * @brief find ssid in scan_table + * + * @param priv A pointer to moal_private + * @ssid_bssid A pointer to mlan_ssid_bssid structure + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE + */ +int +woal_find_essid(moal_private * priv, mlan_ssid_bssid * ssid_bssid) +{ + int ret = 0; + mlan_scan_resp scan_resp; + struct timeval t; + ENTER(); + + if (MLAN_STATUS_SUCCESS != + woal_get_scan_table(priv, MOAL_IOCTL_WAIT, &scan_resp)) { + LEAVE(); + return MLAN_STATUS_FAILURE; + } + do_gettimeofday(&t); +/** scan result timeout value */ +#define SCAN_RESULT_AGEOUT 10 + if (t.tv_sec > (scan_resp.age_in_secs + SCAN_RESULT_AGEOUT)) { + LEAVE(); + return MLAN_STATUS_FAILURE; + } + ret = woal_find_best_network(priv, MOAL_IOCTL_WAIT, ssid_bssid); + LEAVE(); + return ret; +} + +/** + * @brief Request user scan + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * @param scan_cfg A pointer to wlan_bgscan_cfg structure + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + */ +mlan_status +woal_request_bgscan(moal_private * priv, + t_u8 wait_option, wlan_bgscan_cfg * scan_cfg) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_ioctl_req *ioctl_req = NULL; + mlan_ds_scan *scan = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + ENTER(); + + /* Allocate an IOCTL request buffer */ + ioctl_req = + woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan) + + sizeof(wlan_bgscan_cfg)); + if (ioctl_req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + scan = (mlan_ds_scan *) ioctl_req->pbuf; + scan->sub_command = MLAN_OID_SCAN_BGSCAN_CONFIG; + ioctl_req->req_id = MLAN_IOCTL_SCAN; + ioctl_req->action = MLAN_ACT_SET; + memcpy(scan->param.user_scan.scan_cfg_buf, scan_cfg, + sizeof(wlan_bgscan_cfg)); + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, ioctl_req, wait_option); + if (status == MLAN_STATUS_FAILURE) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + done: + if ((ioctl_req) && (status != MLAN_STATUS_PENDING)) + kfree(ioctl_req); + + LEAVE(); + return ret; +} + +/** + * @brief set bgscan config + * + * @param priv A pointer to moal_private structure + * @param buf A pointer to scan command buf + * @param length buf length + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + */ +mlan_status +woal_set_bg_scan(moal_private * priv, char *buf, int length) +{ + t_u8 *ptr = buf + strlen("BGSCAN-CONFIG") + 1; + int buf_left = length - (strlen("BGSCAN-CONFIG") + 1); + int band = 0; + int num_ssid = 0; + int ssid_len = 0; + mlan_status ret = MLAN_STATUS_SUCCESS; + + ENTER(); + memset(&priv->scan_cfg, 0, sizeof(priv->scan_cfg)); + priv->scan_cfg.report_condition = BG_SCAN_SSID_MATCH; + while (buf_left >= 2) { + switch (*ptr) { + case WEXT_CSCAN_SSID_SECTION: + ssid_len = *(ptr + 1); + if ((buf_left < (ssid_len + 2)) || + (ssid_len > MLAN_MAX_SSID_LENGTH)) { + PRINTM(MERROR, "Invalid ssid, buf_left=%d, ssid_len=%d\n", + buf_left, ssid_len); + buf_left = 0; + break; + } + if (ssid_len && (num_ssid < (MRVDRV_MAX_SSID_LIST_LENGTH - 1))) { + strncpy(priv->scan_cfg.ssid_list[num_ssid].ssid, ptr + 2, + ssid_len); + priv->scan_cfg.ssid_list[num_ssid].max_len = 0; + PRINTM(MIOCTL, "BG scan: ssid=%s\n", + priv->scan_cfg.ssid_list[num_ssid].ssid); + num_ssid++; + } + buf_left -= ssid_len + 2; + ptr += ssid_len + 2; + break; + case WEXT_BGSCAN_RSSI_SECTION: + priv->scan_cfg.report_condition = BG_SCAN_SSID_RSSI_MATCH; + priv->scan_cfg.rssi_threshold = ptr[1]; + PRINTM(MIOCTL, "BG scan: rssi_threshold=%d\n", + (int) priv->scan_cfg.rssi_threshold); + ptr += 2; + buf_left -= 2; + break; + case WEXT_BGSCAN_INTERVAL_SECTION: + priv->scan_cfg.scan_interval = (ptr[2] << 8 | ptr[1]) * 1000; + PRINTM(MIOCTL, "BG scan: scan_interval=%d\n", + (int) priv->scan_cfg.scan_interval); + ptr += 3; + buf_left -= 3; + break; + default: + buf_left = 0; + break; + } + } + /** set bgscan when ssid_num > 0 */ + if (num_ssid) { + if (MLAN_STATUS_SUCCESS != woal_get_band(priv, &band)) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + switch (band) { + case WIFI_FREQUENCY_BAND_2GHZ: + priv->scan_cfg.chan_list[0].radio_type = 0 | BAND_SPECIFIED; + break; + case WIFI_FREQUENCY_BAND_5GHZ: + priv->scan_cfg.chan_list[0].radio_type = 1 | BAND_SPECIFIED; + break; + default: + break; + } + priv->scan_cfg.bss_type = MLAN_BSS_MODE_INFRA; + priv->scan_cfg.action = BG_SCAN_ACT_SET; + priv->scan_cfg.enable = MTRUE; + ret = woal_request_bgscan(priv, MOAL_IOCTL_WAIT, &priv->scan_cfg); + } + done: + LEAVE(); + return ret; +} + +/** + * @brief stop bg scan + * + * @param priv A pointer to moal_private structure + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + */ +mlan_status +woal_stop_bg_scan(moal_private * priv) +{ + wlan_bgscan_cfg scan_cfg; + ENTER(); + + memset(&scan_cfg, 0, sizeof(scan_cfg)); + scan_cfg.action = BG_SCAN_ACT_SET; + scan_cfg.enable = MFALSE; + return woal_request_bgscan(priv, MOAL_IOCTL_WAIT, &scan_cfg); + + LEAVE(); +} + +/** + * @brief set bgscan config + * + * @param handle A pointer to moal_handle structure + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + */ +void +woal_reconfig_bgscan(moal_handle * handle) +{ + int i; + for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) { + if (handle->priv[i] && + (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA)) { + if (handle->priv[i]->bg_scan_start && + handle->priv[i]->bg_scan_reported) { + PRINTM(MIOCTL, "Reconfig BGSCAN\n"); + woal_request_bgscan(handle->priv[i], MOAL_NO_WAIT, + &handle->priv[i]->scan_cfg); + handle->priv[i]->bg_scan_reported = MFALSE; + } + } + } +} + +/** + * @brief set rssi low threshold + * + * @param priv A pointer to moal_private structure + * @param scan_type MLAN_SCAN_TYPE_ACTIVE/MLAN_SCAN_TYPE_PASSIVE + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + */ +mlan_status +woal_set_rssi_low_threshold(moal_private * priv, char *rssi) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_ioctl_req *req = NULL; + mlan_ds_misc_cfg *misc = NULL; + int low_rssi = 0; + + ENTER(); + if (priv->media_connected == MFALSE) + goto done; + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + misc = (mlan_ds_misc_cfg *) req->pbuf; + req->req_id = MLAN_IOCTL_MISC_CFG; + misc->sub_command = MLAN_OID_MISC_SUBSCRIBE_EVENT; + req->action = MLAN_ACT_SET; + misc->param.subscribe_event.evt_bitmap = SUBSCRIBE_EVT_RSSI_LOW; + if (MLAN_STATUS_SUCCESS != woal_atoi(&low_rssi, rssi)) { + ret = -EFAULT; + goto done; + } + misc->param.subscribe_event.low_rssi = low_rssi; + misc->param.subscribe_event.low_rssi_freq = 0; + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Get power mode + * + * @param priv A pointer to moal_private structure + * @param powermode A pointer to powermode buf + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + */ +mlan_status +woal_get_powermode(moal_private * priv, int *powermode) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + int ps_mode; + + ENTER(); + + if (MLAN_STATUS_SUCCESS != + woal_set_get_power_mgmt(priv, MLAN_ACT_GET, &ps_mode, 0)) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + if (ps_mode) + *powermode = MFALSE; + else + *powermode = MTRUE; + + done: + LEAVE(); + return ret; +} + +/** + * @brief set scan type + * + * @param priv A pointer to moal_private structure + * @param scan_type MLAN_SCAN_TYPE_ACTIVE/MLAN_SCAN_TYPE_PASSIVE + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + */ +mlan_status +woal_set_scan_type(moal_private * priv, t_u32 scan_type) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_ds_scan *scan = NULL; + mlan_ioctl_req *req = NULL; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan)); + if (req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + scan = (mlan_ds_scan *) req->pbuf; + scan->sub_command = MLAN_OID_SCAN_CONFIG; + req->req_id = MLAN_IOCTL_SCAN; + req->action = MLAN_ACT_SET; + memset(&scan->param.scan_cfg, 0, sizeof(mlan_scan_cfg)); + scan->param.scan_cfg.scan_type = scan_type; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) + ret = MLAN_STATUS_FAILURE; + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief set power mode + * + * @param priv A pointer to moal_private structure + * @param powermode A pointer to powermode string. + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + */ +mlan_status +woal_set_powermode(moal_private * priv, char *powermode) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + int disabled; + + ENTER(); + + if (*powermode == '1') { + PRINTM(MIOCTL, "Disable power save\n"); + disabled = 1; + } else if (*powermode == '0') { + PRINTM(MIOCTL, "Enable power save\n"); + disabled = 0; + } else { + PRINTM(MERROR, "unsupported power mode\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + if (MLAN_STATUS_SUCCESS != + woal_set_get_power_mgmt(priv, MLAN_ACT_SET, &disabled, 0)) + ret = MLAN_STATUS_FAILURE; + + done: + LEAVE(); + return ret; +} + +/** + * @brief set combo scan + * + * @param priv A pointer to moal_private structure + * @param buf A pointer to scan command buf + * @param length buf length + * + * @return 0 -- success, otherwise fail + */ +int +woal_set_combo_scan(moal_private * priv, char *buf, int length) +{ + int ret = 0; + wlan_user_scan_cfg scan_cfg; + t_u8 *ptr = buf + WEXT_CSCAN_HEADER_SIZE; + int buf_left = length - WEXT_CSCAN_HEADER_SIZE; + int num_ssid = 0; + int num_chan = 0; + int ssid_len = 0; + int i = 0; + t_u16 passive_scan_time = 0; + t_u16 specific_scan_time = 0; + + ENTER(); + memset(&scan_cfg, 0, sizeof(scan_cfg)); + while (buf_left >= 2) { + switch (*ptr) { + case WEXT_CSCAN_SSID_SECTION: + ssid_len = *(ptr + 1); + if ((buf_left < (ssid_len + 2)) || + (ssid_len > MLAN_MAX_SSID_LENGTH)) { + PRINTM(MERROR, "Invalid ssid, buf_left=%d, ssid_len=%d\n", + buf_left, ssid_len); + buf_left = 0; + break; + } + if (ssid_len && (num_ssid < (MRVDRV_MAX_SSID_LIST_LENGTH - 1))) { + strncpy(scan_cfg.ssid_list[num_ssid].ssid, ptr + 2, ssid_len); + scan_cfg.ssid_list[num_ssid].max_len = 0; + PRINTM(MIOCTL, "Combo scan: ssid=%s\n", + scan_cfg.ssid_list[num_ssid].ssid); + num_ssid++; + } + buf_left -= ssid_len + 2; + ptr += ssid_len + 2; + break; + case WEXT_CSCAN_CHANNEL_SECTION: + num_chan = ptr[1]; + if ((buf_left < (num_chan + 2)) || + (num_chan > WLAN_USER_SCAN_CHAN_MAX)) { + PRINTM(MERROR, + "Invalid channel list, buf_left=%d, num_chan=%d\n", + buf_left, num_chan); + buf_left = 0; + break; + } + for (i = 0; i < num_chan; i++) { + scan_cfg.chan_list[i].chan_number = ptr[2 + i]; + PRINTM(MIOCTL, "Combo scan: chan=%d\n", + scan_cfg.chan_list[i].chan_number); + } + buf_left -= 2 + num_chan; + ptr += 2 + num_chan; + break; + case WEXT_CSCAN_PASV_DWELL_SECTION: + if (buf_left < 3) { + PRINTM(MERROR, "Invalid PASV_DWELL_SECTION, buf_left=%d\n", + buf_left); + buf_left = 0; + break; + } + passive_scan_time = ptr[2] << 8 | ptr[1]; + ptr += 3; + buf_left -= 3; + break; + case WEXT_CSCAN_HOME_DWELL_SECTION: + if (buf_left < 3) { + PRINTM(MERROR, "Invalid HOME_DWELL_SECTION, buf_left=%d\n", + buf_left); + buf_left = 0; + break; + } + specific_scan_time = ptr[2] << 8 | ptr[1]; + ptr += 3; + buf_left -= 3; + break; + default: + buf_left = 0; + break; + } + } + if (passive_scan_time || specific_scan_time) { + PRINTM(MIOCTL, "Set passive_scan_time=%d specific_scan_time=%d\n", + passive_scan_time, specific_scan_time); + if (MLAN_STATUS_FAILURE == + woal_set_scan_time(priv, passive_scan_time, specific_scan_time)) { + ret = -EFAULT; + goto done; + } + } + if (num_ssid || num_chan) { + if (num_ssid) { + /* Add broadcast scan to ssid_list */ + scan_cfg.ssid_list[num_ssid].max_len = 0xff; + if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE) + woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE); + } + if (MLAN_STATUS_FAILURE == woal_do_scan(priv, &scan_cfg)) + ret = -EFAULT; + if (num_ssid && (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE)) + woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE); + } else { + /* request broadcast scan */ + if (MLAN_STATUS_FAILURE == woal_do_scan(priv, NULL)) + ret = -EFAULT; + } + done: + LEAVE(); + return ret; +} + +/** + * @brief Get band + * + * @param priv A pointer to moal_private structure + * @param band A pointer to band buf + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + */ +mlan_status +woal_get_band(moal_private * priv, int *band) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_ioctl_req *req = NULL; + mlan_ds_radio_cfg *radio_cfg = NULL; + int support_band = 0; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg)); + if (req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + radio_cfg = (mlan_ds_radio_cfg *) req->pbuf; + radio_cfg->sub_command = MLAN_OID_BAND_CFG; + req->req_id = MLAN_IOCTL_RADIO_CFG; + /* Get config_bands, adhoc_start_band and adhoc_channel values from MLAN */ + req->action = MLAN_ACT_GET; + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + if (radio_cfg->param.band_cfg.config_bands & (BAND_B | BAND_G | BAND_GN)) + support_band |= WIFI_FREQUENCY_BAND_2GHZ; + if (radio_cfg->param.band_cfg.config_bands & (BAND_A | BAND_AN)) + support_band |= WIFI_FREQUENCY_BAND_5GHZ; + *band = support_band; + if (support_band == WIFI_FREQUENCY_ALL_BAND) + *band = WIFI_FREQUENCY_BAND_AUTO; + done: + if (req) + kfree(req); + + LEAVE(); + return ret; +} + +/** + * @brief set band + * + * @param priv A pointer to moal_private structure + * @param pband A pointer to band string. + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + */ +mlan_status +woal_set_band(moal_private * priv, char *pband) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + int band = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_radio_cfg *radio_cfg = NULL; + + ENTER(); + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg)); + if (req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + radio_cfg = (mlan_ds_radio_cfg *) req->pbuf; + radio_cfg->sub_command = MLAN_OID_BAND_CFG; + req->req_id = MLAN_IOCTL_RADIO_CFG; + + /* Get fw supported values from MLAN */ + req->action = MLAN_ACT_GET; + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + if (*pband == '0') { + PRINTM(MIOCTL, "Set band to AUTO\n"); + band = radio_cfg->param.band_cfg.fw_bands; +#if defined(STA_CFG80211) || defined(UAP_CFG80211) + if (IS_STA_OR_UAP_CFG80211(cfg80211_wext) && priv->wdev && + priv->wdev->wiphy) { + if (radio_cfg->param.band_cfg.fw_bands & BAND_A) + priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = + &cfg80211_band_5ghz; + priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &cfg80211_band_2ghz; + } +#endif + } else if (*pband == '1') { + PRINTM(MIOCTL, "Set band to 5G\n"); + if (!(radio_cfg->param.band_cfg.fw_bands & BAND_A)) { + PRINTM(MERROR, "Don't support 5G band\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + band = BAND_A; + band |= BAND_AN; +#if defined(STA_CFG80211) || defined(UAP_CFG80211) + if (IS_STA_OR_UAP_CFG80211(cfg80211_wext) && priv->wdev && + priv->wdev->wiphy) { + priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &cfg80211_band_5ghz; + priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = NULL; + } +#endif + } else if (*pband == '2') { + PRINTM(MIOCTL, "Set band to 2G\n"); + band = BAND_B | BAND_G; + band |= BAND_GN; +#if defined(STA_CFG80211) || defined(UAP_CFG80211) + if (IS_STA_OR_UAP_CFG80211(cfg80211_wext) && priv->wdev && + priv->wdev->wiphy) { + priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; + priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &cfg80211_band_2ghz; + } +#endif + } else { + PRINTM(MERROR, "unsupported band\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + /* Set config_bands to MLAN */ + req->action = MLAN_ACT_SET; + memset(&radio_cfg->param.band_cfg, 0, sizeof(mlan_ds_band_cfg)); + radio_cfg->param.band_cfg.config_bands = band; + radio_cfg->param.band_cfg.adhoc_start_band = band; + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Add RX Filter + * + * @param priv A pointer to moal_private structure + * @param rxfilter A pointer to rxfilter string. + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + */ +mlan_status +woal_add_rxfilter(moal_private * priv, char *rxfilter) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + ENTER(); + /* Android command: "DRIVER RXFILTER-ADD 0" "DRIVER RXFILTER-ADD 1" "DRIVER + RXFILTER-ADD 3" */ + if (*rxfilter == '0') { + PRINTM(MIOCTL, "Add IPV4 multicast filter\n"); + priv->rx_filter |= RX_FILTER_IPV4_MULTICAST; + } else if (*rxfilter == '1') { + PRINTM(MIOCTL, "Add broadcast filter\n"); + priv->rx_filter |= RX_FILTER_BROADCAST; + } else if (*rxfilter == '2') { + PRINTM(MIOCTL, "Add unicast filter\n"); + priv->rx_filter |= RX_FILTER_UNICAST; + } else if (*rxfilter == '3') { + PRINTM(MIOCTL, "Add IPV6 multicast fitler\n"); + priv->rx_filter |= RX_FILTER_IPV6_MULTICAST; + } else { + PRINTM(MERROR, "unsupported rx fitler\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + done: + LEAVE(); + return ret; +} + +/** + * @brief Remove RX Filter + * + * @param priv A pointer to moal_private structure + * @param rxfilter A pointer to rxfilter string. + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + */ +mlan_status +woal_remove_rxfilter(moal_private * priv, char *rxfilter) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + ENTER(); + if (*rxfilter == '0') { + PRINTM(MIOCTL, "Remove IPV4 multicast filter\n"); + priv->rx_filter &= ~RX_FILTER_IPV4_MULTICAST; + } else if (*rxfilter == '1') { + PRINTM(MIOCTL, "Remove broadcast filter\n"); + priv->rx_filter &= ~RX_FILTER_BROADCAST; + } else if (*rxfilter == '2') { + PRINTM(MIOCTL, "Remove unicast filter\n"); + priv->rx_filter &= ~RX_FILTER_UNICAST; + } else if (*rxfilter == '3') { + PRINTM(MIOCTL, "Remove IPV6 multicast fitler\n"); + priv->rx_filter &= ~RX_FILTER_IPV6_MULTICAST; + } else { + PRINTM(MERROR, "unsupported rx fitler\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + done: + LEAVE(); + return ret; +} + +/** + * @brief Set QoS configuration + * + * @param priv A pointer to moal_private structure + * @param qos_cfg A pointer to QoS configuration structure + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + */ +mlan_status +woal_set_qos_cfg(moal_private * priv, char *qos_cfg) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_ds_wmm_cfg *cfg = NULL; + mlan_ioctl_req *req = NULL; + int qosinfo = 0; + + ENTER(); + if (MLAN_STATUS_SUCCESS != woal_atoi(&qosinfo, qos_cfg)) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + PRINTM(MIOCTL, "set qosinfo=%d\n", qosinfo); + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg)); + if (req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + cfg = (mlan_ds_wmm_cfg *) req->pbuf; + cfg->sub_command = MLAN_OID_WMM_CFG_QOS; + req->req_id = MLAN_IOCTL_WMM_CFG; + req->action = MLAN_ACT_SET; + cfg->param.qos_cfg = (t_u8) qosinfo; + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) + ret = MLAN_STATUS_FAILURE; + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Set sleep period + * + * @param priv A pointer to moal_private structure + * @param psleeppd A pointer to sleep period configuration structure + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + */ +int +woal_set_sleeppd(moal_private * priv, char *psleeppd) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_ds_pm_cfg *pm_cfg = NULL; + mlan_ioctl_req *req = NULL; + int sleeppd = 0; + + ENTER(); + + if (MLAN_STATUS_SUCCESS != woal_atoi(&sleeppd, psleeppd)) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + PRINTM(MIOCTL, "set sleeppd=%d\n", sleeppd); + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg)); + if (req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + pm_cfg = (mlan_ds_pm_cfg *) req->pbuf; + pm_cfg->sub_command = MLAN_OID_PM_CFG_SLEEP_PD; + req->req_id = MLAN_IOCTL_PM_CFG; + if ((sleeppd <= MAX_SLEEP_PERIOD && sleeppd >= MIN_SLEEP_PERIOD) || + (sleeppd == 0) + || (sleeppd == SLEEP_PERIOD_RESERVED_FF) + ) { + req->action = MLAN_ACT_SET; + pm_cfg->param.sleep_period = sleeppd; + } else { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +#endif /* STA_SUPPORT */ diff --git a/drivers/net/wireless/sd8797/mlinux/moal_main.c b/drivers/net/wireless/sd8797/mlinux/moal_main.c new file mode 100644 index 000000000000..820c1267cc78 --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/moal_main.c @@ -0,0 +1,3773 @@ +/** @file moal_main.c + * + * @brief This file contains the major functions in WLAN + * driver. + * + * Copyright (C) 2008-2012, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +/******************************************************** +Change log: + 10/21/2008: initial version +********************************************************/ + +#include "moal_main.h" +#include "moal_sdio.h" +#ifdef UAP_SUPPORT +#include "moal_uap.h" +#endif +#if defined(STA_CFG80211) || defined(UAP_CFG80211) +#include "moal_cfg80211.h" +#endif +#ifdef STA_CFG80211 +#ifdef STA_SUPPORT +#include "moal_sta_cfg80211.h" +#endif +#endif +#ifdef UAP_CFG80211 +#ifdef UAP_SUPPORT +#include "moal_uap_cfg80211.h" +#endif +#endif +#include +#include +#include "moal_eth_ioctl.h" + +/******************************************************** + Local Variables +********************************************************/ + +#define KERN_VERSION "26" + +/** Driver version */ +char driver_version[] = + "SD8797-%s-M2614" MLAN_RELEASE_VERSION "-GPL" "-(" "FP" FPNUM ")" +#ifdef DEBUG_LEVEL2 + "-dbg" +#endif + " "; + +/** Firmware name */ +char *fw_name = NULL; +int req_fw_nowait = 0; + +/** MAC address */ +char *mac_addr = NULL; + +#ifdef MFG_CMD_SUPPORT +/** Mfg mode */ +int mfg_mode = 0; +#endif + +/** SDIO interrupt mode (0: INT_MODE_SDIO, 1: INT_MODE_GPIO) */ +int intmode = INT_MODE_SDIO; +/** GPIO interrupt pin number */ +int gpiopin = 0; + +/** Auto deep sleep */ +int auto_ds = 0; + +/** IEEE PS mode */ +int ps_mode = 0; + +/** Max Tx buffer size */ +int max_tx_buf = 0; + +#ifdef STA_SUPPORT +/** Max STA interfaces */ +int max_sta_bss = DEF_STA_BSS; +#endif + +#ifdef UAP_SUPPORT +/** Max uAP interfaces */ +int max_uap_bss = DEF_UAP_BSS; +#endif + +#if defined(WIFI_DIRECT_SUPPORT) +/** Max WIFIDIRECT interfaces */ +int max_wfd_bss = DEF_WIFIDIRECT_BSS; +#endif + +#ifdef SDIO_SUSPEND_RESUME +/** PM keep power */ +int pm_keep_power = 1; +#endif + +#if defined(STA_SUPPORT) +/** 802.11d configuration */ +int cfg_11d = 0; +#endif + +/** CAL data config file */ +char *cal_data_cfg = NULL; +/** Init config file (MAC address, register etc.) */ +char *init_cfg = NULL; + +/** Enable minicard power-up/down */ +int minicard_pwrup = 1; +/** Pointer to struct with control hooks */ +struct wifi_platform_data *wifi_control_data = NULL; + +int cfg80211_wext = STA_WEXT_MASK | UAP_WEXT_MASK; + +/** woal_callbacks */ +static mlan_callbacks woal_callbacks = { + .moal_get_fw_data = moal_get_fw_data, + .moal_init_fw_complete = moal_init_fw_complete, + .moal_shutdown_fw_complete = moal_shutdown_fw_complete, + .moal_send_packet_complete = moal_send_packet_complete, + .moal_recv_packet = moal_recv_packet, + .moal_recv_event = moal_recv_event, + .moal_ioctl_complete = moal_ioctl_complete, + .moal_alloc_mlan_buffer = moal_alloc_mlan_buffer, + .moal_free_mlan_buffer = moal_free_mlan_buffer, + .moal_write_reg = moal_write_reg, + .moal_read_reg = moal_read_reg, + .moal_write_data_sync = moal_write_data_sync, + .moal_read_data_sync = moal_read_data_sync, + .moal_malloc = moal_malloc, + .moal_mfree = moal_mfree, + .moal_memset = moal_memset, + .moal_memcpy = moal_memcpy, + .moal_memmove = moal_memmove, + .moal_memcmp = moal_memcmp, + .moal_udelay = moal_udelay, + .moal_get_system_time = moal_get_system_time, + .moal_init_timer = moal_init_timer, + .moal_free_timer = moal_free_timer, + .moal_start_timer = moal_start_timer, + .moal_stop_timer = moal_stop_timer, + .moal_init_lock = moal_init_lock, + .moal_free_lock = moal_free_lock, + .moal_spin_lock = moal_spin_lock, + .moal_spin_unlock = moal_spin_unlock, + .moal_print = moal_print, + .moal_print_netintf = moal_print_netintf, + .moal_assert = moal_assert, +}; + +/** Default Driver mode */ +#if defined(STA_SUPPORT) && defined(UAP_SUPPORT) +#if defined(WIFI_DIRECT_SUPPORT) +int drv_mode = (DRV_MODE_STA | DRV_MODE_UAP | DRV_MODE_WIFIDIRECT); +#else +int drv_mode = (DRV_MODE_STA | DRV_MODE_UAP); +#endif +#else +#ifdef STA_SUPPORT +int drv_mode = DRV_MODE_STA; +#else +int drv_mode = DRV_MODE_UAP; +#endif /* STA_SUPPORT */ +#endif /* STA_SUPPORT & UAP_SUPPORT */ + +/******************************************************** + Global Variables +********************************************************/ + +/** Semaphore for add/remove card */ +struct semaphore AddRemoveCardSem; +/** + * the maximum number of adapter supported + **/ +#define MAX_MLAN_ADAPTER 2 +/** + * The global variable of a pointer to moal_handle + * structure variable + **/ +moal_handle *m_handle[MAX_MLAN_ADAPTER]; + +#ifdef DEBUG_LEVEL1 +#ifdef DEBUG_LEVEL2 +#define DEFAULT_DEBUG_MASK (0xffffffff) +#else +#define DEFAULT_DEBUG_MASK (MMSG | MFATAL | MERROR) +#endif /* DEBUG_LEVEL2 */ +t_u32 drvdbg = DEFAULT_DEBUG_MASK; +#endif /* DEBUG_LEVEL1 */ + +int woal_open(struct net_device *dev); +int woal_close(struct net_device *dev); +int woal_set_mac_address(struct net_device *dev, void *addr); +void woal_tx_timeout(struct net_device *dev); +struct net_device_stats *woal_get_stats(struct net_device *dev); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) +u16 woal_select_queue(struct net_device *dev, struct sk_buff *skb); +#endif + +mlan_debug_info info; + +/******************************************************** + Local Functions +********************************************************/ + +/** + * @brief This function dynamically populates the driver mode table + * + * @param handle A pointer to moal_handle structure + * @param drv_mode_local Driver mode + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +static mlan_status +woal_update_drv_tbl(moal_handle * handle, int drv_mode_local) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + unsigned int intf_num = 0; + int i = 0, j = 0; + mlan_bss_attr *bss_tbl = NULL; + + ENTER(); + + /* Calculate number of interfaces */ +#ifdef STA_SUPPORT + if (drv_mode_local & DRV_MODE_STA) { + if ((max_sta_bss < 1) || (max_sta_bss > MAX_STA_BSS)) { + PRINTM(MWARN, "Unsupported max_sta_bss (%d), setting to default\n", + max_sta_bss); + max_sta_bss = DEF_STA_BSS; + } + intf_num += max_sta_bss; + } +#endif /* STA_SUPPORT */ + +#ifdef UAP_SUPPORT + if (drv_mode_local & DRV_MODE_UAP) { + if ((max_uap_bss < 1) || (max_uap_bss > MAX_UAP_BSS)) { + PRINTM(MWARN, "Unsupported max_uap_bss (%d), setting to default\n", + max_uap_bss); + max_uap_bss = DEF_UAP_BSS; + } + intf_num += max_uap_bss; + } +#endif /* UAP_SUPPORT */ + +#if defined(WIFI_DIRECT_SUPPORT) + if (drv_mode_local & DRV_MODE_WIFIDIRECT) { + if ((max_wfd_bss < 1) || (max_wfd_bss > MAX_WIFIDIRECT_BSS)) { + PRINTM(MWARN, "Unsupported max_wfd_bss (%d), setting to default\n", + max_wfd_bss); + max_wfd_bss = DEF_WIFIDIRECT_BSS; + } + intf_num += max_wfd_bss; + } +#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */ + + /* Create BSS attribute table */ + if ((intf_num == 0) || (intf_num > MLAN_MAX_BSS_NUM)) { + PRINTM(MERROR, "Unsupported number of BSS %d\n", intf_num); + ret = MLAN_STATUS_FAILURE; + goto done; + } else { + /* Create new table */ + if (! + (bss_tbl = + (mlan_bss_attr *) kmalloc(sizeof(mlan_bss_attr) * intf_num, + GFP_KERNEL))) { + PRINTM(MERROR, "Could not create BSS attribute table\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + } + + /* Populate BSS attribute table */ +#ifdef STA_SUPPORT + if (drv_mode_local & DRV_MODE_STA) { + for (j = 0; j < max_sta_bss; j++) { + if (i >= intf_num) + break; + bss_tbl[i].bss_type = MLAN_BSS_TYPE_STA; + bss_tbl[i].frame_type = MLAN_DATA_FRAME_TYPE_ETH_II; + bss_tbl[i].active = MTRUE; + bss_tbl[i].bss_priority = 0; + bss_tbl[i].bss_num = j; + i++; + } + } +#endif /* STA_SUPPORT */ + +#ifdef UAP_SUPPORT + if (drv_mode_local & DRV_MODE_UAP) { + for (j = 0; j < max_uap_bss; j++) { + if (i >= intf_num) + break; + bss_tbl[i].bss_type = MLAN_BSS_TYPE_UAP; + bss_tbl[i].frame_type = MLAN_DATA_FRAME_TYPE_ETH_II; + bss_tbl[i].active = MTRUE; + bss_tbl[i].bss_priority = 0; + bss_tbl[i].bss_num = j; + i++; + } + } +#endif /* UAP_SUPPORT */ + +#if defined(WIFI_DIRECT_SUPPORT) + if (drv_mode_local & DRV_MODE_WIFIDIRECT) { + for (j = 0; j < max_wfd_bss; j++) { + if (i >= intf_num) + break; + bss_tbl[i].bss_type = MLAN_BSS_TYPE_WIFIDIRECT; + bss_tbl[i].frame_type = MLAN_DATA_FRAME_TYPE_ETH_II; + bss_tbl[i].active = MTRUE; + bss_tbl[i].bss_priority = 0; + bss_tbl[i].bss_num = j; + i++; + } + } +#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */ + + /* Clear existing table, if any */ + if (handle->drv_mode.bss_attr != NULL) { + kfree(handle->drv_mode.bss_attr); + handle->drv_mode.bss_attr = NULL; + } + + /* Create moal_drv_mode entry */ + handle->drv_mode.drv_mode = drv_mode; + handle->drv_mode.intf_num = intf_num; + handle->drv_mode.bss_attr = bss_tbl; + if (fw_name) { + handle->drv_mode.fw_name = fw_name; + } else { +#if defined(UAP_SUPPORT) && defined(STA_SUPPORT) + handle->drv_mode.fw_name = DEFAULT_AP_STA_FW_NAME; +#else +#ifdef UAP_SUPPORT + handle->drv_mode.fw_name = DEFAULT_AP_FW_NAME; +#else + handle->drv_mode.fw_name = DEFAULT_FW_NAME; +#endif /* UAP_SUPPORT */ +#endif /* UAP_SUPPORT && STA_SUPPORT */ + } + + done: + LEAVE(); + return ret; +} + +/** + * @brief This function initializes software + * + * @param handle A pointer to moal_handle structure + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +static mlan_status +woal_init_sw(moal_handle * handle) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + unsigned int i; + mlan_device device; + t_void *pmlan; + + ENTER(); + + /* Initialize moal_handle structure */ + handle->hardware_status = HardwareStatusInitializing; + handle->main_state = MOAL_STATE_IDLE; + +#ifdef STA_SUPPORT + if (MTRUE +#ifdef STA_WEXT + && !IS_STA_WEXT(cfg80211_wext) +#endif +#ifdef STA_CFG80211 + && !IS_STA_CFG80211(cfg80211_wext) +#endif + ) { + PRINTM(MERROR, "STA without WEXT or CFG80211 bit definition!\n"); + LEAVE(); + return MLAN_STATUS_FAILURE; + } +#endif /* STA_SUPPORT */ + + if (woal_update_drv_tbl(handle, drv_mode) != MLAN_STATUS_SUCCESS) { + PRINTM(MERROR, "Could not update driver mode table\n"); + LEAVE(); + return MLAN_STATUS_FAILURE; + } + + /* PnP and power profile */ + handle->surprise_removed = MFALSE; + init_waitqueue_head(&handle->init_wait_q); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) + spin_lock_init(&handle->queue_lock); +#endif + +#if defined(SDIO_SUSPEND_RESUME) + handle->is_suspended = MFALSE; + handle->hs_activated = MFALSE; + handle->suspend_fail = MFALSE; +#ifdef SDIO_SUSPEND_RESUME + handle->suspend_notify_req = MFALSE; +#endif + handle->hs_skip_count = 0; + handle->hs_force_count = 0; + handle->cmd52_func = 0; + handle->cmd52_reg = 0; + handle->cmd52_val = 0; + init_waitqueue_head(&handle->hs_activate_wait_q); +#endif + + /* Initialize measurement wait queue */ + handle->meas_wait_q_woken = MFALSE; + handle->meas_start_jiffies = 0; + handle->cac_period = MFALSE; + handle->delay_bss_start = MFALSE; + init_waitqueue_head(&handle->meas_wait_q); +#ifdef DFS_TESTING_SUPPORT + handle->cac_period_jiffies = 0; +#endif + +#ifdef REASSOCIATION + MOAL_INIT_SEMAPHORE(&handle->reassoc_sem); + handle->reassoc_on = 0; + + /* Initialize the timer for the reassociation */ + woal_initialize_timer(&handle->reassoc_timer, + woal_reassoc_timer_func, handle); + + handle->is_reassoc_timer_set = MFALSE; +#endif /* REASSOCIATION */ + + /* Register to MLAN */ + memset(&device, 0, sizeof(mlan_device)); + device.pmoal_handle = handle; + +#ifdef MFG_CMD_SUPPORT + device.mfg_mode = (t_u32) mfg_mode; +#endif + device.int_mode = (t_u32) intmode; + device.gpio_pin = (t_u32) gpiopin; +#ifdef DEBUG_LEVEL1 + device.drvdbg = drvdbg; +#endif + device.auto_ds = (t_u32) auto_ds; + device.ps_mode = (t_u32) ps_mode; + device.max_tx_buf = (t_u32) max_tx_buf; +#if defined(STA_SUPPORT) + device.cfg_11d = (t_u32) cfg_11d; +#endif +#ifdef SDIO_MULTI_PORT_TX_AGGR +#ifdef MMC_QUIRK_BLKSZ_FOR_BYTE_MODE + device.mpa_tx_cfg = MLAN_INIT_PARA_ENABLED; +#else + device.mpa_tx_cfg = MLAN_INIT_PARA_DISABLED; +#endif +#endif +#ifdef SDIO_MULTI_PORT_RX_AGGR +#ifdef MMC_QUIRK_BLKSZ_FOR_BYTE_MODE + device.mpa_rx_cfg = MLAN_INIT_PARA_ENABLED; +#else + device.mpa_rx_cfg = MLAN_INIT_PARA_DISABLED; +#endif +#endif + + for (i = 0; i < handle->drv_mode.intf_num; i++) { + device.bss_attr[i].bss_type = handle->drv_mode.bss_attr[i].bss_type; + device.bss_attr[i].frame_type = handle->drv_mode.bss_attr[i].frame_type; + device.bss_attr[i].active = handle->drv_mode.bss_attr[i].active; + device.bss_attr[i].bss_priority = + handle->drv_mode.bss_attr[i].bss_priority; + device.bss_attr[i].bss_num = handle->drv_mode.bss_attr[i].bss_num; + } + memcpy(&device.callbacks, &woal_callbacks, sizeof(mlan_callbacks)); + + sdio_claim_host(((struct sdio_mmc_card *) handle->card)->func); + if (MLAN_STATUS_SUCCESS == mlan_register(&device, &pmlan)) + handle->pmlan_adapter = pmlan; + else + ret = MLAN_STATUS_FAILURE; + sdio_release_host(((struct sdio_mmc_card *) handle->card)->func); + + LEAVE(); + return ret; +} + +/** + * @brief This function frees the structure of moal_handle + * + * @param handle A pointer to moal_handle structure + * + * @return N/A + */ +static void +woal_free_moal_handle(moal_handle * handle) +{ + ENTER(); + if (!handle) { + PRINTM(MERROR, "The handle is NULL\n"); + LEAVE(); + return; + } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25) + if ((handle->nl_sk) && ((handle->nl_sk)->sk_socket)) { + sock_release((handle->nl_sk)->sk_socket); + handle->nl_sk = NULL; + } +#else + netlink_kernel_release(handle->nl_sk); +#endif + + if (handle->pmlan_adapter) + mlan_unregister(handle->pmlan_adapter); + + /* Free BSS attribute table */ + if (handle->drv_mode.bss_attr != NULL) { + kfree(handle->drv_mode.bss_attr); + handle->drv_mode.bss_attr = NULL; + } + PRINTM(MINFO, "Free Adapter\n"); + if (handle->malloc_count || handle->lock_count || handle->mbufalloc_count) { + PRINTM(MERROR, + "mlan has memory leak: malloc_count=%u lock_count=%u mbufalloc_count=%u\n", + handle->malloc_count, handle->lock_count, + handle->mbufalloc_count); + } + /* Free the moal handle itself */ + kfree(handle); + LEAVE(); +} + +/** + * @brief WOAL get one line data from ASCII format data + * + * @param data Source data + * @param size Source data length + * @param line_pos Destination data + * @return routnine status + */ +static t_size +parse_cfg_get_line(t_u8 * data, t_size size, t_u8 * line_pos) +{ + t_u8 *src, *dest; + static t_s32 pos = 0; + + ENTER(); + + if (pos >= size) { /* reach the end */ + pos = 0; /* Reset position for rfkill */ + LEAVE(); + return -1; + } + memset(line_pos, 0, MAX_LINE_LEN); + src = data + pos; + dest = line_pos; + + while (*src != '\x0A' && *src != '\0') { + if (*src != ' ' && *src != '\t') /* parse space */ + *dest++ = *src++; + else + src++; + pos++; + } + /* parse new line */ + pos++; + *dest = '\0'; + LEAVE(); + return strlen(line_pos); +} + +/** + * @brief Process register access request + * @param type_string String format Register type + * @param offset_string String format Register offset + * @param value_string String format Pointer to value + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static t_u32 +woal_process_regrdwr(moal_handle * handle, t_u8 * type_string, + t_u8 * offset_string, t_u8 * value_string) +{ + mlan_status ret = MLAN_STATUS_FAILURE; + int type, offset, value; + pmlan_ioctl_req ioctl_req = NULL; + mlan_ds_reg_mem *reg = NULL; + + ENTER(); + + /* Alloc ioctl_req */ + ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem)); + + if (ioctl_req == NULL) { + PRINTM(MERROR, "Can't alloc memory\n"); + goto done; + } + + if (MLAN_STATUS_SUCCESS != woal_atoi(&type, type_string)) { + goto done; + } + if (MLAN_STATUS_SUCCESS != woal_atoi(&offset, offset_string)) { + goto done; + } + if (MLAN_STATUS_SUCCESS != woal_atoi(&value, value_string)) { + goto done; + } + + ioctl_req->req_id = MLAN_IOCTL_REG_MEM; + ioctl_req->action = MLAN_ACT_SET; + + reg = (mlan_ds_reg_mem *) ioctl_req->pbuf; + reg->sub_command = MLAN_OID_REG_RW; + if (type < 5) { + reg->param.reg_rw.type = type; + } else { + PRINTM(MERROR, "Unsupported Type\n"); + goto done; + } + reg->param.reg_rw.offset = offset; + reg->param.reg_rw.value = value; + + /* request ioctl for STA */ + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(handle->priv[0], ioctl_req, MOAL_IOCTL_WAIT)) { + goto done; + } + PRINTM(MINFO, "Register type: %d, offset: 0x%x, value: 0x%x\n", type, + offset, value); + ret = MLAN_STATUS_SUCCESS; + + done: + if (ioctl_req) + kfree(ioctl_req); + LEAVE(); + return ret; +} + +/** + * @brief WOAL parse ASCII format data to MAC address + * + * @param handle MOAL handle + * @param data Source data + * @param size data length + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static t_u32 +woal_process_init_cfg(moal_handle * handle, t_u8 * data, t_size size) +{ + mlan_status ret = MLAN_STATUS_FAILURE; + t_u8 *pos; + t_u8 *intf_s, *intf_e; + t_u8 s[MAX_LINE_LEN]; /* 1 line data */ + t_size line_len; + t_u8 index = 0; + t_u32 i; + t_u8 bss_mac_addr[MAX_MAC_ADDR_LEN]; + t_u8 bss_mac_name[MAX_PARAM_LEN]; + t_u8 type[MAX_PARAM_LEN]; + t_u8 offset[MAX_PARAM_LEN]; + t_u8 value[MAX_PARAM_LEN]; + + ENTER(); + + while ((line_len = parse_cfg_get_line(data, size, s)) != -1) { + + pos = s; + while (*pos == ' ' || *pos == '\t') + pos++; + + if (*pos == '#' || (*pos == '\r' && *(pos + 1) == '\n') || + *pos == '\n' || *pos == '\0') + continue; /* Needn't process this line */ + + /* Process MAC addr */ + if (strncmp(pos, "mac_addr", 8) == 0) { + intf_s = strchr(pos, '='); + if (intf_s != NULL) + intf_e = strchr(intf_s, ':'); + else + intf_e = NULL; + if (intf_s != NULL && intf_e != NULL) { + strncpy(bss_mac_addr, intf_e + 1, MAX_MAC_ADDR_LEN - 1); + bss_mac_addr[MAX_MAC_ADDR_LEN - 1] = '\0'; + if ((intf_e - intf_s) > MAX_PARAM_LEN) { + PRINTM(MERROR, "Too long interface name %d\n", __LINE__); + goto done; + } + strncpy(bss_mac_name, intf_s + 1, intf_e - intf_s - 1); + bss_mac_name[intf_e - intf_s - 1] = '\0'; + for (i = 0; i < handle->priv_num; i++) { + if (strcmp(bss_mac_name, handle->priv[i]->netdev->name) == + 0) { + memset(handle->priv[i]->current_addr, 0, ETH_ALEN); + PRINTM(MINFO, "Interface name: %s mac: %s\n", + bss_mac_name, bss_mac_addr); + woal_mac2u8(handle->priv[i]->current_addr, + bss_mac_addr); + /* Set WLAN MAC addresses */ + if (MLAN_STATUS_SUCCESS != + woal_request_set_mac_address(handle->priv[i])) { + PRINTM(MERROR, "Set MAC address failed\n"); + goto done; + } + memcpy(handle->priv[i]->netdev->dev_addr, + handle->priv[i]->current_addr, ETH_ALEN); + index++; /* Mark found one interface matching */ + } + } + } else { + PRINTM(MERROR, "Wrong config file format %d\n", __LINE__); + goto done; + } + } + /* Process REG value */ + else if (strncmp(pos, "wlan_reg", 8) == 0) { + intf_s = strchr(pos, '='); + if (intf_s != NULL) + intf_e = strchr(intf_s, ','); + else + intf_e = NULL; + if (intf_s != NULL && intf_e != NULL) { + /* Copy type */ + strncpy(type, intf_s + 1, 1); + type[1] = '\0'; + } else { + PRINTM(MERROR, "Wrong config file format %d\n", __LINE__); + goto done; + } + intf_s = intf_e + 1; + if (intf_s != NULL) + intf_e = strchr(intf_s, ','); + else + intf_e = NULL; + if (intf_s != NULL && intf_e != NULL) { + if ((intf_e - intf_s) >= MAX_PARAM_LEN) { + PRINTM(MERROR, "Regsier offset is too long %d\n", __LINE__); + goto done; + } + /* Copy offset */ + strncpy(offset, intf_s, intf_e - intf_s); + offset[intf_e - intf_s] = '\0'; + } else { + PRINTM(MERROR, "Wrong config file format %d\n", __LINE__); + goto done; + } + intf_s = intf_e + 1; + if (intf_s != NULL) { + if ((strlen(intf_s) >= MAX_PARAM_LEN)) { + PRINTM(MERROR, "Regsier value is too long %d\n", __LINE__); + goto done; + } + /* Copy value */ + strncpy(value, intf_s, sizeof(value)); + } else { + PRINTM(MERROR, "Wrong config file format %d\n", __LINE__); + goto done; + } + + if (MLAN_STATUS_SUCCESS != + woal_process_regrdwr(handle, type, offset, value)) { + PRINTM(MERROR, "Access Reg failed\n"); + goto done; + } + PRINTM(MINFO, "Reg type: %s, offset: %s, value: %s\n", type, offset, + value); + } + } + + if (index == 0) { + PRINTM(MINFO, "Can't find any matching MAC Address"); + } + ret = MLAN_STATUS_SUCCESS; + + done: + LEAVE(); + return ret; +} + +/** + * @brief WOAL set user defined init data and param + * + * @param handle MOAL handle structure + * @return MLAN_STATUS_SUCCESS--success, otherwise--fail + */ +static t_u32 +woal_set_user_init_data(moal_handle * handle) +{ + mlan_status ret = MLAN_STATUS_FAILURE; + t_u8 *cfg_data = NULL; + t_size len; + + ENTER(); + + if ((request_firmware(&handle->user_data, init_cfg, handle->hotplug_device)) + < 0) { + PRINTM(MERROR, "Init config file request_firmware() failed\n"); + goto done; + } + + if (handle->user_data) { + cfg_data = (t_u8 *) (handle->user_data)->data; + len = (handle->user_data)->size; + if (MLAN_STATUS_SUCCESS != woal_process_init_cfg(handle, cfg_data, len)) { + PRINTM(MERROR, "Can't process init config file\n"); + goto done; + } + ret = MLAN_STATUS_SUCCESS; + } + + done: + if (handle->user_data) + release_firmware(handle->user_data); + + LEAVE(); + return ret; +} + +/** + * @brief Add interfaces DPC + * + * @param handle A pointer to moal_handle structure + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +static mlan_status +woal_add_card_dpc(moal_handle * handle) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + int i; + + ENTER(); + +#ifdef CONFIG_PROC_FS + /* Initialize proc fs */ + woal_proc_init(handle); +#endif /* CONFIG_PROC_FS */ + + /* Add interfaces */ + for (i = 0; i < handle->drv_mode.intf_num; i++) { + if (!woal_add_interface + (handle, handle->priv_num, handle->drv_mode.bss_attr[i].bss_type)) { + ret = MLAN_STATUS_FAILURE; + goto err; + } + handle->priv_num++; + } + if (init_cfg) { + if (MLAN_STATUS_SUCCESS != woal_set_user_init_data(handle)) { + PRINTM(MFATAL, "Set user init data and param failed\n"); + ret = MLAN_STATUS_FAILURE; + goto err; + } + } + + err: + if (ret != MLAN_STATUS_SUCCESS) { + PRINTM(MERROR, "Failed to add interface\n"); + for (i = 0; i < handle->priv_num; i++) + woal_remove_interface(handle, i); + handle->priv_num = 0; +#ifdef CONFIG_PROC_FS + woal_proc_exit(handle); +#endif + } + + LEAVE(); + return ret; +} + +/** + * @brief Download and Initialize firmware DPC + * + * @param handle A pointer to moal_handle structure + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +static mlan_status +woal_init_fw_dpc(moal_handle * handle) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_fw_image fw; + + mlan_init_param param; + + ENTER(); + + if (handle->firmware) { + memset(&fw, 0, sizeof(mlan_fw_image)); + fw.pfw_buf = (t_u8 *) handle->firmware->data; + fw.fw_len = handle->firmware->size; + sdio_claim_host(((struct sdio_mmc_card *) handle->card)->func); + ret = mlan_dnld_fw(handle->pmlan_adapter, &fw); + sdio_release_host(((struct sdio_mmc_card *) handle->card)->func); + if (ret == MLAN_STATUS_FAILURE) { + PRINTM(MERROR, "WLAN: Download FW with nowwait: %d\n", + req_fw_nowait); + goto done; + } + PRINTM(MMSG, "WLAN FW is active\n"); + } + + /** Cal data request */ + memset(¶m, 0, sizeof(mlan_init_param)); + if (cal_data_cfg) { + if ((request_firmware + (&handle->user_data, cal_data_cfg, handle->hotplug_device)) < 0) { + PRINTM(MERROR, "Cal data request_firmware() failed\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + } + + if (handle->user_data) { + param.pcal_data_buf = (t_u8 *) handle->user_data->data; + param.cal_data_len = handle->user_data->size; + } + + handle->hardware_status = HardwareStatusFwReady; + if (ret != MLAN_STATUS_SUCCESS) + goto done; + + handle->init_wait_q_woken = MFALSE; + + ret = mlan_set_init_param(handle->pmlan_adapter, ¶m); + + sdio_claim_host(((struct sdio_mmc_card *) handle->card)->func); + ret = mlan_init_fw(handle->pmlan_adapter); + sdio_release_host(((struct sdio_mmc_card *) handle->card)->func); + if (ret == MLAN_STATUS_FAILURE) { + goto done; + } else if (ret == MLAN_STATUS_SUCCESS) { + handle->hardware_status = HardwareStatusReady; + goto done; + } + /* Wait for mlan_init to complete */ + wait_event_interruptible(handle->init_wait_q, handle->init_wait_q_woken); + if (handle->hardware_status != HardwareStatusReady) { + woal_moal_debug_info(woal_get_priv(handle, MLAN_BSS_ROLE_ANY), handle, + MTRUE); + ret = MLAN_STATUS_FAILURE; + goto done; + } + ret = MLAN_STATUS_SUCCESS; + done: + if (handle->user_data) + release_firmware(handle->user_data); + LEAVE(); + return ret; +} + +/** + * @brief Request firmware DPC + * + * @param handle A pointer to moal_handle structure + * @param firmware A pointer to firmware image + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +static mlan_status +woal_request_fw_dpc(moal_handle * handle, const struct firmware *firmware) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + struct timeval tstamp; + + ENTER(); + + if (!firmware) { + do_gettimeofday(&tstamp); + if (tstamp.tv_sec > (handle->req_fw_time.tv_sec + REQUEST_FW_TIMEOUT)) { + PRINTM(MERROR, "No firmware image found. Skipping download\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + PRINTM(MERROR, "request_firmware_nowait failed for %s. Retrying..\n", + handle->drv_mode.fw_name); + woal_sched_timeout(MOAL_TIMER_1S); + woal_request_fw(handle); + LEAVE(); + return ret; + } + handle->firmware = firmware; + + if ((ret = woal_init_fw_dpc(handle))) + goto done; + if ((ret = woal_add_card_dpc(handle))) + goto done; + + done: + /* We should hold the semaphore until callback finishes execution */ + MOAL_REL_SEMAPHORE(&AddRemoveCardSem); + LEAVE(); + return ret; +} + +/** + * @brief Request firmware callback + * This function is invoked by request_firmware_nowait system call + * + * @param firmware A pointer to firmware image + * @param context A pointer to moal_handle structure + * + * @return N/A + */ +static void +woal_request_fw_callback(const struct firmware *firmware, void *context) +{ + ENTER(); + woal_request_fw_dpc((moal_handle *) context, firmware); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32) + if (firmware) + release_firmware(firmware); +#endif + LEAVE(); + return; +} + +/** + * @brief Download firmware using helper + * + * @param handle A pointer to moal_handle structure + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +woal_request_fw(moal_handle * handle) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + int err; + t_u32 revision_id = 0; + + ENTER(); + + if (!fw_name) { +/** Revision ID register */ +#define REV_ID_REG 0x5c + sdio_claim_host(((struct sdio_mmc_card *) handle->card)->func); + woal_read_reg(handle, REV_ID_REG, &revision_id); + sdio_release_host(((struct sdio_mmc_card *) handle->card)->func); + /* Check revision ID */ + switch (revision_id) { + case SD8797_A0: + handle->drv_mode.fw_name = SD8797_A0_FW_NAME; + break; + case SD8797_B0: + handle->drv_mode.fw_name = SD8797_B0_FW_NAME; + break; + default: + break; + } + } + + if (req_fw_nowait) { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,32) + if ((err = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + handle->drv_mode.fw_name, + handle->hotplug_device, GFP_KERNEL, + handle, + woal_request_fw_callback)) < 0) { +#else +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13) + if ((err = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + handle->drv_mode.fw_name, + handle->hotplug_device, handle, + woal_request_fw_callback)) < 0) { +#else + if ((err = request_firmware_nowait(THIS_MODULE, + handle->drv_mode.fw_name, + handle->hotplug_device, handle, + woal_request_fw_callback)) < 0) { +#endif +#endif + PRINTM(MFATAL, + "WLAN: request_firmware_nowait() failed, error code = %d\n", + err); + ret = MLAN_STATUS_FAILURE; + } + } else { + if ((err = + request_firmware(&handle->firmware, handle->drv_mode.fw_name, + handle->hotplug_device)) < 0) { + PRINTM(MFATAL, "WLAN: request_firmware() failed, error code = %d\n", + err); + ret = MLAN_STATUS_FAILURE; + } else { + ret = woal_request_fw_dpc(handle, handle->firmware); + release_firmware(handle->firmware); + } + } + + LEAVE(); + return ret; +} + +/** + * @brief This function initializes firmware + * + * @param handle A pointer to moal_handle structure + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +static mlan_status +woal_init_fw(moal_handle * handle) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + + ENTER(); + + do_gettimeofday(&handle->req_fw_time); + if ((ret = woal_request_fw(handle)) < 0) { + PRINTM(MFATAL, "woal_request_fw failed\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + done: + LEAVE(); + return ret; +} + +/** + * @brief This function will fill in the mlan_buffer + * + * @param pmbuf A pointer to mlan_buffer + * @param skb A pointer to struct sk_buff + * + * @return N/A + */ +static void +woal_fill_mlan_buffer(moal_private * priv, + mlan_buffer * pmbuf, struct sk_buff *skb) +{ + struct timeval tstamp; + struct ethhdr *eth; + t_u8 tid; + + ENTER(); + + eth = (struct ethhdr *) skb->data; + + switch (eth->h_proto) { + + case __constant_htons(ETH_P_IP): + tid = (IPTOS_PREC(SKB_TOS(skb)) >> IPTOS_OFFSET); + PRINTM(MDAT_D, "packet type ETH_P_IP: %04x, tid=%#x prio=%#x\n", + eth->h_proto, tid, skb->priority); + break; + + case __constant_htons(ETH_P_ARP): + PRINTM(MDATA, "ARP packet %04x\n", eth->h_proto); + tid = 0; + break; + default: + tid = 0; + break; + } + + skb->priority = tid; + + /* Record the current time the packet was queued; used to determine the + amount of time the packet was queued in the driver before it was sent to + the firmware. The delay is then sent along with the packet to the + firmware for aggregate delay calculation for stats and MSDU lifetime + expiry. */ + do_gettimeofday(&tstamp); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) + skb->tstamp = timeval_to_ktime(tstamp); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14) + skb_set_timestamp(skb, &tstamp); +#else + memcpy(&skb->stamp, &tstamp, sizeof(skb->stamp)); +#endif + + pmbuf->pdesc = skb; + pmbuf->pbuf = skb->head + sizeof(mlan_buffer); + pmbuf->data_offset = skb->data - (skb->head + sizeof(mlan_buffer)); + pmbuf->data_len = skb->len; + pmbuf->priority = skb->priority; + pmbuf->buf_type = 0; + pmbuf->in_ts_sec = (t_u32) tstamp.tv_sec; + pmbuf->in_ts_usec = (t_u32) tstamp.tv_usec; + + LEAVE(); + return; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33) +static struct device_type wlan_type = {.name = "wlan", }; +#endif + +#ifdef STA_SUPPORT +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) +/** Network device handlers */ +const struct net_device_ops woal_netdev_ops = { + .ndo_open = woal_open, + .ndo_start_xmit = woal_hard_start_xmit, + .ndo_stop = woal_close, + .ndo_do_ioctl = woal_do_ioctl, + .ndo_set_mac_address = woal_set_mac_address, + .ndo_tx_timeout = woal_tx_timeout, + .ndo_get_stats = woal_get_stats, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0) + .ndo_set_rx_mode = woal_set_multicast_list, +#else + .ndo_set_multicast_list = woal_set_multicast_list, +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) + .ndo_select_queue = woal_select_queue, +#endif +}; +#endif + +/** + * @brief This function initializes the private structure + * and dev structure for station mode + * + * @param dev A pointer to net_device structure + * @param priv A pointer to moal_private structure + * + * @return MLAN_STATUS_SUCCESS + */ +static mlan_status +woal_init_sta_dev(struct net_device *dev, moal_private * priv) +{ + ENTER(); + + /* Setup the OS Interface to our functions */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) + dev->open = woal_open; + dev->hard_start_xmit = woal_hard_start_xmit; + dev->stop = woal_close; + dev->do_ioctl = woal_do_ioctl; + dev->set_mac_address = woal_set_mac_address; + dev->tx_timeout = woal_tx_timeout; + dev->get_stats = woal_get_stats; + dev->set_multicast_list = woal_set_multicast_list; +#else + dev->netdev_ops = &woal_netdev_ops; +#endif + dev->watchdog_timeo = MRVDRV_DEFAULT_WATCHDOG_TIMEOUT; + dev->hard_header_len += MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer); +#ifdef WIRELESS_EXT +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) { +#if WIRELESS_EXT < 21 + dev->get_wireless_stats = woal_get_wireless_stats; +#endif + dev->wireless_handlers = (struct iw_handler_def *) &woal_handler_def; + } +#endif +#endif + dev->flags |= IFF_BROADCAST | IFF_MULTICAST; + + /* Initialize private structure */ + init_waitqueue_head(&priv->ioctl_wait_q); + init_waitqueue_head(&priv->cmd_wait_q); + init_waitqueue_head(&priv->proc_wait_q); +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) + init_waitqueue_head(&priv->w_stats_wait_q); +#endif + + LEAVE(); + return MLAN_STATUS_SUCCESS; +} +#endif /* STA_SUPPORT */ + +#ifdef UAP_SUPPORT +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) +/** Network device handlers */ +const struct net_device_ops woal_uap_netdev_ops = { + .ndo_open = woal_open, + .ndo_start_xmit = woal_hard_start_xmit, + .ndo_stop = woal_close, + .ndo_do_ioctl = woal_uap_do_ioctl, + .ndo_set_mac_address = woal_set_mac_address, + .ndo_tx_timeout = woal_tx_timeout, + .ndo_get_stats = woal_get_stats, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0) + .ndo_set_rx_mode = woal_uap_set_multicast_list, +#else + .ndo_set_multicast_list = woal_uap_set_multicast_list, +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) + .ndo_select_queue = woal_select_queue, +#endif +}; +#endif + +/** + * @brief This function initializes the private structure + * and dev structure for uap mode + * + * @param dev A pointer to net_device structure + * @param priv A pointer to moal_private structure + * + * @return MLAN_STATUS_SUCCESS + */ +static mlan_status +woal_init_uap_dev(struct net_device *dev, moal_private * priv) +{ + mlan_status status = MLAN_STATUS_SUCCESS; + + ENTER(); + + /* Setup the OS Interface to our functions */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) + dev->open = woal_open; + dev->hard_start_xmit = woal_hard_start_xmit; + dev->stop = woal_close; + dev->set_mac_address = woal_set_mac_address; + dev->tx_timeout = woal_tx_timeout; + dev->get_stats = woal_get_stats; + dev->do_ioctl = woal_uap_do_ioctl; + dev->set_multicast_list = woal_uap_set_multicast_list; +#else + dev->netdev_ops = &woal_uap_netdev_ops; +#endif + dev->watchdog_timeo = MRVDRV_DEFAULT_UAP_WATCHDOG_TIMEOUT; + dev->hard_header_len += MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer); +#ifdef UAP_WEXT +#ifdef WIRELESS_EXT + if (IS_UAP_WEXT(cfg80211_wext)) { +#if WIRELESS_EXT < 21 + dev->get_wireless_stats = woal_get_uap_wireless_stats; +#endif + dev->wireless_handlers = + (struct iw_handler_def *) &woal_uap_handler_def; + } +#endif /* WIRELESS_EXT */ +#endif /* UAP_WEXT */ + dev->flags |= IFF_BROADCAST | IFF_MULTICAST; + + /* Initialize private structure */ + init_waitqueue_head(&priv->ioctl_wait_q); + init_waitqueue_head(&priv->cmd_wait_q); + init_waitqueue_head(&priv->proc_wait_q); +#ifdef UAP_WEXT + if (IS_UAP_WEXT(cfg80211_wext)) + init_waitqueue_head(&priv->w_stats_wait_q); +#endif + + LEAVE(); + return status; +} +#endif /* UAP_SUPPORT */ + +/** + * @brief This function adds a new interface. It will + * allocate, initialize and register the device. + * + * @param handle A pointer to moal_handle structure + * @param bss_index BSS index number + * @param bss_type BSS type + * + * @return A pointer to the new priv structure + */ +moal_private * +woal_add_interface(moal_handle * handle, t_u8 bss_index, t_u8 bss_type) +{ + struct net_device *dev = NULL; + moal_private *priv = NULL; + + ENTER(); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) +#define MAX_WMM_QUEUE 4 + /* Allocate an Ethernet device */ + if (!(dev = alloc_etherdev_mq(sizeof(moal_private), MAX_WMM_QUEUE))) { +#else + if (!(dev = alloc_etherdev(sizeof(moal_private)))) { +#endif + PRINTM(MFATAL, "Init virtual ethernet device failed\n"); + goto error; + } +#ifdef STA_SUPPORT + /* Allocate device name */ + if ((bss_type == MLAN_BSS_TYPE_STA) && (dev_alloc_name(dev, "mlan%d") < 0)) { + PRINTM(MERROR, "Could not allocate mlan device name\n"); + goto error; + } +#endif +#ifdef UAP_SUPPORT + if ((bss_type == MLAN_BSS_TYPE_UAP) && (dev_alloc_name(dev, "uap%d") < 0)) { + PRINTM(MERROR, "Could not allocate uap device name\n"); + goto error; + } +#endif +#if defined(WIFI_DIRECT_SUPPORT) + if ((bss_type == MLAN_BSS_TYPE_WIFIDIRECT) && + (dev_alloc_name(dev, "wfd%d") < 0)) { + PRINTM(MERROR, "Could not allocate wifidirect device name\n"); + goto error; + } +#endif + priv = (moal_private *) netdev_priv(dev); + /* Save the priv to handle */ + handle->priv[bss_index] = priv; + + /* Use the same handle structure */ + priv->phandle = handle; + priv->netdev = dev; + priv->bss_index = bss_index; + priv->bss_type = bss_type; + if (bss_type == MLAN_BSS_TYPE_STA) + priv->bss_role = MLAN_BSS_ROLE_STA; + else if (bss_type == MLAN_BSS_TYPE_UAP) + priv->bss_role = MLAN_BSS_ROLE_UAP; +#if defined(WIFI_DIRECT_SUPPORT) + else if (bss_type == MLAN_BSS_TYPE_WIFIDIRECT) + priv->bss_role = MLAN_BSS_ROLE_STA; +#endif +#if defined(STA_CFG80211) || defined(UAP_CFG80211) + priv->probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; +#endif +#ifdef STA_SUPPORT +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) + SET_MODULE_OWNER(dev); +#endif +#ifdef STA_SUPPORT + if (bss_type == MLAN_BSS_TYPE_STA +#if defined(WIFI_DIRECT_SUPPORT) + || bss_type == MLAN_BSS_TYPE_WIFIDIRECT +#endif + ) + woal_init_sta_dev(dev, priv); +#endif +#ifdef UAP_SUPPORT + if (bss_type == MLAN_BSS_TYPE_UAP) { + if (MLAN_STATUS_SUCCESS != woal_init_uap_dev(dev, priv)) + goto error; + } +#endif +#ifdef STA_CFG80211 +#ifdef STA_SUPPORT + if ((priv->bss_role == MLAN_BSS_ROLE_STA) && IS_STA_CFG80211(cfg80211_wext)) { + if (bss_type == MLAN_BSS_TYPE_STA +#if defined(WIFI_DIRECT_SUPPORT) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) || defined(COMPAT_WIRELESS) + || bss_type == MLAN_BSS_TYPE_WIFIDIRECT +#endif +#endif + ) + /* Register cfg80211 for STA or Wifi direct */ + if (woal_register_sta_cfg80211(dev, bss_type)) { + PRINTM(MERROR, "Cannot register STA with cfg80211\n"); + goto error; + } + } +#endif /* STA_SUPPORT */ +#endif /* STA_CFG80211 */ +#ifdef UAP_CFG80211 +#ifdef UAP_SUPPORT + if ((priv->bss_role == MLAN_BSS_ROLE_UAP) && IS_UAP_CFG80211(cfg80211_wext)) { + /* Register cfg80211 for UAP */ + if (woal_register_uap_cfg80211(dev, bss_type)) { + PRINTM(MERROR, "Cannot register UAP with cfg80211\n"); + goto error; + } + } +#endif +#endif /* UAP_CFG80211 */ + + /* Initialize priv structure */ + woal_init_priv(priv, MOAL_CMD_WAIT); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) + SET_NETDEV_DEV(dev, handle->hotplug_device); +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33) + SET_NETDEV_DEVTYPE(dev, &wlan_type); +#endif + + /* Register network device */ + if (register_netdev(dev)) { + PRINTM(MERROR, "Cannot register virtual network device\n"); + goto error; + } + netif_carrier_off(dev); + woal_stop_queue(dev); + + PRINTM(MINFO, "%s: Marvell 802.11 Adapter\n", dev->name); + + /* Set MAC address from the insmod command line */ + if (handle->set_mac_addr) { + memset(priv->current_addr, 0, ETH_ALEN); + memcpy(priv->current_addr, handle->mac_addr, ETH_ALEN); + if (MLAN_STATUS_SUCCESS != woal_request_set_mac_address(priv)) { + PRINTM(MERROR, "Set MAC address failed\n"); + goto error; + } + memcpy(dev->dev_addr, priv->current_addr, ETH_ALEN); + } +#ifdef CONFIG_PROC_FS + woal_create_proc_entry(priv); +#ifdef PROC_DEBUG + woal_debug_entry(priv); +#endif /* PROC_DEBUG */ +#endif /* CONFIG_PROC_FS */ + + LEAVE(); + return priv; + error: + if (dev && dev->reg_state == NETREG_REGISTERED) + unregister_netdev(dev); +#if defined(STA_CFG80211) || defined(UAP_CFG80211) + /* Unregister wiphy device and free */ + if (priv->wdev && IS_STA_OR_UAP_CFG80211(cfg80211_wext)) { + wiphy_unregister(priv->wdev->wiphy); + wiphy_free(priv->wdev->wiphy); + /* Free wireless device */ + kfree(priv->wdev); + priv->wdev = NULL; + } +#endif + if (dev) + free_netdev(dev); + LEAVE(); + return NULL; +} + +/** + * @brief This function removes an interface. + * + * @param handle A pointer to the moal_handle structure + * @param bss_index BSS index number + * + * @return N/A + */ +void +woal_remove_interface(moal_handle * handle, t_u8 bss_index) +{ + struct net_device *dev = NULL; + moal_private *priv = handle->priv[bss_index]; +#if defined(STA_WEXT) || defined(UAP_WEXT) + union iwreq_data wrqu; +#endif + + ENTER(); + if (!priv) + goto error; + dev = priv->netdev; + + if (priv->media_connected == MTRUE) { + priv->media_connected = MFALSE; +#if defined(STA_WEXT) || defined(UAP_WEXT) + if (IS_STA_OR_UAP_WEXT(cfg80211_wext) && + GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) { + memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu, NULL); + } +#endif + } +#ifdef CONFIG_PROC_FS +#ifdef PROC_DEBUG + /* Remove proc debug */ + woal_debug_remove(priv); +#endif /* PROC_DEBUG */ + woal_proc_remove(priv); +#endif /* CONFIG_PROC_FS */ + /* Last reference is our one */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) + PRINTM(MINFO, "refcnt = %d\n", atomic_read(&dev->refcnt)); +#else + PRINTM(MINFO, "refcnt = %d\n", netdev_refcnt_read(dev)); +#endif + + PRINTM(MINFO, "netdev_finish_unregister: %s\n", dev->name); + + if (dev->reg_state == NETREG_REGISTERED) + unregister_netdev(dev); + +#if defined(STA_CFG80211) || defined(UAP_CFG80211) + /* Unregister wiphy device and free */ + if (priv->wdev && IS_STA_OR_UAP_CFG80211(cfg80211_wext)) { + wiphy_unregister(priv->wdev->wiphy); + wiphy_free(priv->wdev->wiphy); + /* Free wireless device */ + kfree(priv->wdev); + priv->wdev = NULL; + } +#endif + + /* Clear the priv in handle */ + priv->phandle->priv[priv->bss_index] = NULL; + priv->phandle = NULL; + priv->netdev = NULL; + free_netdev(dev); + error: + LEAVE(); + return; +} + +/** + * @brief Send FW shutdown command to MLAN + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +static mlan_status +woal_shutdown_fw(moal_private * priv, t_u8 wait_option) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_misc_cfg *misc = NULL; + mlan_status status; + + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = + (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req == NULL) { + status = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill request buffer */ + misc = (mlan_ds_misc_cfg *) req->pbuf; + misc->sub_command = MLAN_OID_MISC_INIT_SHUTDOWN; + misc->param.func_init_shutdown = MLAN_FUNC_SHUTDOWN; + req->req_id = MLAN_IOCTL_MISC_CFG; + req->action = MLAN_ACT_SET; + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, wait_option); + + done: + if (req) + kfree(req); + LEAVE(); + return status; +} + +/** + * @brief Return hex value of a give character + * + * @param chr Character to be converted + * + * @return The converted character if chr is a valid hex, else 0 + */ +static int +woal_hexval(char chr) +{ + if (chr >= '0' && chr <= '9') + return chr - '0'; + if (chr >= 'A' && chr <= 'F') + return chr - 'A' + 10; + if (chr >= 'a' && chr <= 'f') + return chr - 'a' + 10; + + return 0; +} + +#ifdef STA_WEXT +#endif + +/** + * @brief This function cancel all works in the queue + * and destroy the main workqueue. + * + * @param handle A pointer to moal_handle + * + * @return N/A + */ +static void +woal_terminate_workqueue(moal_handle * handle) +{ + ENTER(); + + /* Terminate main workqueue */ + if (handle->workqueue) { + flush_workqueue(handle->workqueue); + destroy_workqueue(handle->workqueue); + handle->workqueue = NULL; + } + + LEAVE(); +} + +/* Support for Cardhu wifi gpio toggling */ +/** + * @brief Sets the card detect state + * + * @param on 0: Card will be made undetected + * 1: Card will be detected + * + * @return 0 + */ +static int +wifi_set_carddetect(int on) +{ + ENTER(); + PRINTM(MMSG, "%s = %d\n", __FUNCTION__, on); + if (wifi_control_data && wifi_control_data->set_carddetect) { + wifi_control_data->set_carddetect(on); + } + LEAVE(); + return 0; +} + +/** + * @brief Sets the power state to On or Off after 'msec' millisecond + * + * @param on 0: Card will be powered on + * 1: Card will be powered off + * @param msec Delay in millisecond + * + * @return 0 + */ +static int +wifi_set_power(int on, unsigned long msec) +{ + ENTER(); + PRINTM(MMSG, "%s = %d\n", __FUNCTION__, on); + if (wifi_control_data && wifi_control_data->set_power) { + wifi_control_data->set_power(on); + } + if (msec) + mdelay(msec); + LEAVE(); + return 0; +} + +/** + * @brief Probes an wifi device + * + * @param pdev A pointer to the platform_device structure + * + * @return 0 + */ +static int +wifi_probe(struct platform_device *pdev) +{ + struct wifi_platform_data *wifi_ctrl = + (struct wifi_platform_data *) (pdev->dev.platform_data); + + ENTER(); + + wifi_control_data = wifi_ctrl; + wifi_set_power(1, 0); /* Power On */ + wifi_set_carddetect(1); /* CardDetect (0->1) */ + + LEAVE(); + return 0; +} + +/** + * @brief Removes an wifi device + * + * @param pdev A pointer to the platform_device structure + * + * @return 0 + */ +static int +wifi_remove(struct platform_device *pdev) +{ + struct wifi_platform_data *wifi_ctrl = + (struct wifi_platform_data *) (pdev->dev.platform_data); + + ENTER(); + + wifi_control_data = wifi_ctrl; + wifi_set_power(0, 0); /* Power Off */ + wifi_set_carddetect(0); /* CardDetect (1->0) */ + + LEAVE(); + return 0; +} + +static struct platform_driver wifi_device = { + .probe = wifi_probe, + .remove = wifi_remove, + .driver = { + .name = "mrvl8797_wlan", + } +}; + +/** + * @brief Adds an wifi device + * @return 0 --success, otherwise fail + */ +static int +wifi_add_dev(void) +{ + int ret = 0; + + ENTER(); + + if (minicard_pwrup) + ret = platform_driver_register(&wifi_device); + + LEAVE(); + return ret; +} + +/** + * @brief Removes an wifi device + * + * @return N/A + */ +static void +wifi_del_dev(void) +{ + ENTER(); + + if (minicard_pwrup) + platform_driver_unregister(&wifi_device); + + LEAVE(); +} + +/******************************************************** + Global Functions +********************************************************/ + +/** + * @brief This function opens the network device + * + * @param dev A pointer to net_device structure + * + * @return 0 --success, otherwise fail + */ +int +woal_open(struct net_device *dev) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + t_u8 carrier_on = MFALSE; + + ENTER(); + + if (!MODULE_GET) { + LEAVE(); + return -EFAULT; + } +#ifdef UAP_SUPPORT + if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) && (priv->media_connected)) + carrier_on = MTRUE; +#endif +#ifdef STA_SUPPORT + if ((GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && + (priv->media_connected || priv->is_adhoc_link_sensed)) + carrier_on = MTRUE; +#endif + if (carrier_on == MTRUE) { + if (!netif_carrier_ok(priv->netdev)) + netif_carrier_on(priv->netdev); + woal_wake_queue(priv->netdev); + } else { + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); + } + + LEAVE(); + return 0; +} + +/** + * @brief This function closes the network device + * + * @param dev A pointer to net_device structure + * + * @return 0 + */ +int +woal_close(struct net_device *dev) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + + ENTER(); + + woal_stop_queue(priv->netdev); + + MODULE_PUT; + + LEAVE(); + return 0; +} + +/** + * @brief This function sets the MAC address to firmware. + * + * @param dev A pointer to mlan_private structure + * @param addr MAC address to set + * + * @return 0 --success, otherwise fail + */ +int +woal_set_mac_address(struct net_device *dev, void *addr) +{ + int ret = 0; + moal_private *priv = (moal_private *) netdev_priv(dev); + struct sockaddr *phw_addr = (struct sockaddr *) addr; + t_u8 prev_addr[ETH_ALEN]; + + ENTER(); + + memcpy(prev_addr, priv->current_addr, ETH_ALEN); + memset(priv->current_addr, 0, ETH_ALEN); + /* dev->dev_addr is 6 bytes */ + HEXDUMP("dev->dev_addr:", dev->dev_addr, ETH_ALEN); + + HEXDUMP("addr:", (t_u8 *) phw_addr->sa_data, ETH_ALEN); + memcpy(priv->current_addr, phw_addr->sa_data, ETH_ALEN); + if (MLAN_STATUS_SUCCESS != woal_request_set_mac_address(priv)) { + PRINTM(MERROR, "Set MAC address failed\n"); + /* For failure restore the MAC address */ + memcpy(priv->current_addr, prev_addr, ETH_ALEN); + ret = -EFAULT; + goto done; + } + HEXDUMP("priv->MacAddr:", priv->current_addr, ETH_ALEN); + memcpy(dev->dev_addr, priv->current_addr, ETH_ALEN); + done: + LEAVE(); + return ret; +} + +/** + * @brief Display MLAN debug information + * + * @param priv A pointer to moal_private + * + * @return N/A + */ +void +woal_mlan_debug_info(moal_private * priv) +{ + int i; + + ENTER(); + + if (!priv || woal_get_debug_info(priv, MOAL_CMD_WAIT, &info)) { + PRINTM(MERROR, "Could not retrieve debug information from MLAN\n"); + LEAVE(); + return; + } + + PRINTM(MERROR, "num_cmd_timeout = %d\n", info.num_cmd_timeout); + PRINTM(MERROR, "Timeout cmd id = 0x%x, act = 0x%x \n", + info.timeout_cmd_id, info.timeout_cmd_act); + + PRINTM(MERROR, "last_cmd_index = %d\n", info.last_cmd_index); + PRINTM(MERROR, "last_cmd_id = "); + for (i = 0; i < DBG_CMD_NUM; i++) { + PRINTM(MERROR, "0x%x ", info.last_cmd_id[i]); + } + PRINTM(MERROR, "\n"); + PRINTM(MERROR, "last_cmd_act = "); + for (i = 0; i < DBG_CMD_NUM; i++) { + PRINTM(MERROR, "0x%x ", info.last_cmd_act[i]); + } + PRINTM(MERROR, "\n"); + PRINTM(MERROR, "last_cmd_resp_index = %d\n", info.last_cmd_resp_index); + PRINTM(MERROR, "last_cmd_resp_id = "); + for (i = 0; i < DBG_CMD_NUM; i++) { + PRINTM(MERROR, "0x%x ", info.last_cmd_resp_id[i]); + } + PRINTM(MERROR, "\n"); + PRINTM(MERROR, "last_event_index = %d\n", info.last_event_index); + PRINTM(MERROR, "last_event = "); + for (i = 0; i < DBG_CMD_NUM; i++) { + PRINTM(MERROR, "0x%x ", info.last_event[i]); + } + PRINTM(MERROR, "\n"); + + PRINTM(MERROR, "num_data_h2c_failure = %d\n", + info.num_tx_host_to_card_failure); + PRINTM(MERROR, "num_cmd_h2c_failure = %d\n", + info.num_cmd_host_to_card_failure); + PRINTM(MERROR, "num_data_c2h_failure = %d\n", + info.num_rx_card_to_host_failure); + PRINTM(MERROR, "num_cmdevt_c2h_failure = %d\n", + info.num_cmdevt_card_to_host_failure); + PRINTM(MERROR, "num_int_read_failure = %d\n", info.num_int_read_failure); + PRINTM(MERROR, "last_int_status = %d\n", info.last_int_status); + + PRINTM(MERROR, "num_event_deauth = %d\n", info.num_event_deauth); + PRINTM(MERROR, "num_event_disassoc = %d\n", info.num_event_disassoc); + PRINTM(MERROR, "num_event_link_lost = %d\n", info.num_event_link_lost); + PRINTM(MERROR, "num_cmd_deauth = %d\n", info.num_cmd_deauth); + PRINTM(MERROR, "num_cmd_assoc_success = %d\n", info.num_cmd_assoc_success); + PRINTM(MERROR, "num_cmd_assoc_failure = %d\n", info.num_cmd_assoc_failure); + PRINTM(MERROR, "cmd_resp_received = %d\n", info.cmd_resp_received); + PRINTM(MERROR, "event_received = %d\n", info.event_received); + + PRINTM(MERROR, "max_tx_buf_size = %d\n", info.max_tx_buf_size); + PRINTM(MERROR, "tx_buf_size = %d\n", info.tx_buf_size); + PRINTM(MERROR, "curr_tx_buf_size = %d\n", info.curr_tx_buf_size); + + PRINTM(MERROR, "data_sent=%d cmd_sent=%d\n", info.data_sent, info.cmd_sent); + + PRINTM(MERROR, "ps_mode=%d ps_state=%d\n", info.ps_mode, info.ps_state); + PRINTM(MERROR, "wakeup_dev_req=%d wakeup_tries=%d\n", + info.pm_wakeup_card_req, info.pm_wakeup_fw_try); + PRINTM(MERROR, "hs_configured=%d hs_activated=%d\n", + info.is_hs_configured, info.hs_activated); + PRINTM(MERROR, "pps_uapsd_mode=%d sleep_pd=%d\n", + info.pps_uapsd_mode, info.sleep_pd); + PRINTM(MERROR, "tx_lock_flag = %d\n", info.tx_lock_flag); + PRINTM(MERROR, "port_open = %d\n", info.port_open); + PRINTM(MERROR, "scan_processing = %d\n", info.scan_processing); + + PRINTM(MERROR, "mp_rd_bitmap=0x%x curr_rd_port=0x%x\n", + (unsigned int) info.mp_rd_bitmap, info.curr_rd_port); + PRINTM(MERROR, "mp_wr_bitmap=0x%x curr_wr_port=0x%x\n", + (unsigned int) info.mp_wr_bitmap, info.curr_wr_port); + + LEAVE(); +} + +/** + * @brief This function handles the timeout of packet + * transmission + * + * @param dev A pointer to net_device structure + * + * @return N/A + */ +void +woal_tx_timeout(struct net_device *dev) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + + ENTER(); + + priv->num_tx_timeout++; + PRINTM(MERROR, "%lu : Tx timeout (%d), bss_index=%d\n", + jiffies, priv->num_tx_timeout, priv->bss_index); + woal_set_trans_start(dev); + + if (priv->num_tx_timeout == NUM_TX_TIMEOUT_THRESHOLD) { + woal_mlan_debug_info(priv); + woal_moal_debug_info(priv, NULL, MFALSE); + } + + LEAVE(); +} + +/** + * @brief This function returns the network statistics + * + * @param dev A pointer to net_device structure + * + * @return A pointer to net_device_stats structure + */ +struct net_device_stats * +woal_get_stats(struct net_device *dev) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + return &priv->stats; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) +/** + * @brief This function handles wmm queue select + * + * @param dev A pointer to net_device structure + * @param skb A pointer to sk_buff structure + * + * @return tx_queue index (0-3) + */ +u16 +woal_select_queue(struct net_device * dev, struct sk_buff * skb) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + struct ethhdr *eth = NULL; + struct iphdr *iph; + t_u8 tid = 0; + t_u8 index = 0; + + ENTER(); + + eth = (struct ethhdr *) skb->data; + switch (eth->h_proto) { + case __constant_htons(ETH_P_IP): + iph = ip_hdr(skb); + tid = IPTOS_PREC(iph->tos); + break; + case __constant_htons(ETH_P_ARP): + default: + break; + } +/** Offset for TOS field in the IP header */ +#define IPTOS_OFFSET 5 + tid = (tid >> IPTOS_OFFSET); + index = + mlan_select_wmm_queue(priv->phandle->pmlan_adapter, priv->bss_index, + tid); + PRINTM(MDATA, "select queue: tid=%d, index=%d\n", tid, index); + LEAVE(); + return index; +} +#endif + +/** + * @brief This function handles packet transmission + * + * @param skb A pointer to sk_buff structure + * @param dev A pointer to net_device structure + * + * @return 0 --success + */ +int +woal_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_buffer *pmbuf = NULL; + mlan_status status; + struct sk_buff *new_skb = NULL; + + ENTER(); + + PRINTM(MDATA, "%lu BSS(%d): Data <= kernel\n", jiffies, priv->bss_index); + + if (priv->phandle->surprise_removed == MTRUE) { + dev_kfree_skb_any(skb); + priv->stats.tx_dropped++; + goto done; + } + priv->num_tx_timeout = 0; + if (!skb->len || (skb->len > ETH_FRAME_LEN)) { + PRINTM(MERROR, "Tx Error: Bad skb length %d : %d\n", + skb->len, ETH_FRAME_LEN); + dev_kfree_skb_any(skb); + priv->stats.tx_dropped++; + goto done; + } + if (skb->cloned || + (skb_headroom(skb) < + (MLAN_MIN_DATA_HEADER_LEN + sizeof(mlan_buffer)))) { + PRINTM(MWARN, "Tx: Insufficient skb headroom %d\n", skb_headroom(skb)); + /* Insufficient skb headroom - allocate a new skb */ + new_skb = + skb_realloc_headroom(skb, + MLAN_MIN_DATA_HEADER_LEN + + sizeof(mlan_buffer)); + if (unlikely(!new_skb)) { + PRINTM(MERROR, "Tx: Cannot allocate skb\n"); + dev_kfree_skb_any(skb); + priv->stats.tx_dropped++; + goto done; + } + if (new_skb != skb) + dev_kfree_skb_any(skb); + skb = new_skb; + PRINTM(MINFO, "new skb headroom %d\n", skb_headroom(skb)); + } + pmbuf = (mlan_buffer *) skb->head; + memset((t_u8 *) pmbuf, 0, sizeof(mlan_buffer)); + pmbuf->bss_index = priv->bss_index; + woal_fill_mlan_buffer(priv, pmbuf, skb); + status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf); + switch (status) { + case MLAN_STATUS_PENDING: + atomic_inc(&priv->phandle->tx_pending); + if (atomic_read(&priv->phandle->tx_pending) >= MAX_TX_PENDING) + woal_stop_queue(priv->netdev); + queue_work(priv->phandle->workqueue, &priv->phandle->main_work); + break; + case MLAN_STATUS_SUCCESS: + priv->stats.tx_packets++; + priv->stats.tx_bytes += skb->len; + dev_kfree_skb_any(skb); + break; + case MLAN_STATUS_FAILURE: + default: + priv->stats.tx_dropped++; + dev_kfree_skb_any(skb); + break; + } + done: + LEAVE(); + return 0; +} + +/** + * @brief Convert ascii string to Hex integer + * + * @param d A pointer to integer buf + * @param s A pointer to ascii string + * @param dlen The byte number of ascii string in hex + * + * @return Number of integer + */ +int +woal_ascii2hex(t_u8 * d, char *s, t_u32 dlen) +{ + unsigned int i; + t_u8 n; + + ENTER(); + + memset(d, 0x00, dlen); + + for (i = 0; i < dlen * 2; i++) { + if ((s[i] >= 48) && (s[i] <= 57)) + n = s[i] - 48; + else if ((s[i] >= 65) && (s[i] <= 70)) + n = s[i] - 55; + else if ((s[i] >= 97) && (s[i] <= 102)) + n = s[i] - 87; + else + break; + if (!(i % 2)) + n = n * 16; + d[i / 2] += n; + } + + LEAVE(); + return i; +} + +/** + * @brief Return integer value of a given ascii string + * + * @param data Converted data to be returned + * @param a String to be converted + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +woal_atoi(int *data, char *a) +{ + int i, val = 0, len; + + ENTER(); + + len = strlen(a); + if (!strncmp(a, "0x", 2)) { + a = a + 2; + len -= 2; + *data = woal_atox(a); + LEAVE(); + return MLAN_STATUS_SUCCESS; + } + for (i = 0; i < len; i++) { + if (isdigit(a[i])) { + val = val * 10 + (a[i] - '0'); + } else { + PRINTM(MERROR, "Invalid char %c in string %s\n", a[i], a); + LEAVE(); + return MLAN_STATUS_FAILURE; + } + } + *data = val; + + LEAVE(); + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Return hex value of a given ascii string + * + * @param a String to be converted to ascii + * + * @return The converted character if a is a valid hex, else 0 + */ +int +woal_atox(char *a) +{ + int i = 0; + + ENTER(); + + while (isxdigit(*a)) + i = i * 16 + woal_hexval(*a++); + + LEAVE(); + return i; +} + +/** + * @brief Extension of strsep lib command. This function will also take care + * escape character + * + * @param s A pointer to array of chars to process + * @param delim The delimiter character to end the string + * @param esc The escape character to ignore for delimiter + * + * @return Pointer to the separated string if delim found, else NULL + */ +char * +woal_strsep(char **s, char delim, char esc) +{ + char *se = *s, *sb; + + ENTER(); + + if (!(*s) || (*se == '\0')) { + LEAVE(); + return NULL; + } + + for (sb = *s; *sb != '\0'; ++sb) { + if (*sb == esc && *(sb + 1) == esc) { + /* + * We get a esc + esc seq then keep the one esc + * and chop off the other esc character + */ + memmove(sb, sb + 1, strlen(sb)); + continue; + } + if (*sb == esc && *(sb + 1) == delim) { + /* + * We get a delim + esc seq then keep the delim + * and chop off the esc character + */ + memmove(sb, sb + 1, strlen(sb)); + continue; + } + if (*sb == delim) + break; + } + + if (*sb == '\0') + sb = NULL; + else + *sb++ = '\0'; + + *s = sb; + + LEAVE(); + return se; +} + +/** + * @brief Convert mac address from string to t_u8 buffer. + * + * @param mac_addr The buffer to store the mac address in. + * @param buf The source of mac address which is a string. + * + * @return N/A + */ +void +woal_mac2u8(t_u8 * mac_addr, char *buf) +{ + char *begin = buf, *end; + int i; + + ENTER(); + + for (i = 0; i < ETH_ALEN; ++i) { + end = woal_strsep(&begin, ':', '/'); + if (end) + mac_addr[i] = woal_atox(end); + } + + LEAVE(); +} + +#ifdef STA_SUPPORT +/** + * @brief This function sets multicast addresses to firmware + * + * @param dev A pointer to net_device structure + * + * @return N/A + */ +void +woal_set_multicast_list(struct net_device *dev) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + ENTER(); + woal_request_set_multicast_list(priv, dev); + LEAVE(); +} +#endif + +/** + * @brief This function initializes the private structure + * and set default value to the member of moal_private. + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * + * @return N/A + */ +void +woal_init_priv(moal_private * priv, t_u8 wait_option) +{ + ENTER(); +#ifdef STA_SUPPORT + if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) { + priv->current_key_index = 0; + priv->rate_index = AUTO_RATE; + priv->is_adhoc_link_sensed = MFALSE; + priv->scan_type = MLAN_SCAN_TYPE_ACTIVE; + priv->bg_scan_start = MFALSE; + priv->bg_scan_reported = MFALSE; + memset(&priv->nick_name, 0, sizeof(priv->nick_name)); + priv->num_tx_timeout = 0; + priv->rx_filter = 0; + +#ifdef REASSOCIATION + priv->reassoc_on = MFALSE; +#endif +#ifdef STA_CFG80211 + if (IS_STA_CFG80211(cfg80211_wext)) { + if (priv->bss_type == MLAN_BSS_TYPE_STA +#if defined(WIFI_DIRECT_SUPPORT) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) || defined(COMPAT_WIRELESS) + || priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT +#endif +#endif + ) + woal_cfg80211_sta_init_wiphy(priv, wait_option); + } +#endif + } +#endif /* STA_SUPPORT */ +#ifdef UAP_SUPPORT + if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) { + priv->bss_started = MFALSE; +#ifdef UAP_CFG80211 + if (IS_UAP_CFG80211(cfg80211_wext)) + woal_cfg80211_uap_init_wiphy(priv, wait_option); +#endif + } +#endif + priv->media_connected = MFALSE; + woal_request_get_fw_info(priv, wait_option, NULL); + + LEAVE(); +} + +/** + * @brief Reset all interfaces if all_intf flag is TRUE, + * otherwise specified interface only + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * @param all_intf TRUE : all interfaces + * FALSE : current interface only + * + * @return MLAN_STATUS_SUCCESS --success, otherwise fail + */ +int +woal_reset_intf(moal_private * priv, t_u8 wait_option, int all_intf) +{ + int ret = MLAN_STATUS_SUCCESS; + int intf_num; + moal_handle *handle = priv->phandle; + mlan_bss_info bss_info; + + ENTER(); + + /* Stop queue and detach device */ + if (!all_intf) { + woal_stop_queue(priv->netdev); + netif_device_detach(priv->netdev); + } else { + for (intf_num = 0; intf_num < handle->priv_num; intf_num++) { + woal_stop_queue(handle->priv[intf_num]->netdev); + netif_device_detach(handle->priv[intf_num]->netdev); + } + } + + /* Get BSS info */ + memset(&bss_info, 0, sizeof(bss_info)); + woal_get_bss_info(priv, wait_option, &bss_info); + +#ifdef STA_SUPPORT + /* If scan is in process, cancel the scan command */ + if (handle->scan_pending_on_block == MTRUE) { + mlan_ioctl_req *req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan)); + if (req == NULL) { + ret = -EFAULT; + goto err_cancel_scan; + } + req->req_id = MLAN_IOCTL_SCAN; + req->action = MLAN_ACT_SET; + ((mlan_ds_scan *) req->pbuf)->sub_command = MLAN_OID_SCAN_CANCEL; + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, wait_option)) { + ret = -EFAULT; + goto err_cancel_scan; + } + err_cancel_scan: + handle->scan_pending_on_block = MFALSE; + MOAL_REL_SEMAPHORE(&handle->async_sem); + if (req) + kfree(req); + } +#endif + + /* Cancel host sleep */ + if (bss_info.is_hs_configured) { + if (MLAN_STATUS_SUCCESS != woal_cancel_hs(priv, wait_option)) { + ret = -EFAULT; + goto done; + } + } + + /* Disconnect from network */ + if (!all_intf) { + /* Disconnect specified interface only */ + if ((priv->media_connected == MTRUE) +#ifdef UAP_SUPPORT + || (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) +#endif + ) { + woal_disconnect(priv, wait_option, NULL); + priv->media_connected = MFALSE; + } + } else { + /* Disconnect all interfaces */ + for (intf_num = 0; intf_num < handle->priv_num; intf_num++) { + if (handle->priv[intf_num]->media_connected == MTRUE +#ifdef UAP_SUPPORT + || (GET_BSS_ROLE(handle->priv[intf_num]) == MLAN_BSS_ROLE_UAP) +#endif + ) { + woal_disconnect(handle->priv[intf_num], wait_option, NULL); + handle->priv[intf_num]->media_connected = MFALSE; + } + } + } + +#ifdef REASSOCIATION + /* Reset the reassoc timer and status */ + if (!all_intf) { + handle->reassoc_on &= ~MBIT(priv->bss_index); + priv->reassoc_on = MFALSE; + } else { + handle->reassoc_on = 0; + for (intf_num = 0; intf_num < handle->priv_num; intf_num++) { + handle->priv[intf_num]->reassoc_on = MFALSE; + } + } + if (!handle->reassoc_on && handle->is_reassoc_timer_set) { + woal_cancel_timer(&handle->reassoc_timer); + handle->is_reassoc_timer_set = MFALSE; + } +#endif /* REASSOCIATION */ + + done: + LEAVE(); + return ret; +} + +/** + * @brief This function return the point to structure moal_private + * + * @param handle Pointer to structure moal_handle + * @param bss_index BSS index number + * + * @return moal_private pointer or NULL + */ +moal_private * +woal_bss_index_to_priv(moal_handle * handle, t_u8 bss_index) +{ + int i; + + ENTER(); + if (!handle) { + LEAVE(); + return NULL; + } + for (i = 0; i < MLAN_MAX_BSS_NUM; i++) { + if (handle->priv[i] && (handle->priv[i]->bss_index == bss_index)) { + LEAVE(); + return handle->priv[i]; + } + } + + LEAVE(); + return NULL; +} + +/** + * @brief This function alloc mlan_buffer. + * @param handle A pointer to moal_handle structure + * @param size buffer size to allocate + * + * @return mlan_buffer pointer or NULL + */ +pmlan_buffer +woal_alloc_mlan_buffer(moal_handle * handle, int size) +{ + mlan_buffer *pmbuf = NULL; + struct sk_buff *skb; + + ENTER(); + if (!(pmbuf = kmalloc(sizeof(mlan_buffer), GFP_ATOMIC))) { + PRINTM(MERROR, "%s: Fail to alloc mlan buffer\n", __FUNCTION__); + LEAVE(); + return NULL; + } + memset((t_u8 *) pmbuf, 0, sizeof(mlan_buffer)); + if (!(skb = dev_alloc_skb(size))) { + PRINTM(MERROR, "%s: No free skb\n", __FUNCTION__); + kfree(pmbuf); + LEAVE(); + return NULL; + } + pmbuf->pdesc = (t_void *) skb; + pmbuf->pbuf = (t_u8 *) skb->data; + handle->mbufalloc_count++; + LEAVE(); + return pmbuf; +} + +/** + * @brief This function alloc mlan_ioctl_req. + * + * @param size buffer size to allocate + * + * @return mlan_ioctl_req pointer or NULL + */ +pmlan_ioctl_req +woal_alloc_mlan_ioctl_req(int size) +{ + mlan_ioctl_req *req = NULL; + + ENTER(); + + if (! + (req = + (mlan_ioctl_req *) + kmalloc((sizeof(mlan_ioctl_req) + size + sizeof(int) + + sizeof(wait_queue)), GFP_ATOMIC))) { + PRINTM(MERROR, "%s: Fail to alloc ioctl buffer\n", __FUNCTION__); + LEAVE(); + return NULL; + } + memset((t_u8 *) req, 0, (sizeof(mlan_ioctl_req) + size + + sizeof(int) + sizeof(wait_queue))); + req->pbuf = (t_u8 *) req + sizeof(mlan_ioctl_req) + sizeof(wait_queue); + req->buf_len = (t_u32) size; + req->reserved_1 = (t_ptr) ((t_u8 *) req + sizeof(mlan_ioctl_req)); + + LEAVE(); + return req; +} + +/** + * @brief This function frees mlan_buffer. + * @param handle A pointer to moal_handle structure + * @param pmbuf Pointer to mlan_buffer + * + * @return N/A + */ +void +woal_free_mlan_buffer(moal_handle * handle, pmlan_buffer pmbuf) +{ + ENTER(); + if (!pmbuf) { + LEAVE(); + return; + } + if (pmbuf->pdesc) + dev_kfree_skb_any((struct sk_buff *) pmbuf->pdesc); + kfree(pmbuf); + handle->mbufalloc_count--; + LEAVE(); + return; +} + +#ifdef STA_WEXT +#endif + +/** + * @brief This function handles events generated by firmware + * + * @param priv A pointer to moal_private structure + * @param payload A pointer to payload buffer + * @param len Length of the payload + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +woal_broadcast_event(moal_private * priv, t_u8 * payload, t_u32 len) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + struct sk_buff *skb = NULL; + struct nlmsghdr *nlh = NULL; + moal_handle *handle = priv->phandle; + struct sock *sk = handle->nl_sk; + + ENTER(); + /* interface name to be prepended to event */ + if ((len + IFNAMSIZ) > NL_MAX_PAYLOAD) { + PRINTM(MERROR, "event size is too big, len=%d\n", (int) len); + ret = MLAN_STATUS_FAILURE; + goto done; + } + if (sk) { + /* Allocate skb */ + if (!(skb = alloc_skb(NLMSG_SPACE(NL_MAX_PAYLOAD), GFP_ATOMIC))) { + PRINTM(MERROR, "Could not allocate skb for netlink\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + nlh = (struct nlmsghdr *) skb->data; + nlh->nlmsg_len = NLMSG_SPACE(len + IFNAMSIZ); + + /* From kernel */ + nlh->nlmsg_pid = 0; + nlh->nlmsg_flags = 0; + + /* Data */ + skb_put(skb, nlh->nlmsg_len); + memcpy(NLMSG_DATA(nlh), priv->netdev->name, IFNAMSIZ); + memcpy(((t_u8 *) (NLMSG_DATA(nlh))) + IFNAMSIZ, payload, len); + + /* From Kernel */ + NETLINK_CB(skb).pid = 0; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + /* Multicast message */ + NETLINK_CB(skb).dst_pid = 0; +#endif + + /* Multicast group number */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) + NETLINK_CB(skb).dst_groups = NL_MULTICAST_GROUP; +#else + NETLINK_CB(skb).dst_group = NL_MULTICAST_GROUP; +#endif + + /* Send message */ + netlink_broadcast(sk, skb, 0, NL_MULTICAST_GROUP, GFP_ATOMIC); + + ret = MLAN_STATUS_SUCCESS; + } else { + PRINTM(MERROR, "Could not send event through NETLINK. Link down.\n"); + ret = MLAN_STATUS_FAILURE; + } + done: + LEAVE(); + return ret; +} + +#ifdef REASSOCIATION +/** + * @brief This function handles re-association. it is triggered + * by re-assoc timer. + * + * @param data A pointer to wlan_thread structure + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +int +woal_reassociation_thread(void *data) +{ + moal_thread *pmoal_thread = data; + moal_private *priv = NULL; + moal_handle *handle = (moal_handle *) pmoal_thread->handle; + wait_queue_t wait; + int i; + BOOLEAN reassoc_timer_req; + mlan_802_11_ssid req_ssid; + mlan_ssid_bssid ssid_bssid; + mlan_status status; + mlan_bss_info bss_info; + t_u32 timer_val = MOAL_TIMER_10S; + + ENTER(); + + woal_activate_thread(pmoal_thread); + init_waitqueue_entry(&wait, current); + + current->flags |= PF_NOFREEZE; + + for (;;) { + add_wait_queue(&pmoal_thread->wait_q, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + schedule(); + + set_current_state(TASK_RUNNING); + remove_wait_queue(&pmoal_thread->wait_q, &wait); + + /* Cancel re-association timer */ + if (handle->is_reassoc_timer_set == MTRUE) { + woal_cancel_timer(&handle->reassoc_timer); + handle->is_reassoc_timer_set = MFALSE; + } + + if (handle->surprise_removed) + break; + if (kthread_should_stop()) + break; + + if (handle->hardware_status != HardwareStatusReady) { + PRINTM(MINFO, "Reassoc: Hardware status is not correct\n"); + continue; + } + + PRINTM(MEVENT, "Reassoc: Thread waking up...\n"); + reassoc_timer_req = MFALSE; + + for (i = 0; i < handle->priv_num && (priv = handle->priv[i]); i++) { + + if (priv->reassoc_required == MFALSE) + continue; + + memset(&bss_info, 0x00, sizeof(bss_info)); + + if (MLAN_STATUS_SUCCESS != woal_get_bss_info(priv, + MOAL_CMD_WAIT, + &bss_info)) { + PRINTM(MINFO, "Ressoc: Fail to get bss info\n"); + priv->reassoc_required = MFALSE; + continue; + } + + if (bss_info.bss_mode != MLAN_BSS_MODE_INFRA || + priv->media_connected != MFALSE) { + PRINTM(MINFO, "Reassoc: ad-hoc mode or media connected\n"); + priv->reassoc_required = MFALSE; + continue; + } + + /* The semaphore is used to avoid reassociation thread and + wlan_set_scan/wlan_set_essid interrupting each other. + Reassociation should be disabled completely by application if + wlan_set_user_scan_ioctl/wlan_set_wap is used. */ + if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) { + PRINTM(MERROR, + "Acquire semaphore error, reassociation thread\n"); + reassoc_timer_req = MTRUE; + break; + } + + PRINTM(MINFO, "Reassoc: Required ESSID: %s\n", + priv->prev_ssid_bssid.ssid.ssid); + PRINTM(MINFO, "Reassoc: Performing Active Scan\n"); + + memset(&req_ssid, 0x00, sizeof(mlan_802_11_ssid)); + memcpy(&req_ssid, + &priv->prev_ssid_bssid.ssid, sizeof(mlan_802_11_ssid)); + + /* Do specific SSID scanning */ + if (MLAN_STATUS_SUCCESS != + woal_request_scan(priv, MOAL_CMD_WAIT, &req_ssid)) { + PRINTM(MERROR, "Reassoc: Fail to do specific scan\n"); + reassoc_timer_req = MTRUE; + MOAL_REL_SEMAPHORE(&handle->reassoc_sem); + break; + } + + if (handle->surprise_removed) { + MOAL_REL_SEMAPHORE(&handle->reassoc_sem); + break; + } + + /* Search AP by BSSID first */ + PRINTM(MINFO, "Reassoc: Search AP by BSSID first\n"); + memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid)); + memcpy(&ssid_bssid.bssid, + &priv->prev_ssid_bssid.bssid, MLAN_MAC_ADDR_LENGTH); + status = woal_find_best_network(priv, MOAL_CMD_WAIT, &ssid_bssid); + + if (MLAN_STATUS_SUCCESS != status) { + PRINTM(MINFO, "Reassoc: AP not found in scan list\n"); + PRINTM(MINFO, "Reassoc: Search AP by SSID\n"); + /* Search AP by SSID */ + memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid)); + memcpy(&ssid_bssid.ssid, + &priv->prev_ssid_bssid.ssid, sizeof(mlan_802_11_ssid)); + status = woal_find_best_network(priv, + MOAL_CMD_WAIT, &ssid_bssid); + } + + if (status == MLAN_STATUS_SUCCESS) { + /* set the wep key */ + if (bss_info.wep_status) + woal_enable_wep_key(priv, MOAL_CMD_WAIT); + /* Zero SSID implies use BSSID to connect */ + memset(&ssid_bssid.ssid, 0, sizeof(mlan_802_11_ssid)); + status = woal_bss_start(priv, MOAL_CMD_WAIT, &ssid_bssid); + } + + if (priv->media_connected == MFALSE) + reassoc_timer_req = MTRUE; + else { + mlan_ds_rate *rate = NULL; + mlan_ioctl_req *req = NULL; + + reassoc_timer_req = MFALSE; + + if (priv->rate_index != AUTO_RATE) { + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate)); + + if (req == NULL) { + LEAVE(); + return MLAN_STATUS_FAILURE; + } + + rate = (mlan_ds_rate *) req->pbuf; + rate->param.rate_cfg.rate_type = MLAN_RATE_INDEX; + rate->sub_command = MLAN_OID_RATE_CFG; + req->req_id = MLAN_IOCTL_RATE; + + req->action = MLAN_ACT_SET; + + rate->param.rate_cfg.rate = priv->rate_index; + + if (MLAN_STATUS_SUCCESS + != woal_request_ioctl(priv, req, MOAL_CMD_WAIT)) { + kfree(req); + LEAVE(); + return MLAN_STATUS_FAILURE; + } + if (req) + kfree(req); + } + } + + MOAL_REL_SEMAPHORE(&handle->reassoc_sem); + } + + if (handle->surprise_removed) + break; + + if (reassoc_timer_req == MTRUE) { + PRINTM(MEVENT, + "Reassoc: No AP found or assoc failed. " + "Restarting re-assoc Timer: %d\n", (int) timer_val); + handle->is_reassoc_timer_set = MTRUE; + woal_mod_timer(&handle->reassoc_timer, timer_val); + } + } + woal_deactivate_thread(pmoal_thread); + + LEAVE(); + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief This function triggers re-association by waking up + * re-assoc thread. + * + * @param context A pointer to context + * @return N/A + */ +void +woal_reassoc_timer_func(void *context) +{ + moal_handle *handle = (moal_handle *) context; + + ENTER(); + + PRINTM(MINFO, "reassoc_timer fired.\n"); + handle->is_reassoc_timer_set = MFALSE; + + PRINTM(MINFO, "Waking Up the Reassoc Thread\n"); + wake_up_interruptible(&handle->reassoc_thread.wait_q); + + LEAVE(); + return; +} +#endif /* REASSOCIATION */ + +#ifdef STA_SUPPORT +/** + * @brief Sends disconnect event + * + * @param priv A pointer to moal_private struct + * @return N/A + */ +t_void +woal_send_disconnect_to_system(moal_private * priv) +{ +#ifdef STA_WEXT + union iwreq_data wrqu; +#endif + + ENTER(); + priv->media_connected = MFALSE; + woal_stop_queue(priv->netdev); + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) { + memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu, NULL); + } +#endif + LEAVE(); +} +#endif /* STA_SUPPORT */ + +/** + * @brief This function reads and displays SDIO registers for debugging + * + * @param phandle A pointer to moal_handle + * + * @return N/A + */ +void +woal_sdio_reg_dbg(moal_handle * phandle) +{ + int ret = 0; + t_u8 loop, index = 0, func, data; + unsigned int reg, reg_start, reg_end; + unsigned int reg_table[] = { 0x28, 0x30, 0x34, 0x38, 0x3c }; + char buf[128], *ptr; + + sdio_claim_host(((struct sdio_mmc_card *) phandle->card)->func); + for (loop = 0; loop < 5; loop++) { + memset(buf, 0, sizeof(buf)); + ptr = buf; + if (loop < 2) { + /* Read the registers of SDIO function0 and function1 */ + func = loop; + reg_start = 0; + reg_end = 9; + } else if (loop == 2) { + /* Read specific registers of SDIO function1 */ + index = 0; + func = 1; + reg_start = reg_table[index++]; + reg_end = reg_table[sizeof(reg_table) / sizeof(int) - 1]; + } else { + /* Read the scratch registers of SDIO function1 */ + if (loop == 4) + mdelay(100); + func = 1; +#define SDIO_SCRATCH_REG 0x60 + reg_start = SDIO_SCRATCH_REG; + reg_end = SDIO_SCRATCH_REG + 10; + } + if (loop != 2) + ptr += + sprintf(ptr, "SDIO Func%d (%#x-%#x): ", func, reg_start, + reg_end); + else + ptr += sprintf(ptr, "SDIO Func%d: ", func); + for (reg = reg_start; reg <= reg_end;) { + if (func == 0) + data = + sdio_f0_readb(((struct sdio_mmc_card *) phandle->card)-> + func, reg, &ret); + else + data = + sdio_readb(((struct sdio_mmc_card *) phandle->card)->func, + reg, &ret); + if (loop == 2) + ptr += sprintf(ptr, "(%#x) ", reg); + if (!ret) + ptr += sprintf(ptr, "%02x ", data); + else { + ptr += sprintf(ptr, "ERR"); + break; + } + if (loop == 2 && reg < reg_end) + reg = reg_table[index++]; + else + reg++; + } + PRINTM(MMSG, "%s\n", buf); + } + sdio_release_host(((struct sdio_mmc_card *) phandle->card)->func); +} + +/** + * @brief This function displays extra MOAL debug information + * + * @param priv A pointer to moal_private + * @param handle A pointer to moal_handle + * @param flag Indicates whether register read can be done directly + * + * @return N/A + */ +void +woal_moal_debug_info(moal_private * priv, moal_handle * handle, u8 flag) +{ + moal_handle *phandle = NULL; + char buf[MLAN_MAX_VER_STR_LEN]; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) + int i = 0; +#endif + + ENTER(); + + if (!priv) { + if (handle) { + phandle = handle; + } else { + PRINTM(MERROR, "Could not retrieve debug information from MOAL\n"); + LEAVE(); + return; + } + } else { + phandle = priv->phandle; + } + + woal_get_version(phandle, buf, sizeof(buf) - 1); + PRINTM(MERROR, "Driver version = %s\n", buf); + PRINTM(MERROR, "main_state = %d\n", phandle->main_state); + PRINTM(MERROR, "ioctl_pending = %d\n", + atomic_read(&phandle->ioctl_pending)); + PRINTM(MERROR, "tx_pending = %d\n", atomic_read(&phandle->tx_pending)); + PRINTM(MERROR, "rx_pending = %d\n", atomic_read(&phandle->rx_pending)); + PRINTM(MERROR, "malloc_count = %u\n", phandle->malloc_count); + PRINTM(MERROR, "lock_count = %u\n", phandle->lock_count); + PRINTM(MERROR, "mbufalloc_count = %u\n", phandle->mbufalloc_count); +#if defined(SDIO_SUSPEND_RESUME) + PRINTM(MERROR, "hs_skip_count = %u\n", phandle->hs_skip_count); + PRINTM(MERROR, "hs_force_count = %u\n", phandle->hs_force_count); +#endif + + if (priv) { + PRINTM(MERROR, "Media state = \"%s\"\n", + ((priv->media_connected == + MFALSE) ? "Disconnected" : "Connected")); + PRINTM(MERROR, "carrier %s\n", + ((netif_carrier_ok(priv->netdev)) ? "on" : "off")); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) + for (i = 0; i < (priv->netdev->num_tx_queues); i++) { + PRINTM(MERROR, "tx queue %d: %s\n", i, + ((netif_tx_queue_stopped + (netdev_get_tx_queue(priv->netdev, 0))) ? "stopped" : + "started")); + } +#else + PRINTM(MERROR, "tx queue %s\n", + ((netif_queue_stopped(priv->netdev)) ? "stopped" : "started")); +#endif + } + + /* Display SDIO registers */ + if (flag && phandle->main_state == MOAL_END_MAIN_PROCESS) { + woal_sdio_reg_dbg(phandle); + } else { + phandle->sdio_reg_dbg = MTRUE; + queue_work(phandle->workqueue, &phandle->main_work); + } + + LEAVE(); + return; +} + +/** + * @brief This workqueue function handles main_process + * + * @param work A pointer to work_struct + * + * @return N/A + */ +t_void +woal_main_work_queue(struct work_struct * work) +{ + moal_handle *handle = container_of(work, moal_handle, main_work); + + ENTER(); + + if (handle->surprise_removed == MTRUE) { + LEAVE(); + return; + } + + if (handle->sdio_reg_dbg == MTRUE) { + handle->sdio_reg_dbg = MFALSE; + woal_sdio_reg_dbg(handle); + LEAVE(); + return; + } + + handle->main_state = MOAL_ENTER_WORK_QUEUE; + sdio_claim_host(((struct sdio_mmc_card *) handle->card)->func); + handle->main_state = MOAL_START_MAIN_PROCESS; + /* Call MLAN main process */ + mlan_main_process(handle->pmlan_adapter); + handle->main_state = MOAL_END_MAIN_PROCESS; + sdio_release_host(((struct sdio_mmc_card *) handle->card)->func); + + LEAVE(); +} + +/** + * @brief Handles interrupt + * + * @param handle A pointer to moal_handle struct + * + * @return N/A + */ +void +woal_interrupt(moal_handle * handle) +{ + ENTER(); + handle->main_state = MOAL_RECV_INT; + PRINTM(MINTR, "*\n"); + if (handle->surprise_removed == MTRUE) { + LEAVE(); + return; + } + /* call mlan_interrupt to read int status */ + mlan_interrupt(handle->pmlan_adapter); + handle->main_state = MOAL_START_MAIN_PROCESS; + /* Call MLAN main process */ + mlan_main_process(handle->pmlan_adapter); + handle->main_state = MOAL_END_MAIN_PROCESS; + LEAVE(); +} + +/** + * @brief This function adds the card. it will probe the + * card, allocate the mlan_private and initialize the device. + * + * @param card A pointer to card + * + * @return A pointer to moal_handle structure + */ +moal_handle * +woal_add_card(void *card) +{ + moal_handle *handle = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + int netlink_num = NETLINK_MARVELL; + int index = 0; + + ENTER(); + + if (MOAL_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem)) + goto exit_sem_err; + + /* Allocate buffer for moal_handle */ + if (!(handle = kmalloc(sizeof(moal_handle), GFP_KERNEL))) { + PRINTM(MERROR, "Allocate buffer for moal_handle failed!\n"); + goto err_handle; + } + + /* Init moal_handle */ + memset(handle, 0, sizeof(moal_handle)); + handle->card = card; + /* Save the handle */ + for (index = 0; index < MAX_MLAN_ADAPTER; index++) { + if (m_handle[index] == NULL) + break; + } + if (index < MAX_MLAN_ADAPTER) { + m_handle[index] = handle; + handle->handle_idx = index; + } else { + PRINTM(MERROR, "Exceeded maximum cards supported!\n"); + goto err_kmalloc; + } + + if (mac_addr) { + t_u8 temp[20]; + t_u8 len = strlen(mac_addr) + 1; + if (len < sizeof(temp)) { + memcpy(temp, mac_addr, len); + handle->set_mac_addr = 1; + /* note: the following function overwrites the temp buffer */ + woal_mac2u8(handle->mac_addr, temp); + } + } + + ((struct sdio_mmc_card *) card)->handle = handle; +#ifdef STA_SUPPORT + handle->scan_pending_on_block = MFALSE; + MOAL_INIT_SEMAPHORE(&handle->async_sem); +#endif + + /* Init SW */ + if (MLAN_STATUS_SUCCESS != woal_init_sw(handle)) { + PRINTM(MFATAL, "Software Init Failed\n"); + goto err_kmalloc; + } + + do { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) + handle->nl_sk = netlink_kernel_create(netlink_num, NULL); +#else +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) + handle->nl_sk = + netlink_kernel_create(netlink_num, NL_MULTICAST_GROUP, NULL, + THIS_MODULE); +#else +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) + handle->nl_sk = + netlink_kernel_create(netlink_num, NL_MULTICAST_GROUP, NULL, NULL, + THIS_MODULE); +#else + handle->nl_sk = + netlink_kernel_create(&init_net, netlink_num, NL_MULTICAST_GROUP, + NULL, NULL, THIS_MODULE); +#endif +#endif +#endif + if (handle->nl_sk) { + PRINTM(MINFO, "Netlink number = %d\n", netlink_num); + handle->netlink_num = netlink_num; + break; + } + netlink_num--; + } while (netlink_num > 0); + + if (handle->nl_sk == NULL) { + PRINTM(MERROR, + "Could not initialize netlink event passing mechanism!\n"); + goto err_kmalloc; + } + + /* Create workqueue for main process */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14) + /* For kernel less than 2.6.14 name can not be greater than 10 characters */ + handle->workqueue = create_workqueue("MOAL_WORKQ"); +#else + handle->workqueue = create_workqueue("MOAL_WORK_QUEUE"); +#endif + if (!handle->workqueue) + goto err_kmalloc; + + MLAN_INIT_WORK(&handle->main_work, woal_main_work_queue); + +#ifdef REASSOCIATION + PRINTM(MINFO, "Starting re-association thread...\n"); + handle->reassoc_thread.handle = handle; + woal_create_thread(woal_reassociation_thread, + &handle->reassoc_thread, "woal_reassoc_service"); + + while (!handle->reassoc_thread.pid) { + woal_sched_timeout(2); + } +#endif /* REASSOCIATION */ + + /* Register the device. Fill up the private data structure with relevant + information from the card and request for the required IRQ. */ + if (woal_register_dev(handle) != MLAN_STATUS_SUCCESS) { + PRINTM(MFATAL, "Failed to register wlan device!\n"); + goto err_registerdev; + } + + /* Init FW and HW */ + if (MLAN_STATUS_SUCCESS != woal_init_fw(handle)) { + PRINTM(MFATAL, "Firmware Init Failed\n"); + goto err_init_fw; + } + + LEAVE(); + return handle; + + err_init_fw: + /* Unregister device */ + PRINTM(MINFO, "unregister device\n"); + woal_unregister_dev(handle); + err_registerdev: + handle->surprise_removed = MTRUE; +#ifdef REASSOCIATION + if (handle->reassoc_thread.pid) { + wake_up_interruptible(&handle->reassoc_thread.wait_q); + } + /* waiting for main thread quit */ + while (handle->reassoc_thread.pid) { + woal_sched_timeout(2); + } +#endif /* REASSOCIATION */ + woal_terminate_workqueue(handle); + err_kmalloc: + if ((handle->hardware_status == HardwareStatusFwReady) || + (handle->hardware_status == HardwareStatusReady)) { + PRINTM(MINFO, "shutdown mlan\n"); + handle->init_wait_q_woken = MFALSE; + status = mlan_shutdown_fw(handle->pmlan_adapter); + if (status == MLAN_STATUS_PENDING) + wait_event_interruptible(handle->init_wait_q, + handle->init_wait_q_woken); + } + woal_free_moal_handle(handle); + if (index < MAX_MLAN_ADAPTER) { + m_handle[index] = NULL; + } + ((struct sdio_mmc_card *) card)->handle = NULL; + err_handle: + MOAL_REL_SEMAPHORE(&AddRemoveCardSem); + exit_sem_err: + LEAVE(); + return NULL; +} + +/** + * @brief This function removes the card. + * + * @param card A pointer to card + * + * @return MLAN_STATUS_SUCCESS + */ +mlan_status +woal_remove_card(void *card) +{ + moal_handle *handle = NULL; + moal_private *priv = NULL; + mlan_status status; + int i; + int index = 0; + + ENTER(); + + if (MOAL_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem)) + goto exit_sem_err; + /* Find the correct handle */ + for (index = 0; index < MAX_MLAN_ADAPTER; index++) { + if (m_handle[index] && (m_handle[index]->card == card)) { + handle = m_handle[index]; + break; + } + } + if (!handle) + goto exit_remove; + handle->surprise_removed = MTRUE; + + /* Stop data */ + for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) { + if ((priv = handle->priv[i])) { + woal_stop_queue(priv->netdev); + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); + } + } + + if ((handle->hardware_status == HardwareStatusFwReady) || + (handle->hardware_status == HardwareStatusReady)) { + /* Shutdown firmware */ + PRINTM(MIOCTL, "mlan_shutdown_fw.....\n"); + handle->init_wait_q_woken = MFALSE; + + status = mlan_shutdown_fw(handle->pmlan_adapter); + if (status == MLAN_STATUS_PENDING) + wait_event_interruptible(handle->init_wait_q, + handle->init_wait_q_woken); + PRINTM(MIOCTL, "mlan_shutdown_fw done!\n"); + } + if (atomic_read(&handle->rx_pending) || atomic_read(&handle->tx_pending) || + atomic_read(&handle->ioctl_pending)) { + PRINTM(MERROR, "ERR: rx_pending=%d,tx_pending=%d,ioctl_pending=%d\n", + atomic_read(&handle->rx_pending), + atomic_read(&handle->tx_pending), + atomic_read(&handle->ioctl_pending)); + } + + /* Remove interface */ + for (i = 0; i < handle->priv_num; i++) + woal_remove_interface(handle, i); + + woal_terminate_workqueue(handle); + +#ifdef REASSOCIATION + PRINTM(MINFO, "Free reassoc_timer\n"); + if (handle->is_reassoc_timer_set) { + woal_cancel_timer(&handle->reassoc_timer); + handle->is_reassoc_timer_set = MFALSE; + } + if (handle->reassoc_thread.pid) + wake_up_interruptible(&handle->reassoc_thread.wait_q); + + /* waiting for main thread quit */ + while (handle->reassoc_thread.pid) { + woal_sched_timeout(2); + } +#endif /* REASSOCIATION */ + +#ifdef CONFIG_PROC_FS + woal_proc_exit(handle); +#endif + /* Unregister device */ + PRINTM(MINFO, "unregister device\n"); + woal_unregister_dev(handle); + /* Free adapter structure */ + PRINTM(MINFO, "Free Adapter\n"); + woal_free_moal_handle(handle); + + for (index = 0; index < MAX_MLAN_ADAPTER; index++) { + if (m_handle[index] == handle) { + m_handle[index] = NULL; + break; + } + } + exit_remove: + MOAL_REL_SEMAPHORE(&AddRemoveCardSem); + exit_sem_err: + LEAVE(); + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief This function switch the drv_mode + * + * @param handle A pointer to moal_handle structure + * @param mode new drv_mode to switch. + * + * @return MLAN_STATUS_SUCCESS /MLAN_STATUS_FAILURE /MLAN_STATUS_PENDING + */ +mlan_status +woal_switch_drv_mode(moal_handle * handle, t_u32 mode) +{ + unsigned int i; + mlan_status status = MLAN_STATUS_SUCCESS; + moal_private *priv = NULL; + + ENTER(); + + if (MOAL_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem)) + goto exit_sem_err; + + if (woal_update_drv_tbl(handle, mode) != MLAN_STATUS_SUCCESS) { + PRINTM(MERROR, "Could not update driver mode table!\n"); + status = MLAN_STATUS_FAILURE; + goto exit; + } + + /* Reset all interfaces */ + priv = woal_get_priv(handle, MLAN_BSS_ROLE_ANY); + woal_reset_intf(priv, MOAL_PROC_WAIT, MTRUE); + + status = woal_shutdown_fw(priv, MOAL_CMD_WAIT); + if (status != MLAN_STATUS_SUCCESS) { + PRINTM(MERROR, "func shutdown failed!\n"); + goto exit; + } + + /* Shutdown firmware */ + PRINTM(MIOCTL, "mlan_shutdown_fw.....\n"); + handle->init_wait_q_woken = MFALSE; + status = mlan_shutdown_fw(handle->pmlan_adapter); + if (status == MLAN_STATUS_PENDING) + wait_event_interruptible(handle->init_wait_q, + handle->init_wait_q_woken); + PRINTM(MIOCTL, "mlan_shutdown_fw done!\n"); + if (atomic_read(&handle->rx_pending) || atomic_read(&handle->tx_pending) || + atomic_read(&handle->ioctl_pending)) { + PRINTM(MERROR, "ERR: rx_pending=%d,tx_pending=%d,ioctl_pending=%d\n", + atomic_read(&handle->rx_pending), + atomic_read(&handle->tx_pending), + atomic_read(&handle->ioctl_pending)); + } + + /* Remove interface */ + for (i = 0; i < handle->priv_num; i++) + woal_remove_interface(handle, i); + + /* Unregister mlan */ + if (handle->pmlan_adapter) { + mlan_unregister(handle->pmlan_adapter); + if (handle->malloc_count || handle->lock_count) { + PRINTM(MERROR, + "mlan has memory leak: malloc_count=%u lock_count=%u\n", + handle->malloc_count, handle->lock_count); + } + handle->pmlan_adapter = NULL; + } + + handle->priv_num = 0; + drv_mode = mode; + /* Init SW */ + if (woal_init_sw(handle)) { + PRINTM(MFATAL, "Software Init Failed\n"); + goto exit; + } + /* Init FW and HW */ + if (woal_init_fw(handle)) { + PRINTM(MFATAL, "Firmware Init Failed\n"); + goto exit; + } + LEAVE(); + return status; + exit: + MOAL_REL_SEMAPHORE(&AddRemoveCardSem); + exit_sem_err: + LEAVE(); + return status; +} + +/** + * @brief This function initializes module. + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +static int +woal_init_module(void) +{ + int ret = (int) MLAN_STATUS_SUCCESS; + int index = 0; + + ENTER(); + + /* Init the wlan_private pointer array first */ + for (index = 0; index < MAX_MLAN_ADAPTER; index++) { + m_handle[index] = NULL; + } + /* Init mutex */ + MOAL_INIT_SEMAPHORE(&AddRemoveCardSem); + + /* Register with bus */ + ret = woal_bus_register(); + + wifi_add_dev(); + + LEAVE(); + return ret; +} + +/** + * @brief This function cleans module + * + * @return N/A + */ +static void +woal_cleanup_module(void) +{ + moal_handle *handle = NULL; + int index = 0; + int i; + + ENTER(); + + if (MOAL_ACQ_SEMAPHORE_BLOCK(&AddRemoveCardSem)) + goto exit_sem_err; + for (index = 0; index < MAX_MLAN_ADAPTER; index++) { + handle = m_handle[index]; + if (!handle) + continue; + if (!handle->priv_num) + goto exit; +#ifdef SDIO_SUSPEND_RESUME +#ifdef MMC_PM_KEEP_POWER + if (handle->is_suspended == MTRUE) { + woal_sdio_resume(&(((struct sdio_mmc_card *) handle->card)->func)-> + dev); + } +#endif +#endif /* SDIO_SUSPEND_RESUME */ + + for (i = 0; i < handle->priv_num; i++) { +#ifdef STA_SUPPORT + if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA) { + if (handle->priv[i]->media_connected == MTRUE) + woal_disconnect(handle->priv[i], MOAL_CMD_WAIT, NULL); +#ifdef STA_CFG80211 + if (handle->priv[i]->scan_request) { + cfg80211_scan_done(handle->priv[i]->scan_request, MTRUE); + handle->priv[i]->scan_request = NULL; + } +#endif + } +#endif +#ifdef UAP_SUPPORT + if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_UAP) { +#ifdef MFG_CMD_SUPPORT + if (mfg_mode != MLAN_INIT_PARA_ENABLED) +#endif + woal_disconnect(handle->priv[i], MOAL_CMD_WAIT, NULL); + } +#endif +#if defined(STA_CFG80211) || defined(UAP_CFG80211) + if (handle->priv[i]->probereq_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK) + woal_cfg80211_mgmt_frame_ie(handle->priv[i], NULL, 0, NULL, 0, + NULL, 0, NULL, 0, + MGMT_MASK_PROBE_REQ); +#endif + } + +#ifdef MFG_CMD_SUPPORT + if (mfg_mode != MLAN_INIT_PARA_ENABLED) +#endif + woal_set_deep_sleep(woal_get_priv(handle, MLAN_BSS_ROLE_ANY), + MOAL_CMD_WAIT, MFALSE, 0); + +#ifdef MFG_CMD_SUPPORT + if (mfg_mode != MLAN_INIT_PARA_ENABLED) +#endif + woal_shutdown_fw(woal_get_priv(handle, MLAN_BSS_ROLE_ANY), + MOAL_CMD_WAIT); + } + + wifi_del_dev(); + + exit: + MOAL_REL_SEMAPHORE(&AddRemoveCardSem); + exit_sem_err: + /* Unregister from bus */ + woal_bus_unregister(); + LEAVE(); +} + +module_init(woal_init_module); +module_exit(woal_cleanup_module); + +module_param(fw_name, charp, 0); +MODULE_PARM_DESC(fw_name, "Firmware name"); +module_param(req_fw_nowait, int, 0); +MODULE_PARM_DESC(req_fw_nowait, + "0: Use request_firmware API; 1: Use request_firmware_nowait API"); +module_param(mac_addr, charp, 0); +MODULE_PARM_DESC(mac_addr, "MAC address"); +#ifdef MFG_CMD_SUPPORT +module_param(mfg_mode, int, 0); +MODULE_PARM_DESC(mfg_mode, + "0: Download normal firmware; 1: Download MFG firmware"); +#endif /* MFG_CMD_SUPPORT */ +module_param(drv_mode, int, 0); +#if defined(WIFI_DIRECT_SUPPORT) +MODULE_PARM_DESC(drv_mode, "Bit 0: STA; Bit 1: uAP; Bit 2: WIFIDIRECT"); +#else +MODULE_PARM_DESC(drv_mode, "Bit 0: STA; Bit 1: uAP"); +#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */ +#ifdef STA_SUPPORT +module_param(max_sta_bss, int, 0); +MODULE_PARM_DESC(max_sta_bss, "Number of STA interfaces (1)"); +#endif /* STA_SUPPORT */ +#ifdef UAP_SUPPORT +module_param(max_uap_bss, int, 0); +MODULE_PARM_DESC(max_uap_bss, "Number of uAP interfaces (1)"); +#endif /* UAP_SUPPORT */ +#if defined(WIFI_DIRECT_SUPPORT) +module_param(max_wfd_bss, int, 0); +MODULE_PARM_DESC(max_wfd_bss, "Number of WIFIDIRECT interfaces (1)"); +#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */ +#ifdef DEBUG_LEVEL1 +module_param(drvdbg, uint, 0); +MODULE_PARM_DESC(drvdbg, "Driver debug"); +#endif /* DEBUG_LEVEL1 */ +module_param(auto_ds, int, 0); +MODULE_PARM_DESC(auto_ds, + "0: MLAN default; 1: Enable auto deep sleep; 2: Disable auto deep sleep"); +module_param(ps_mode, int, 0); +MODULE_PARM_DESC(ps_mode, + "0: MLAN default; 1: Enable IEEE PS mode; 2: Disable IEEE PS mode"); +module_param(max_tx_buf, int, 0); +MODULE_PARM_DESC(max_tx_buf, "Maximum Tx buffer size (2048/4096/8192)"); +#ifdef SDIO_SUSPEND_RESUME +module_param(pm_keep_power, int, 1); +MODULE_PARM_DESC(pm_keep_power, "1: PM keep power; 0: PM no power"); +#endif +#if defined(STA_SUPPORT) +module_param(cfg_11d, int, 0); +MODULE_PARM_DESC(cfg_11d, + "0: MLAN default; 1: Enable 802.11d; 2: Disable 802.11d"); +#endif +module_param(init_cfg, charp, 0); +MODULE_PARM_DESC(init_cfg, "Init config file name"); +module_param(cal_data_cfg, charp, 0); +MODULE_PARM_DESC(cal_data_cfg, "Calibration data file name"); +module_param(minicard_pwrup, int, 0); +MODULE_PARM_DESC(minicard_pwrup, + "1: Driver load clears PDn/Rst, unload sets (default); 0: Don't do this."); +module_param(cfg80211_wext, int, 0); +MODULE_PARM_DESC(cfg80211_wext, +#ifdef STA_WEXT + "Bit 0: STA WEXT; " +#endif +#ifdef UAP_WEXT + "Bit 1: UAP WEXT; " +#endif +#ifdef STA_CFG80211 + "Bit 2: STA CFG80211; " +#endif +#ifdef UAP_CFG80211 + "Bit 3: UAP CFG80211;" +#endif + ); +MODULE_DESCRIPTION("M-WLAN Driver"); +MODULE_AUTHOR("Marvell International Ltd."); +MODULE_VERSION(MLAN_RELEASE_VERSION); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/sd8797/mlinux/moal_main.h b/drivers/net/wireless/sd8797/mlinux/moal_main.h new file mode 100644 index 000000000000..0a753dabe488 --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/moal_main.h @@ -0,0 +1,1510 @@ +/** @file moal_main.h + * + * @brief This file contains wlan driver specific defines etc. + * + * Copyright (C) 2008-2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +/******************************************************** +Change log: + 10/21/2008: initial version +********************************************************/ + +#ifndef _MOAL_MAIN_H +#define _MOAL_MAIN_H + +/* warnfix for FS redefination if any? */ +#ifdef FS +#undef FS +#endif + +/* Linux header files */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) +#include +#endif + +/* ASM files */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) +#include +#else +#include +#endif +#include +#include +#include +#include +#include + +/* Net header files */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "mlan.h" +#include "moal_shim.h" +/* Wireless header */ +#include +#if defined(STA_CFG80211) || defined(UAP_CFG80211) +#include +#include +#include +#endif +#if defined(STA_WEXT) || defined(UAP_WEXT) +#include +#include "moal_wext.h" +#endif +#ifdef STA_WEXT +#include "moal_priv.h" +#endif + +/** Define BOOLEAN */ +typedef t_u8 BOOLEAN; + +/** Driver version */ +extern char driver_version[]; + +/** Private structure for MOAL */ +typedef struct _moal_private moal_private; +/** Handle data structure for MOAL */ +typedef struct _moal_handle moal_handle; + +/** Hardware status codes */ +typedef enum _MOAL_HARDWARE_STATUS +{ + HardwareStatusReady, + HardwareStatusInitializing, + HardwareStatusFwReady, + HardwareStatusReset, + HardwareStatusClosing, + HardwareStatusNotReady +} MOAL_HARDWARE_STATUS; + +/** moal_wait_option */ +enum +{ + MOAL_NO_WAIT, + MOAL_IOCTL_WAIT, + MOAL_CMD_WAIT, + MOAL_PROC_WAIT, + MOAL_WSTATS_WAIT +}; + +/** moal_main_state */ +enum +{ + MOAL_STATE_IDLE, + MOAL_RECV_INT, + MOAL_ENTER_WORK_QUEUE, + MOAL_START_MAIN_PROCESS, + MOAL_END_MAIN_PROCESS +}; + +/** HostCmd_Header */ +typedef struct _HostCmd_Header +{ + /** Command */ + t_u16 command; + /** Size */ + t_u16 size; +} HostCmd_Header; + +#ifndef MIN +/** Find minimum */ +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/* + * OS timer specific + */ + +/** Timer structure */ +typedef struct _moal_drv_timer +{ + /** Timer list */ + struct timer_list tl; + /** Timer function */ + void (*timer_function) (void *context); + /** Timer function context */ + void *function_context; + /** Time period */ + t_u32 time_period; + /** Is timer periodic ? */ + t_u32 timer_is_periodic; + /** Is timer cancelled ? */ + t_u32 timer_is_canceled; +} moal_drv_timer, *pmoal_drv_timer; + +/** + * @brief Timer handler + * + * @param fcontext Timer context + * + * @return N/A + */ +static inline void +woal_timer_handler(unsigned long fcontext) +{ + pmoal_drv_timer timer = (pmoal_drv_timer) fcontext; + + timer->timer_function(timer->function_context); + + if (timer->timer_is_periodic == MTRUE) { + mod_timer(&timer->tl, jiffies + ((timer->time_period * HZ) / 1000)); + } else { + timer->timer_is_canceled = MTRUE; + timer->time_period = 0; + } +} + +/** + * @brief Initialize timer + * + * @param timer Timer structure + * @param TimerFunction Timer function + * @param FunctionContext Timer function context + * + * @return N/A + */ +static inline void +woal_initialize_timer(pmoal_drv_timer timer, + void (*TimerFunction) (void *context), + void *FunctionContext) +{ + /* First, setup the timer to trigger the wlan_timer_handler proxy */ + init_timer(&timer->tl); + timer->tl.function = woal_timer_handler; + timer->tl.data = (t_ptr) timer; + + /* Then tell the proxy which function to call and what to pass it */ + timer->timer_function = TimerFunction; + timer->function_context = FunctionContext; + timer->timer_is_canceled = MTRUE; + timer->time_period = 0; + timer->timer_is_periodic = MFALSE; +} + +/** + * @brief Modify timer + * + * @param timer Timer structure + * @param MillisecondPeriod Time period in millisecond + * + * @return N/A + */ +static inline void +woal_mod_timer(pmoal_drv_timer timer, t_u32 MillisecondPeriod) +{ + timer->time_period = MillisecondPeriod; + mod_timer(&timer->tl, jiffies + (MillisecondPeriod * HZ) / 1000); + timer->timer_is_canceled = MFALSE; +} + +/** + * @brief Cancel timer + * + * @param timer Timer structure + * + * @return N/A + */ +static inline void +woal_cancel_timer(moal_drv_timer * timer) +{ + del_timer(&timer->tl); + timer->timer_is_canceled = MTRUE; + timer->time_period = 0; +} + +#ifdef REASSOCIATION +/* + * OS Thread Specific + */ + +#include + +/** Kernel thread structure */ +typedef struct _moal_thread +{ + /** Task control structrue */ + struct task_struct *task; + /** Pointer to wait_queue_head */ + wait_queue_head_t wait_q; + /** PID */ + pid_t pid; + /** Pointer to moal_handle */ + void *handle; +} moal_thread; + +/** + * @brief Activate thread + * + * @param thr Thread structure + * @return N/A + */ +static inline void +woal_activate_thread(moal_thread * thr) +{ + /** Initialize the wait queue */ + init_waitqueue_head(&thr->wait_q); + + /** Record the thread pid */ + thr->pid = current->pid; +} + +/** + * @brief De-activate thread + * + * @param thr Thread structure + * @return N/A + */ +static inline void +woal_deactivate_thread(moal_thread * thr) +{ + /* Reset the pid */ + thr->pid = 0; +} + +/** + * @brief Create and run the thread + * + * @param threadfunc Thread function + * @param thr Thread structure + * @param name Thread name + * @return N/A + */ +static inline void +woal_create_thread(int (*threadfunc) (void *), moal_thread * thr, char *name) +{ + /* Create and run the thread */ + thr->task = kthread_run(threadfunc, thr, "%s", name); +} +#endif /* REASSOCIATION */ + +/* The following macros are neccessary to retain compatibility + * around the workqueue chenges happened in kernels >= 2.6.20: + * - INIT_WORK changed to take 2 arguments and let the work function + * get its own data through the container_of macro + * - delayed works have been split from normal works to save some + * memory usage in struct work_struct + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) +/** Work_queue work initialization */ +#define MLAN_INIT_WORK(_work, _fun) INIT_WORK(_work, ((void (*)(void *))_fun), _work) +/** Work_queue delayed work initialization */ +#define MLAN_INIT_DELAYED_WORK(_work, _fun) INIT_WORK(_work, ((void (*)(void *))_fun), _work) +/** Work_queue container parameter */ +#define MLAN_DELAYED_CONTAINER_OF(_ptr, _type, _m) container_of(_ptr, _type, _m) +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) */ +/** Work_queue work initialization */ +#define MLAN_INIT_WORK INIT_WORK +/** Work_queue delayed work initialization */ +#define MLAN_INIT_DELAYED_WORK INIT_DELAYED_WORK +/** Work_queue container parameter */ +#define MLAN_DELAYED_CONTAINER_OF(_ptr, _type, _m) container_of(_ptr, _type, _m.work) +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) */ + +/** + * @brief Schedule timeout + * + * @param millisec Timeout duration in milli second + * + * @return N/A + */ +static inline void +woal_sched_timeout(t_u32 millisec) +{ + set_current_state(TASK_INTERRUPTIBLE); + + schedule_timeout((millisec * HZ) / 1000); +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) +#define IN6PTON_XDIGIT 0x00010000 +#define IN6PTON_DIGIT 0x00020000 +#define IN6PTON_COLON_MASK 0x00700000 +#define IN6PTON_COLON_1 0x00100000 /* single : requested */ +#define IN6PTON_COLON_2 0x00200000 /* second : requested */ +#define IN6PTON_COLON_1_2 0x00400000 /* :: requested */ +#define IN6PTON_DOT 0x00800000 /* . */ +#define IN6PTON_DELIM 0x10000000 +#define IN6PTON_NULL 0x20000000 /* first/tail */ +#define IN6PTON_UNKNOWN 0x40000000 + +static inline int +xdigit2bin(char c, int delim) +{ + if (c == delim || c == '\0') + return IN6PTON_DELIM; + if (c == ':') + return IN6PTON_COLON_MASK; + if (c == '.') + return IN6PTON_DOT; + if (c >= '0' && c <= '9') + return (IN6PTON_XDIGIT | IN6PTON_DIGIT | (c - '0')); + if (c >= 'a' && c <= 'f') + return (IN6PTON_XDIGIT | (c - 'a' + 10)); + if (c >= 'A' && c <= 'F') + return (IN6PTON_XDIGIT | (c - 'A' + 10)); + if (delim == -1) + return IN6PTON_DELIM; + return IN6PTON_UNKNOWN; +} + +static inline int +in4_pton(const char *src, int srclen, u8 * dst, int delim, const char **end) +{ + const char *s; + u8 *d; + u8 dbuf[4]; + int ret = 0; + int i; + int w = 0; + + if (srclen < 0) + srclen = strlen(src); + s = src; + d = dbuf; + i = 0; + while (1) { + int c; + c = xdigit2bin(srclen > 0 ? *s : '\0', delim); + if (! + (c & + (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM | + IN6PTON_COLON_MASK))) { + goto out; + } + if (c & (IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK)) { + if (w == 0) + goto out; + *d++ = w & 0xff; + w = 0; + i++; + if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) { + if (i != 4) + goto out; + break; + } + goto cont; + } + w = (w * 10) + c; + if ((w & 0xffff) > 255) { + goto out; + } + cont: + if (i >= 4) + goto out; + s++; + srclen--; + } + ret = 1; + memcpy(dst, dbuf, sizeof(dbuf)); + out: + if (end) + *end = s; + return ret; +} +#endif /* < 2.6.19 */ + +#ifndef __ATTRIB_ALIGN__ +#define __ATTRIB_ALIGN__ __attribute__((aligned(4))) +#endif + +#ifndef __ATTRIB_PACK__ +#define __ATTRIB_PACK__ __attribute__ ((packed)) +#endif + +/** Get module */ +#define MODULE_GET try_module_get(THIS_MODULE) +/** Put module */ +#define MODULE_PUT module_put(THIS_MODULE) + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) +/** Initialize semaphore */ +#define MOAL_INIT_SEMAPHORE(x) init_MUTEX(x) +/** Initialize semaphore */ +#define MOAL_INIT_SEMAPHORE_LOCKED(x) init_MUTEX_LOCKED(x) +#else +/** Initialize semaphore */ +#define MOAL_INIT_SEMAPHORE(x) sema_init(x,1) +/** Initialize semaphore */ +#define MOAL_INIT_SEMAPHORE_LOCKED(x) sema_init(x,0) +#endif + +/** Acquire semaphore and with blocking */ +#define MOAL_ACQ_SEMAPHORE_BLOCK(x) down_interruptible(x) +/** Acquire semaphore without blocking */ +#define MOAL_ACQ_SEMAPHORE_NOBLOCK(x) down_trylock(x) +/** Release semaphore */ +#define MOAL_REL_SEMAPHORE(x) up(x) + +/** Request FW timeout in second */ +#define REQUEST_FW_TIMEOUT 30 + +/** Default watchdog timeout */ +#define MRVDRV_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ) + +#ifdef UAP_SUPPORT +/** Default watchdog timeout + Increase the value to avoid kernel Tx timeout message in case + station in PS mode or left. + The default value of PS station ageout timer is 40 seconds. + Hence, the watchdog timer is set to a value higher than it. +*/ +#define MRVDRV_DEFAULT_UAP_WATCHDOG_TIMEOUT (41 * HZ) +#endif + +/** Threshold value of number of times the Tx timeout happened */ +#define NUM_TX_TIMEOUT_THRESHOLD 5 + +/** 10 seconds */ +#define MOAL_TIMER_10S 10000 +/** 5 seconds */ +#define MOAL_TIMER_5S 5000 +/** 1 second */ +#define MOAL_TIMER_1S 1000 + +/** Default value of re-assoc timer */ +#define REASSOC_TIMER_DEFAULT 500 + +/** Netlink protocol number */ +#define NETLINK_MARVELL (MAX_LINKS - 1) +/** Netlink maximum payload size */ +#define NL_MAX_PAYLOAD 1024 +/** Netlink multicast group number */ +#define NL_MULTICAST_GROUP 1 + +/** MAX Tx Pending count */ +#define MAX_TX_PENDING 100 + +/** LOW Tx Pending count */ +#define LOW_TX_PENDING 80 + +/** Offset for subcommand */ +#define SUBCMD_OFFSET 4 + +/** Macro to extract the TOS field from a skb */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) +#define SKB_TOS(skb) (ip_hdr(skb)->tos) +#else +#define SKB_TOS(skb) (skb->nh.iph->tos) +#endif + +/** Offset for TOS field in the IP header */ +#define IPTOS_OFFSET 5 + +/** Offset for DSCP in the tos field */ +#define DSCP_OFFSET 2 + +/** wait_queue structure */ +typedef struct _wait_queue +{ + /** Pointer to wait_queue_head */ + wait_queue_head_t *wait; + /** Wait condition */ + BOOLEAN condition; + /** Start time */ + t_u32 start_time; + /** Status from MLAN */ + mlan_status status; +} wait_queue, *pwait_queue; + +/** Auto Rate */ +#define AUTO_RATE 0xFF + +#define STA_WEXT_MASK MBIT(0) +#define UAP_WEXT_MASK MBIT(1) +#define STA_CFG80211_MASK MBIT(2) +#define UAP_CFG80211_MASK MBIT(3) +#ifdef STA_CFG80211 +#ifdef STA_SUPPORT +/** Is STA CFG80211 enabled in module param */ +#define IS_STA_CFG80211(x) (x & STA_CFG80211_MASK) +#endif +#endif +#ifdef UAP_CFG80211 +#ifdef UAP_SUPPORT +/** Is UAP CFG80211 enabled in module param */ +#define IS_UAP_CFG80211(x) (x & UAP_CFG80211_MASK) +#endif +#endif +#if defined(STA_CFG80211) || defined(UAP_CFG80211) +/** Is UAP or STA CFG80211 enabled in module param */ +#define IS_STA_OR_UAP_CFG80211(x) (x & (STA_CFG80211_MASK | UAP_CFG80211_MASK)) +#endif + +#ifdef STA_WEXT +/** Is STA WEXT enabled in module param */ +#define IS_STA_WEXT(x) (x & STA_WEXT_MASK) +#endif /* STA_WEXT */ +#ifdef UAP_WEXT +/** Is UAP WEXT enabled in module param */ +#define IS_UAP_WEXT(x) (x & UAP_WEXT_MASK) +#endif /* UAP_WEXT */ +#if defined(STA_WEXT) || defined(UAP_WEXT) +/** Is UAP or STA WEXT enabled in module param */ +#define IS_STA_OR_UAP_WEXT(x) (x & (STA_WEXT_MASK | UAP_WEXT_MASK)) +#endif + +#ifdef STA_SUPPORT +/** Driver mode STA bit */ +#define DRV_MODE_STA MBIT(0) +/** Maximum STA BSS */ +#define MAX_STA_BSS 1 +/** Default STA BSS */ +#define DEF_STA_BSS 1 +#endif +#ifdef UAP_SUPPORT +/** Driver mode uAP bit */ +#define DRV_MODE_UAP MBIT(1) +/** Maximum uAP BSS */ +#define MAX_UAP_BSS 2 +/** Default uAP BSS */ +#define DEF_UAP_BSS 1 +#endif +#if defined(WIFI_DIRECT_SUPPORT) +/** Driver mode WIFIDIRECT bit */ +#define DRV_MODE_WIFIDIRECT MBIT(2) +/** Maximum WIFIDIRECT BSS */ +#define MAX_WIFIDIRECT_BSS 1 +/** Default WIFIDIRECT BSS */ +#define DEF_WIFIDIRECT_BSS 1 +#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */ + +typedef struct _moal_drv_mode +{ + /** driver mode */ + t_u16 drv_mode; + /** total number of interfaces */ + t_u16 intf_num; + /** attribute of bss */ + mlan_bss_attr *bss_attr; + /** name of firmware image */ + char *fw_name; +} moal_drv_mode; + +#ifdef PROC_DEBUG +/** Debug data */ +struct debug_data +{ + /** Name */ + char name[32]; + /** Size */ + t_u32 size; + /** Address */ + t_ptr addr; +}; + +/** Private debug data */ +struct debug_data_priv +{ + /** moal_private handle */ + moal_private *priv; + /** Debug items */ + struct debug_data *items; + /** numbre of item */ + int num_of_items; +}; +#endif + +/** Maximum IP address buffer length */ +#define IPADDR_MAX_BUF 20 +/** IP address operation: Remove */ +#define IPADDR_OP_REMOVE 0 + +/** Private structure for MOAL */ +struct _moal_private +{ + /** Handle structure */ + moal_handle *phandle; + /** Tx timeout count */ + t_u32 num_tx_timeout; + /** BSS index */ + t_u8 bss_index; + /** BSS type */ + t_u8 bss_type; + /** BSS role */ + t_u8 bss_role; + /** MAC address information */ + t_u8 current_addr[ETH_ALEN]; + /** Media connection status */ + BOOLEAN media_connected; +#ifdef UAP_SUPPORT + /** uAP started or not */ + BOOLEAN bss_started; +#endif +#ifdef STA_SUPPORT + /** scan type */ + t_u8 scan_type; + /** bg_scan_start */ + t_u8 bg_scan_start; + /** bg_scan reported */ + t_u8 bg_scan_reported; + /** bg_scan config */ + wlan_bgscan_cfg scan_cfg; +#endif + /** Net device pointer */ + struct net_device *netdev; + /** Net device statistics structure */ + struct net_device_stats stats; +#if defined(STA_CFG80211) || defined(UAP_CFG80211) + /** Country code for regulatory domain */ + t_u8 country_code[COUNTRY_CODE_LEN]; + /** Wireless device pointer */ + struct wireless_dev *wdev; + /** channel parameter for UAP/GO */ + t_u16 channel; + /** cipher */ + t_u32 cipher; + /** key index */ + t_u8 key_index; + /** key len */ + t_u16 key_len; + /** key data */ + t_u8 key_material[MLAN_MAX_KEY_LENGTH]; + /** probereq index for mgmt ie */ + t_u16 probereq_index; +#endif +#ifdef STA_CFG80211 +#ifdef STA_SUPPORT + /** CFG80211 scan request description */ + struct cfg80211_scan_request *scan_request; + /** CFG80211 association description */ + t_u8 cfg_bssid[ETH_ALEN]; + /** Disconnect request from CFG80211 */ + bool cfg_disconnect; +#endif /* STA_SUPPORT */ +#endif /* STA_CFG80211 */ + /** IOCTL wait queue */ + wait_queue_head_t ioctl_wait_q __ATTRIB_ALIGN__; + /** CMD wait queue */ + wait_queue_head_t cmd_wait_q __ATTRIB_ALIGN__; +#ifdef CONFIG_PROC_FS + /** Proc entry */ + struct proc_dir_entry *proc_entry; + /** Proc entry name */ + t_s8 proc_entry_name[IFNAMSIZ]; + /** PROC wait queue */ + wait_queue_head_t proc_wait_q __ATTRIB_ALIGN__; +#endif /* CONFIG_PROC_FS */ +#ifdef STA_SUPPORT + /** Nickname */ + t_u8 nick_name[16]; + /** AdHoc link sensed flag */ + BOOLEAN is_adhoc_link_sensed; + /** Current WEP key index */ + t_u16 current_key_index; +#ifdef REASSOCIATION + mlan_ssid_bssid prev_ssid_bssid; + /** Re-association required */ + BOOLEAN reassoc_required; + /** Flag of re-association on/off */ + BOOLEAN reassoc_on; +#endif /* REASSOCIATION */ + /** Report scan result */ + t_u8 report_scan_result; + /** wpa_version */ + t_u8 wpa_version; + /** key mgmt */ + t_u8 key_mgmt; + /** rx_filter */ + t_u8 rx_filter; +#endif /* STA_SUPPORT */ + /** Rate index */ + t_u16 rate_index; +#if defined(STA_WEXT) || defined(UAP_WEXT) + /** IW statistics */ + struct iw_statistics w_stats; + /** w_stats wait queue */ + wait_queue_head_t w_stats_wait_q __ATTRIB_ALIGN__; +#endif +#ifdef UAP_WEXT + /** Pairwise Cipher used for WPA/WPA2 mode */ + t_u16 pairwise_cipher; + /** Group Cipher */ + t_u16 group_cipher; + /** Protocol stored during uap wext configuratoin */ + t_u16 uap_protocol; + /** Key Mgmt whether PSK or 1x */ + t_u16 uap_key_mgmt; + /** Beacon IE length from hostapd */ + t_u16 bcn_ie_len; + /** Beacon IE buffer from hostapd */ + t_u8 bcn_ie_buf[MAX_IE_SIZE]; +#endif + +#ifdef PROC_DEBUG + /** MLAN debug info */ + struct debug_data_priv items_priv; +#endif +}; + +/** Handle data structure for MOAL */ +struct _moal_handle +{ + /** MLAN adapter structure */ + t_void *pmlan_adapter; + /** Private pointer */ + moal_private *priv[MLAN_MAX_BSS_NUM]; + /** Priv number */ + t_u8 priv_num; + /** Bss attr */ + moal_drv_mode drv_mode; + /** set mac address flag */ + t_u8 set_mac_addr; + /** MAC address */ + t_u8 mac_addr[ETH_ALEN]; +#ifdef CONFIG_PROC_FS + /** Proc top level directory entry */ + struct proc_dir_entry *proc_mwlan; +#endif + /** Firmware */ + const struct firmware *firmware; + /** Firmware request start time */ + struct timeval req_fw_time; + /** Init config file */ + const struct firmware *user_data; + /** Hotplug device */ + struct device *hotplug_device; + /** STATUS variables */ + MOAL_HARDWARE_STATUS hardware_status; + /** POWER MANAGEMENT AND PnP SUPPORT */ + BOOLEAN surprise_removed; + /** Firmware release number */ + t_u32 fw_release_number; + /** Init wait queue token */ + t_u16 init_wait_q_woken; + /** Init wait queue */ + wait_queue_head_t init_wait_q __ATTRIB_ALIGN__; + /** Device suspend flag */ + BOOLEAN is_suspended; +#ifdef SDIO_SUSPEND_RESUME + /** suspend notify flag */ + BOOLEAN suspend_notify_req; +#endif + /** Host Sleep activated flag */ + t_u8 hs_activated; + /** Host Sleep activated event wait queue token */ + t_u16 hs_activate_wait_q_woken; + /** Host Sleep activated event wait queue */ + wait_queue_head_t hs_activate_wait_q __ATTRIB_ALIGN__; + /** Card pointer */ + t_void *card; + /** Rx pending in MLAN */ + atomic_t rx_pending; + /** Tx packet pending count in mlan */ + atomic_t tx_pending; + /** IOCTL pending count in mlan */ + atomic_t ioctl_pending; + /** Malloc count */ + t_u32 malloc_count; + /** lock count */ + t_u32 lock_count; + /** mlan buffer alloc count */ + t_u32 mbufalloc_count; + /** hs skip count */ + t_u32 hs_skip_count; + /** hs force count */ + t_u32 hs_force_count; + /** suspend_fail flag */ + BOOLEAN suspend_fail; +#ifdef REASSOCIATION + /** Re-association thread */ + moal_thread reassoc_thread; + /** Re-association timer set flag */ + BOOLEAN is_reassoc_timer_set; + /** Re-association timer */ + moal_drv_timer reassoc_timer __ATTRIB_ALIGN__; + /** */ + struct semaphore reassoc_sem; + /** Bitmap for re-association on/off */ + t_u8 reassoc_on; +#endif /* REASSOCIATION */ + /** Driver workqueue */ + struct workqueue_struct *workqueue; + /** main work */ + struct work_struct main_work; +#if defined(STA_CFG80211) || defined(UAP_CFG80211) +#ifdef WIFI_DIRECT_SUPPORT + /** remain on channel flag */ + t_u8 remain_on_channel; + /** ieee802_11_channel */ + struct ieee80211_channel chan; + /** channel type */ + enum nl80211_channel_type channel_type; + /** cookie */ + t_u64 cookie; +#endif +#endif + /** Read SDIO registers for debugging */ + t_u32 sdio_reg_dbg; + /** Netlink kernel socket */ + struct sock *nl_sk; + /** Netlink kernel socket number */ + t_u32 netlink_num; + /** w_stats wait queue token */ + BOOLEAN meas_wait_q_woken; + /** w_stats wait queue */ + wait_queue_head_t meas_wait_q __ATTRIB_ALIGN__; + /** Measurement start jiffes */ + t_u32 meas_start_jiffies; + /** CAC checking period flag */ + BOOLEAN cac_period; + /** BSS START command delay executing flag */ + BOOLEAN delay_bss_start; + /** SSID,BSSID parameter of delay executing */ + mlan_ssid_bssid delay_ssid_bssid; +#ifdef DFS_TESTING_SUPPORT + /** cac period length, valid only when dfs testing is enabled */ + t_u32 cac_period_jiffies; +#endif + /** handle index - for multiple card supports */ + t_u8 handle_idx; +#ifdef SDIO_MMC_DEBUG + /** cmd53 write state */ + u8 cmd53w; + /** cmd53 read state */ + u8 cmd53r; +#endif +#ifdef STA_SUPPORT + /** Scan pending on blocked flag */ + t_u8 scan_pending_on_block; + /** Async scan semaphore */ + struct semaphore async_sem; + +#endif + /** main state */ + t_u8 main_state; + /** cmd52 function */ + t_u8 cmd52_func; + /** cmd52 register */ + t_u8 cmd52_reg; + /** cmd52 value */ + t_u8 cmd52_val; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) + /** spinlock to stop_queue/wake_queue*/ + spinlock_t queue_lock; +#endif +}; + +/** + * @brief set trans_start for each TX queue. + * + * @param dev A pointer to net_device structure + * + * @return N/A + */ +static inline void +woal_set_trans_start(struct net_device *dev) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) + unsigned int i; + for (i = 0; i < dev->num_tx_queues; i++) { + netdev_get_tx_queue(dev, i)->trans_start = jiffies; + } +#endif + dev->trans_start = jiffies; +} + +/** + * @brief Start queue + * + * @param dev A pointer to net_device structure + * + * @return N/A + */ +static inline void +woal_start_queue(struct net_device *dev) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) + netif_start_queue(dev); +#else + netif_tx_start_all_queues(dev); +#endif +} + +/** + * @brief Stop queue + * + * @param dev A pointer to net_device structure + * + * @return N/A + */ +static inline void +woal_stop_queue(struct net_device *dev) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) + unsigned long flags; + moal_private *priv = (moal_private *) netdev_priv(dev); + spin_lock_irqsave(&priv->phandle->queue_lock, flags); + woal_set_trans_start(dev); + if (!netif_queue_stopped(dev)) + netif_tx_stop_all_queues(dev); + spin_unlock_irqrestore(&priv->phandle->queue_lock, flags); +#else + woal_set_trans_start(dev); + if (!netif_queue_stopped(dev)) + netif_stop_queue(dev); +#endif +} + +/** + * @brief wake queue + * + * @param dev A pointer to net_device structure + * + * @return N/A + */ +static inline void +woal_wake_queue(struct net_device *dev) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) + unsigned long flags; + moal_private *priv = (moal_private *) netdev_priv(dev); + spin_lock_irqsave(&priv->phandle->queue_lock, flags); + if (netif_queue_stopped(dev)) + netif_tx_wake_all_queues(dev); + spin_unlock_irqrestore(&priv->phandle->queue_lock, flags); +#else + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); +#endif +} + +/** Max number of char in custom event - use multiple of them if needed */ +#define IW_CUSTOM_MAX 256 /* In bytes */ + +/** Debug Macro definition*/ +#ifdef DEBUG_LEVEL1 +extern t_u32 drvdbg; + +#ifdef DEBUG_LEVEL2 +#define PRINTM_MINFO(msg...) do {if (drvdbg & MINFO) printk(KERN_DEBUG msg);} while(0) +#define PRINTM_MWARN(msg...) do {if (drvdbg & MWARN) printk(KERN_DEBUG msg);} while(0) +#define PRINTM_MENTRY(msg...) do {if (drvdbg & MENTRY) printk(KERN_DEBUG msg);} while(0) +#else +#define PRINTM_MINFO(msg...) do {} while (0) +#define PRINTM_MWARN(msg...) do {} while (0) +#define PRINTM_MENTRY(msg...) do {} while (0) +#endif /* DEBUG_LEVEL2 */ + +#define PRINTM_MFW_D(msg...) do {if (drvdbg & MFW_D) printk(KERN_DEBUG msg);} while(0) +#define PRINTM_MCMD_D(msg...) do {if (drvdbg & MCMD_D) printk(KERN_DEBUG msg);} while(0) +#define PRINTM_MDAT_D(msg...) do {if (drvdbg & MDAT_D) printk(KERN_DEBUG msg);} while(0) +#define PRINTM_MIF_D(msg...) do {if (drvdbg & MIF_D) printk(KERN_DEBUG msg);} while(0) + +#define PRINTM_MIOCTL(msg...) do {if (drvdbg & MIOCTL) printk(KERN_DEBUG msg);} while(0) +#define PRINTM_MINTR(msg...) do {if (drvdbg & MINTR) printk(KERN_DEBUG msg);} while(0) +#define PRINTM_MEVENT(msg...) do {if (drvdbg & MEVENT) printk(msg);} while(0) +#define PRINTM_MCMND(msg...) do {if (drvdbg & MCMND) printk(KERN_DEBUG msg);} while(0) +#define PRINTM_MDATA(msg...) do {if (drvdbg & MDATA) printk(KERN_DEBUG msg);} while(0) +#define PRINTM_MERROR(msg...) do {if (drvdbg & MERROR) printk(KERN_ERR msg);} while(0) +#define PRINTM_MFATAL(msg...) do {if (drvdbg & MFATAL) printk(KERN_ERR msg);} while(0) +#define PRINTM_MMSG(msg...) do {if (drvdbg & MMSG) printk(KERN_ALERT msg);} while(0) + +#define PRINTM(level,msg...) PRINTM_##level(msg) + +#else + +#define PRINTM(level,msg...) do {} while (0) + +#endif /* DEBUG_LEVEL1 */ + +/** Wait until a condition becomes true */ +#define MASSERT(cond) \ +do { \ + if (!(cond)) { \ + PRINTM(MFATAL, "ASSERT: %s: %i\n", __FUNCTION__, __LINE__); \ + panic("Assert failed: Panic!"); \ + } \ +} while(0) + +/** Log entry point for debugging */ +#define ENTER() PRINTM(MENTRY, "Enter: %s\n", \ + __FUNCTION__) +/** Log exit point for debugging */ +#define LEAVE() PRINTM(MENTRY, "Leave: %s\n", \ + __FUNCTION__) + +#ifdef DEBUG_LEVEL1 +#define DBG_DUMP_BUF_LEN 64 +#define MAX_DUMP_PER_LINE 16 + +static inline void +hexdump(char *prompt, t_u8 * buf, int len) +{ + int i; + char dbgdumpbuf[DBG_DUMP_BUF_LEN]; + char *ptr = dbgdumpbuf; + + printk(KERN_DEBUG "%s:\n", prompt); + for (i = 1; i <= len; i++) { + ptr += snprintf(ptr, 4, "%02x ", *buf); + buf++; + if (i % MAX_DUMP_PER_LINE == 0) { + *ptr = 0; + printk(KERN_DEBUG "%s\n", dbgdumpbuf); + ptr = dbgdumpbuf; + } + } + if (len % MAX_DUMP_PER_LINE) { + *ptr = 0; + printk(KERN_DEBUG "%s\n", dbgdumpbuf); + } +} + +#define DBG_HEXDUMP_MERROR(x,y,z) do {if (drvdbg & MERROR) hexdump(x,y,z);} while(0) +#define DBG_HEXDUMP_MCMD_D(x,y,z) do {if (drvdbg & MCMD_D) hexdump(x,y,z);} while(0) +#define DBG_HEXDUMP_MDAT_D(x,y,z) do {if (drvdbg & MDAT_D) hexdump(x,y,z);} while(0) +#define DBG_HEXDUMP_MIF_D(x,y,z) do {if (drvdbg & MIF_D) hexdump(x,y,z);} while(0) +#define DBG_HEXDUMP_MEVT_D(x,y,z) do {if (drvdbg & MEVT_D) hexdump(x,y,z);} while(0) +#define DBG_HEXDUMP_MFW_D(x,y,z) do {if (drvdbg & MFW_D) hexdump(x,y,z);} while(0) +#define DBG_HEXDUMP(level,x,y,z) DBG_HEXDUMP_##level(x,y,z) + +#else +/** Do nothing since debugging is not turned on */ +#define DBG_HEXDUMP(level,x,y,z) do {} while (0) +#endif + +#ifdef DEBUG_LEVEL2 +#define HEXDUMP(x,y,z) do {if (drvdbg & MINFO) hexdump(x,y,z);} while(0) +#else +/** Do nothing since debugging is not turned on */ +#define HEXDUMP(x,y,z) do {} while (0) +#endif + +#ifdef BIG_ENDIAN_SUPPORT +/** Convert from 16 bit little endian format to CPU format */ +#define woal_le16_to_cpu(x) le16_to_cpu(x) +/** Convert from 32 bit little endian format to CPU format */ +#define woal_le32_to_cpu(x) le32_to_cpu(x) +/** Convert from 64 bit little endian format to CPU format */ +#define woal_le64_to_cpu(x) le64_to_cpu(x) +/** Convert to 16 bit little endian format from CPU format */ +#define woal_cpu_to_le16(x) cpu_to_le16(x) +/** Convert to 32 bit little endian format from CPU format */ +#define woal_cpu_to_le32(x) cpu_to_le32(x) +/** Convert to 64 bit little endian format from CPU format */ +#define woal_cpu_to_le64(x) cpu_to_le64(x) +#else +/** Do nothing */ +#define woal_le16_to_cpu(x) x +/** Do nothing */ +#define woal_le32_to_cpu(x) x +/** Do nothing */ +#define woal_le64_to_cpu(x) x +/** Do nothing */ +#define woal_cpu_to_le16(x) x +/** Do nothing */ +#define woal_cpu_to_le32(x) x +/** Do nothing */ +#define woal_cpu_to_le64(x) x +#endif + +/** + * @brief This function returns first available priv + * based on the BSS role + * + * @param handle A pointer to moal_handle + * @param bss_role BSS role or MLAN_BSS_ROLE_ANY + * + * @return Pointer to moal_private + */ +static inline moal_private * +woal_get_priv(moal_handle * handle, mlan_bss_role bss_role) +{ + int i; + + for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) { + if (handle->priv[i]) { + if (bss_role == MLAN_BSS_ROLE_ANY || + GET_BSS_ROLE(handle->priv[i]) == bss_role) + return (handle->priv[i]); + } + } + return NULL; +} + +/** Max line length allowed in init config file */ +#define MAX_LINE_LEN 256 +/** Max MAC address string length allowed */ +#define MAX_MAC_ADDR_LEN 18 +/** Max register type/offset/value etc. parameter length allowed */ +#define MAX_PARAM_LEN 12 + +/** HostCmd_CMD_CFG_DATA for CAL data */ +#define HostCmd_CMD_CFG_DATA 0x008f +/** HostCmd action set */ +#define HostCmd_ACT_GEN_SET 0x0001 +/** HostCmd CAL data header length */ +#define CFG_DATA_HEADER_LEN 6 + +typedef struct _HostCmd_DS_GEN +{ + t_u16 command; + t_u16 size; + t_u16 seq_num; + t_u16 result; +} HostCmd_DS_GEN; + +typedef struct _HostCmd_DS_802_11_CFG_DATA +{ + /** Action */ + t_u16 action; + /** Type */ + t_u16 type; + /** Data length */ + t_u16 data_len; + /** Data */ + t_u8 data[1]; +} __ATTRIB_PACK__ HostCmd_DS_802_11_CFG_DATA; + +/** combo scan header */ +#define WEXT_CSCAN_HEADER "CSCAN S\x01\x00\x00S\x00" +/** combo scan header size */ +#define WEXT_CSCAN_HEADER_SIZE 12 +/** combo scan ssid section */ +#define WEXT_CSCAN_SSID_SECTION 'S' +/** commbo scan channel section */ +#define WEXT_CSCAN_CHANNEL_SECTION 'C' +/** commbo scan passive dwell section */ +#define WEXT_CSCAN_PASV_DWELL_SECTION 'P' +/** commbo scan home dwell section */ +#define WEXT_CSCAN_HOME_DWELL_SECTION 'H' +/** BGSCAN RSSI section */ +#define WEXT_BGSCAN_RSSI_SECTION 'R' +/** BGSCAN SCAN INTERVAL SECTION */ +#define WEXT_BGSCAN_INTERVAL_SECTION 'T' + +/** band AUTO */ +#define WIFI_FREQUENCY_BAND_AUTO 0 +/** band 5G */ +#define WIFI_FREQUENCY_BAND_5GHZ 1 +/** band 2G */ +#define WIFI_FREQUENCY_BAND_2GHZ 2 +/** All band */ +#define WIFI_FREQUENCY_ALL_BAND 3 + +/** Rx filter: IPV4 multicast */ +#define RX_FILTER_IPV4_MULTICAST 1 +/** Rx filter: broadcast */ +#define RX_FILTER_BROADCAST 2 +/** Rx filter: unicast */ +#define RX_FILTER_UNICAST 4 +/** Rx filter: IPV6 multicast */ +#define RX_FILTER_IPV6_MULTICAST 8 + +/** Convert ASCII string to hex value */ +int woal_ascii2hex(t_u8 * d, char *s, t_u32 dlen); +/** Convert mac address from string to t_u8 buffer */ +void woal_mac2u8(t_u8 * mac_addr, char *buf); +/** Extract token from string */ +char *woal_strsep(char **s, char delim, char esc); +/** Return int value of a given ASCII string */ +mlan_status woal_atoi(int *data, char *a); +/** Return hex value of a given ASCII string */ +int woal_atox(char *a); +/** Allocate buffer */ +pmlan_buffer woal_alloc_mlan_buffer(moal_handle * handle, int size); +/** Allocate IOCTL request buffer */ +pmlan_ioctl_req woal_alloc_mlan_ioctl_req(int size); +/** Free buffer */ +void woal_free_mlan_buffer(moal_handle * handle, pmlan_buffer pmbuf); +/** Get private structure of a BSS by index */ +moal_private *woal_bss_index_to_priv(moal_handle * handle, t_u8 bss_index); +/* Functions in interface module */ +/** Add card */ +moal_handle *woal_add_card(void *card); +/** Remove card */ +mlan_status woal_remove_card(void *card); +/** broadcast event */ +mlan_status woal_broadcast_event(moal_private * priv, t_u8 * payload, + t_u32 len); +/** switch driver mode */ +mlan_status woal_switch_drv_mode(moal_handle * handle, t_u32 mode); + +/** Interrupt handler */ +void woal_interrupt(moal_handle * handle); + +#ifdef STA_WEXT +#endif +/** Get version */ +void woal_get_version(moal_handle * handle, char *version, int maxlen); +/** Get Driver Version */ +int woal_get_driver_version(moal_private * priv, struct ifreq *req); +/** Get extended driver version */ +int woal_get_driver_verext(moal_private * priv, struct ifreq *ireq); +/** Mgmt frame forward registration */ +int woal_reg_rx_mgmt_ind(moal_private * priv, t_u16 action, + t_u32 * pmgmt_subtype_mask, t_u8 wait_option); +#ifdef DEBUG_LEVEL1 +/** Set driver debug bit masks */ +int woal_set_drvdbg(moal_private * priv, t_u32 drvdbg); +#endif +/** Set/Get TX beamforming configurations */ +mlan_status woal_set_get_tx_bf_cfg(moal_private * priv, t_u16 action, + mlan_ds_11n_tx_bf_cfg * bf_cfg); +/** Request MAC address setting */ +mlan_status woal_request_set_mac_address(moal_private * priv); +/** Request multicast list setting */ +void woal_request_set_multicast_list(moal_private * priv, + struct net_device *dev); +/** Request IOCTL action */ +mlan_status woal_request_ioctl(moal_private * priv, mlan_ioctl_req * req, + t_u8 wait_option); +mlan_status woal_request_soft_reset(moal_handle * handle); +#ifdef PROC_DEBUG +/** Get debug information */ +mlan_status woal_get_debug_info(moal_private * priv, t_u8 wait_option, + mlan_debug_info * debug_info); +/** Set debug information */ +mlan_status woal_set_debug_info(moal_private * priv, t_u8 wait_option, + mlan_debug_info * debug_info); +#endif +/** Disconnect */ +mlan_status woal_disconnect(moal_private * priv, t_u8 wait_option, t_u8 * mac); +/** associate */ +mlan_status woal_bss_start(moal_private * priv, t_u8 wait_option, + mlan_ssid_bssid * ssid_bssid); +/** Request firmware information */ +mlan_status woal_request_get_fw_info(moal_private * priv, t_u8 wait_option, + mlan_fw_info * fw_info); +/** Set/get Host Sleep parameters */ +mlan_status woal_set_get_hs_params(moal_private * priv, t_u16 action, + t_u8 wait_option, mlan_ds_hs_cfg * hscfg); +/** Cancel Host Sleep configuration */ +mlan_status woal_cancel_hs(moal_private * priv, t_u8 wait_option); +/** Enable Host Sleep configuration */ +int woal_enable_hs(moal_private * priv); +/** hs active timeout 2 second */ +#define HS_ACTIVE_TIMEOUT (2 * HZ) + +/** set deep sleep */ +int woal_set_deep_sleep(moal_private * priv, t_u8 wait_option, + BOOLEAN bdeep_sleep, t_u16 idletime); + +/** Get BSS information */ +mlan_status woal_get_bss_info(moal_private * priv, t_u8 wait_option, + mlan_bss_info * bss_info); +void woal_process_ioctl_resp(moal_private * priv, mlan_ioctl_req * req); +#ifdef STA_SUPPORT +void woal_send_disconnect_to_system(moal_private * priv); +void woal_send_mic_error_event(moal_private * priv, t_u32 event); +void woal_ioctl_get_bss_resp(moal_private * priv, mlan_ds_bss * bss); +void woal_ioctl_get_info_resp(moal_private * priv, mlan_ds_get_info * info); +/** Get signal information */ +mlan_status woal_get_signal_info(moal_private * priv, t_u8 wait_option, + mlan_ds_get_signal * signal); +#ifdef STA_WEXT +/** Get mode */ +t_u32 woal_get_mode(moal_private * priv, t_u8 wait_option); +/** Get data rates */ +mlan_status woal_get_data_rates(moal_private * priv, t_u8 wait_option, + moal_802_11_rates * m_rates); +void woal_send_iwevcustom_event(moal_private * priv, t_s8 * str); +/** Get statistics information */ +mlan_status woal_get_stats_info(moal_private * priv, t_u8 wait_option, + mlan_ds_get_stats * stats); +/** Get channel list */ +mlan_status woal_get_channel_list(moal_private * priv, t_u8 wait_option, + mlan_chan_list * chanlist); +#endif +/** Set/Get retry count */ +mlan_status woal_set_get_retry(moal_private * priv, t_u32 action, + t_u8 wait_option, int *value); +/** Set/Get RTS threshold */ +mlan_status woal_set_get_rts(moal_private * priv, t_u32 action, + t_u8 wait_option, int *value); +/** Set/Get fragment threshold */ +mlan_status woal_set_get_frag(moal_private * priv, t_u32 action, + t_u8 wait_option, int *value); +/** Set/Get generic element */ +mlan_status woal_set_get_gen_ie(moal_private * priv, t_u32 action, t_u8 * ie, + int *ie_len); +/** Set/Get TX power */ +mlan_status woal_set_get_tx_power(moal_private * priv, t_u32 action, + mlan_power_cfg_t * pwr); +/** Set/Get power IEEE management */ +mlan_status woal_set_get_power_mgmt(moal_private * priv, t_u32 action, + int *disabled, int type); +/** Get data rate */ +mlan_status woal_set_get_data_rate(moal_private * priv, t_u8 action, + mlan_rate_cfg_t * datarate); +/** Request a network scan */ +mlan_status woal_request_scan(moal_private * priv, t_u8 wait_option, + mlan_802_11_ssid * req_ssid); +/** Set radio on/off */ +int woal_set_radio(moal_private * priv, t_u8 option); +/** Set region code */ +mlan_status woal_set_region_code(moal_private * priv, char *region); +/** Set authentication mode */ +mlan_status woal_set_auth_mode(moal_private * priv, t_u8 wait_option, + t_u32 auth_mode); +/** Set encryption mode */ +mlan_status woal_set_encrypt_mode(moal_private * priv, t_u8 wait_option, + t_u32 encrypt_mode); +/** Enable wep key */ +mlan_status woal_enable_wep_key(moal_private * priv, t_u8 wait_option); +/** Set WPA enable */ +mlan_status woal_set_wpa_enable(moal_private * priv, t_u8 wait_option, + t_u32 enable); + +/** Find best network to connect */ +mlan_status woal_find_best_network(moal_private * priv, t_u8 wait_option, + mlan_ssid_bssid * ssid_bssid); +/** Set Ad-Hoc channel */ +mlan_status woal_change_adhoc_chan(moal_private * priv, int channel); + +/** Get scan table */ +mlan_status woal_get_scan_table(moal_private * priv, t_u8 wait_option, + mlan_scan_resp * scanresp); +/** Get authentication mode */ +mlan_status woal_get_auth_mode(moal_private * priv, t_u8 wait_option, + t_u32 * auth_mode); +/** Get encryption mode */ +mlan_status woal_get_encrypt_mode(moal_private * priv, t_u8 wait_option, + t_u32 * encrypt_mode); +/** Get WPA state */ +mlan_status woal_get_wpa_enable(moal_private * priv, t_u8 wait_option, + t_u32 * enable); +#endif /**STA_SUPPORT */ + +mlan_status woal_set_wapi_enable(moal_private * priv, t_u8 wait_option, + t_u32 enable); + +/** Initialize priv */ +void woal_init_priv(moal_private * priv, t_u8 wait_option); +/** Reset interface(s) */ +int woal_reset_intf(moal_private * priv, t_u8 wait_option, int all_intf); +/** common ioctl for uap, station */ +int woal_custom_ie_ioctl(struct net_device *dev, struct ifreq *req); +int woal_send_host_packet(struct net_device *dev, struct ifreq *req); +/** Private command ID to pass mgmt frame */ +#define WOAL_MGMT_FRAME_TX_IOCTL (SIOCDEVPRIVATE + 12) + +int woal_get_bss_type(struct net_device *dev, struct ifreq *req); +#if defined(STA_WEXT) || defined(UAP_WEXT) +int woal_host_command(moal_private * priv, struct iwreq *wrq); +#endif +#if defined(WIFI_DIRECT_SUPPORT) +#if defined(STA_SUPPORT) && defined(UAP_SUPPORT) +#if defined(STA_WEXT) || defined(UAP_WEXT) +int woal_set_get_bss_role(moal_private * priv, struct iwreq *wrq); +#endif +#endif +#endif +#if defined(WIFI_DIRECT_SUPPORT) || defined(UAP_SUPPORT) +/** hostcmd ioctl for uap, wifidirect */ +int woal_hostcmd_ioctl(struct net_device *dev, struct ifreq *req); +#endif + +#if defined(WIFI_DIRECT_SUPPORT) +mlan_status woal_set_remain_channel_ioctl(moal_private * priv, t_u8 wait_option, + mlan_ds_remain_chan * pchan); +mlan_status woal_cfg80211_wifi_direct_mode_cfg(moal_private * priv, + t_u16 action, t_u16 * mode); +#endif /* WIFI_DIRECT_SUPPORT */ + +#ifdef CONFIG_PROC_FS +/** Initialize proc fs */ +void woal_proc_init(moal_handle * handle); +/** Clean up proc fs */ +void woal_proc_exit(moal_handle * handle); +/** Create proc entry */ +void woal_create_proc_entry(moal_private * priv); +/** Remove proc entry */ +void woal_proc_remove(moal_private * priv); +/** string to number */ +int woal_string_to_number(char *s); +#endif + +#ifdef PROC_DEBUG +/** Create debug proc fs */ +void woal_debug_entry(moal_private * priv); +/** Remove debug proc fs */ +void woal_debug_remove(moal_private * priv); +#endif /* PROC_DEBUG */ + +/** check pm info */ +mlan_status woal_get_pm_info(moal_private * priv, mlan_ds_ps_info * pm_info); + +#ifdef REASSOCIATION +int woal_reassociation_thread(void *data); +void woal_reassoc_timer_func(void *context); +#endif /* REASSOCIATION */ + +t_void woal_main_work_queue(struct work_struct *work); + +int woal_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); +moal_private *woal_add_interface(moal_handle * handle, t_u8 bss_num, + t_u8 bss_type); +void woal_remove_interface(moal_handle * handle, t_u8 bss_index); +void woal_set_multicast_list(struct net_device *dev); +mlan_status woal_request_fw(moal_handle * handle); + +int woal_11h_channel_check_ioctl(moal_private * priv); +void woal_cancel_cac_block(moal_private * priv); +void woal_moal_debug_info(moal_private * priv, moal_handle * handle, u8 flag); + +#ifdef STA_SUPPORT +mlan_status woal_get_powermode(moal_private * priv, int *powermode); +mlan_status woal_set_scan_type(moal_private * priv, t_u32 scan_type); +mlan_status woal_set_powermode(moal_private * priv, char *powermode); +int woal_find_essid(moal_private * priv, mlan_ssid_bssid * ssid_bssid); +mlan_status woal_do_scan(moal_private * priv, wlan_user_scan_cfg * scan_cfg); +int woal_set_combo_scan(moal_private * priv, char *buf, int length); +mlan_status woal_get_band(moal_private * priv, int *band); +mlan_status woal_set_band(moal_private * priv, char *pband); +mlan_status woal_add_rxfilter(moal_private * priv, char *rxfilter); +mlan_status woal_remove_rxfilter(moal_private * priv, char *rxfilter); +mlan_status woal_set_qos_cfg(moal_private * priv, char *qos_cfg); +int woal_set_sleeppd(moal_private * priv, char *psleeppd); +mlan_status woal_set_rssi_low_threshold(moal_private * priv, char *rssi); +mlan_status woal_set_bg_scan(moal_private * priv, char *buf, int length); +mlan_status woal_stop_bg_scan(moal_private * priv); +void woal_reconfig_bgscan(moal_handle * handle); +#endif + +#endif /* _MOAL_MAIN_H */ diff --git a/drivers/net/wireless/sd8797/mlinux/moal_priv.c b/drivers/net/wireless/sd8797/mlinux/moal_priv.c new file mode 100644 index 000000000000..dc5cd82b7f44 --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/moal_priv.c @@ -0,0 +1,6596 @@ +/** @file moal_priv.c + * + * @brief This file contains standard ioctl functions + * + * Copyright (C) 2008-2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +/************************************************************************ +Change log: + 10/30/2008: initial version +************************************************************************/ + +#include "moal_main.h" +#include "moal_sdio.h" + +#if defined(STA_CFG80211) && defined(UAP_CFG80211) +#include "moal_cfg80211.h" +#endif +#include "moal_eth_ioctl.h" + +/******************************************************** + Local Variables +********************************************************/ +/** Bands supported in Infra mode */ +static t_u8 SupportedInfraBand[] = { + BAND_B, + BAND_B | BAND_G, BAND_G, + BAND_GN, BAND_B | BAND_G | BAND_GN, BAND_G | BAND_GN, + BAND_A, BAND_B | BAND_A, BAND_B | BAND_G | BAND_A, BAND_G | BAND_A, + BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN, + BAND_A | BAND_G | BAND_AN | BAND_GN, BAND_A | BAND_AN, +}; + +/** Bands supported in Ad-Hoc mode */ +static t_u8 SupportedAdhocBand[] = { + BAND_B, BAND_B | BAND_G, BAND_G, + BAND_GN, BAND_B | BAND_G | BAND_GN, BAND_G | BAND_GN, + BAND_A, + BAND_AN, BAND_A | BAND_AN, +}; + +/******************************************************** + Global Variables +********************************************************/ + +extern int cfg80211_wext; + +/******************************************************** + Local Functions +********************************************************/ + +/** + * @brief Copy Rates + * + * @param dest A pointer to destination buffer + * @param pos The position for copy + * @param src A pointer to source buffer + * @param len Length of the source buffer + * + * @return Number of rates copied + */ +static inline int +woal_copy_rates(t_u8 * dest, int pos, t_u8 * src, int len) +{ + int i; + + for (i = 0; i < len && src[i]; i++, pos++) { + if (pos >= MLAN_SUPPORTED_RATES) + break; + dest[pos] = src[i]; + } + return pos; +} + +/** + * @brief Performs warm reset + * + * @param priv A pointer to moal_private structure + * + * @return 0/MLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int +woal_warm_reset(moal_private * priv) +{ + int ret = 0; + int intf_num; + moal_handle *handle = priv->phandle; + mlan_ioctl_req *req = NULL; + mlan_ds_misc_cfg *misc = NULL; + + ENTER(); + + woal_cancel_cac_block(priv); + + /* Reset all interfaces */ + ret = woal_reset_intf(priv, MOAL_IOCTL_WAIT, MTRUE); + + /* Initialize private structures */ + for (intf_num = 0; intf_num < handle->priv_num; intf_num++) + woal_init_priv(handle->priv[intf_num], MOAL_IOCTL_WAIT); + + /* Restart the firmware */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req) { + misc = (mlan_ds_misc_cfg *) req->pbuf; + misc->sub_command = MLAN_OID_MISC_WARM_RESET; + req->req_id = MLAN_IOCTL_MISC_CFG; + req->action = MLAN_ACT_SET; + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + kfree(req); + goto done; + } + kfree(req); + } + + /* Enable interfaces */ + for (intf_num = 0; intf_num < handle->priv_num; intf_num++) { + netif_device_attach(handle->priv[intf_num]->netdev); + woal_start_queue(handle->priv[intf_num]->netdev); + } + + done: + LEAVE(); + return ret; +} + +/** + * @brief Get signal + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_get_signal(moal_private * priv, struct iwreq *wrq) +{ +/** Input data size */ +#define IN_DATA_SIZE 2 +/** Output data size */ +#define OUT_DATA_SIZE 12 + int ret = 0; + int in_data[IN_DATA_SIZE]; + int out_data[OUT_DATA_SIZE]; + mlan_ds_get_signal signal; + int data_length = 0; + int buflen = 0; + + ENTER(); + + memset(in_data, 0, sizeof(in_data)); + memset(out_data, 0, sizeof(out_data)); + buflen = MIN(wrq->u.data.length, IN_DATA_SIZE); + + if (priv->media_connected == MFALSE) { + PRINTM(MERROR, "Can not get RSSI in disconnected state\n"); + ret = -ENOTSUPP; + goto done; + } + + if (wrq->u.data.length) { + if (sizeof(int) * wrq->u.data.length > sizeof(in_data)) { + PRINTM(MERROR, "Too many arguments\n"); + ret = -EINVAL; + goto done; + } + if (copy_from_user(in_data, wrq->u.data.pointer, sizeof(int) * buflen)) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + } + + switch (wrq->u.data.length) { + case 0: /* No checking, get everything */ + break; + case 2: /* Check subtype range */ + if (in_data[1] < 1 || in_data[1] > 4) { + ret = -EINVAL; + goto done; + } + /* Fall through */ + case 1: /* Check type range */ + if (in_data[0] < 1 || in_data[0] > 3) { + ret = -EINVAL; + goto done; + } + break; + default: + ret = -EINVAL; + goto done; + } + + memset(&signal, 0, sizeof(mlan_ds_get_signal)); + if (MLAN_STATUS_SUCCESS != + woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) { + ret = -EFAULT; + goto done; + } + PRINTM(MINFO, "RSSI Beacon Last : %d\n", (int) signal.bcn_rssi_last); + PRINTM(MINFO, "RSSI Beacon Average: %d\n", (int) signal.bcn_rssi_avg); + PRINTM(MINFO, "RSSI Data Last : %d\n", (int) signal.data_rssi_last); + PRINTM(MINFO, "RSSI Data Average : %d\n", (int) signal.data_rssi_avg); + PRINTM(MINFO, "SNR Beacon Last : %d\n", (int) signal.bcn_snr_last); + PRINTM(MINFO, "SNR Beacon Average : %d\n", (int) signal.bcn_snr_avg); + PRINTM(MINFO, "SNR Data Last : %d\n", (int) signal.data_snr_last); + PRINTM(MINFO, "SNR Data Average : %d\n", (int) signal.data_snr_avg); + PRINTM(MINFO, "NF Beacon Last : %d\n", (int) signal.bcn_nf_last); + PRINTM(MINFO, "NF Beacon Average : %d\n", (int) signal.bcn_nf_avg); + PRINTM(MINFO, "NF Data Last : %d\n", (int) signal.data_nf_last); + PRINTM(MINFO, "NF Data Average : %d\n", (int) signal.data_nf_avg); + + /* Check type */ + switch (in_data[0]) { + case 0: /* Send everything */ + out_data[data_length++] = signal.bcn_rssi_last; + out_data[data_length++] = signal.bcn_rssi_avg; + out_data[data_length++] = signal.data_rssi_last; + out_data[data_length++] = signal.data_rssi_avg; + out_data[data_length++] = signal.bcn_snr_last; + out_data[data_length++] = signal.bcn_snr_avg; + out_data[data_length++] = signal.data_snr_last; + out_data[data_length++] = signal.data_snr_avg; + out_data[data_length++] = signal.bcn_nf_last; + out_data[data_length++] = signal.bcn_nf_avg; + out_data[data_length++] = signal.data_nf_last; + out_data[data_length++] = signal.data_nf_avg; + break; + case 1: /* RSSI */ + /* Check subtype */ + switch (in_data[1]) { + case 0: /* Everything */ + out_data[data_length++] = signal.bcn_rssi_last; + out_data[data_length++] = signal.bcn_rssi_avg; + out_data[data_length++] = signal.data_rssi_last; + out_data[data_length++] = signal.data_rssi_avg; + break; + case 1: /* bcn last */ + out_data[data_length++] = signal.bcn_rssi_last; + break; + case 2: /* bcn avg */ + out_data[data_length++] = signal.bcn_rssi_avg; + break; + case 3: /* data last */ + out_data[data_length++] = signal.data_rssi_last; + break; + case 4: /* data avg */ + out_data[data_length++] = signal.data_rssi_avg; + break; + default: + break; + } + break; + case 2: /* SNR */ + /* Check subtype */ + switch (in_data[1]) { + case 0: /* Everything */ + out_data[data_length++] = signal.bcn_snr_last; + out_data[data_length++] = signal.bcn_snr_avg; + out_data[data_length++] = signal.data_snr_last; + out_data[data_length++] = signal.data_snr_avg; + break; + case 1: /* bcn last */ + out_data[data_length++] = signal.bcn_snr_last; + break; + case 2: /* bcn avg */ + out_data[data_length++] = signal.bcn_snr_avg; + break; + case 3: /* data last */ + out_data[data_length++] = signal.data_snr_last; + break; + case 4: /* data avg */ + out_data[data_length++] = signal.data_snr_avg; + break; + default: + break; + } + break; + case 3: /* NF */ + /* Check subtype */ + switch (in_data[1]) { + case 0: /* Everything */ + out_data[data_length++] = signal.bcn_nf_last; + out_data[data_length++] = signal.bcn_nf_avg; + out_data[data_length++] = signal.data_nf_last; + out_data[data_length++] = signal.data_nf_avg; + break; + case 1: /* bcn last */ + out_data[data_length++] = signal.bcn_nf_last; + break; + case 2: /* bcn avg */ + out_data[data_length++] = signal.bcn_nf_avg; + break; + case 3: /* data last */ + out_data[data_length++] = signal.data_nf_last; + break; + case 4: /* data avg */ + out_data[data_length++] = signal.data_nf_avg; + break; + default: + break; + } + break; + default: + break; + } + + wrq->u.data.length = data_length; + if (copy_to_user(wrq->u.data.pointer, out_data, + wrq->u.data.length * sizeof(out_data[0]))) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + goto done; + } + done: + LEAVE(); + return ret; +} + +/** + * @brief Get Deep Sleep + * + * @param priv Pointer to the moal_private driver data struct + * @param deep_sleep Pointer to return deep_sleep setting + * + * @return 0 --success, otherwise fail + */ +static int +woal_get_deep_sleep(moal_private * priv, t_u32 * data) +{ + int ret = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_pm_cfg *pm = NULL; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg)); + if (req == NULL) { + LEAVE(); + return -ENOMEM; + } + pm = (mlan_ds_pm_cfg *) req->pbuf; + pm->sub_command = MLAN_OID_PM_CFG_DEEP_SLEEP; + req->req_id = MLAN_IOCTL_PM_CFG; + + req->action = MLAN_ACT_GET; + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + *data = pm->param.auto_deep_sleep.auto_ds; + *(data + 1) = pm->param.auto_deep_sleep.idletime; + + done: + if (req) + kfree(req); + + LEAVE(); + return ret; +} + +/** + * @brief Get/Set DeepSleep mode + * + * @param priv Pointer to the moal_private driver data struct + * @param wreq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_deep_sleep_ioctl(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + t_u32 deep_sleep = DEEP_SLEEP_OFF; + t_u32 data[2]; + t_u16 idletime = DEEP_SLEEP_IDLE_TIME; + + ENTER(); + + if (wrq->u.data.length == 1 || wrq->u.data.length == 2) { + if (copy_from_user + (&data, wrq->u.data.pointer, wrq->u.data.length * sizeof(int))) { + PRINTM(MERROR, "Copy from user failed\n"); + LEAVE(); + return -EFAULT; + } + deep_sleep = data[0]; + if (deep_sleep == DEEP_SLEEP_OFF) { + PRINTM(MINFO, "Exit Deep Sleep Mode\n"); + ret = woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MFALSE, 0); + if (ret != MLAN_STATUS_SUCCESS) { + LEAVE(); + return -EINVAL; + } + } else if (deep_sleep == DEEP_SLEEP_ON) { + PRINTM(MINFO, "Enter Deep Sleep Mode\n"); + if (wrq->u.data.length == 2) + idletime = data[1]; + else + idletime = 0; + ret = woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MTRUE, idletime); + if (ret != MLAN_STATUS_SUCCESS) { + LEAVE(); + return -EINVAL; + } + } else { + PRINTM(MERROR, "Unknown option = %u\n", deep_sleep); + LEAVE(); + return -EINVAL; + } + } else if (wrq->u.data.length > 2) { + PRINTM(MERROR, "Invalid number of arguments %d\n", wrq->u.data.length); + LEAVE(); + return -EINVAL; + } else { /* Display Deep Sleep settings */ + PRINTM(MINFO, "Get Deep Sleep Mode\n"); + if (MLAN_STATUS_SUCCESS != woal_get_deep_sleep(priv, data)) { + LEAVE(); + return -EFAULT; + } + if (data[0] == 0) + wrq->u.data.length = 1; + else + wrq->u.data.length = 2; + } + + /* Copy the Deep Sleep setting to user */ + if (copy_to_user + (wrq->u.data.pointer, data, wrq->u.data.length * sizeof(int))) { + PRINTM(MERROR, "Copy to user failed\n"); + LEAVE(); + return -EINVAL; + } + + LEAVE(); + return 0; +} + +/** + * @brief Set/Get Usr 11n configuration request + * + * @param priv Pointer to the moal_private driver data struct + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_11n_htcap_cfg(moal_private * priv, struct iwreq *wrq) +{ + int data[2]; + mlan_ioctl_req *req = NULL; + mlan_ds_11n_cfg *cfg_11n = NULL; + int ret = 0; + int data_length = wrq->u.data.length; + + ENTER(); + + if (data_length > 2) { + PRINTM(MERROR, "Invalid number of arguments\n"); + ret = -EINVAL; + goto done; + } + + if (((req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg))) == NULL)) { + ret = -ENOMEM; + goto done; + } + + cfg_11n = (mlan_ds_11n_cfg *) req->pbuf; + cfg_11n->sub_command = MLAN_OID_11N_HTCAP_CFG; + req->req_id = MLAN_IOCTL_11N_CFG; + + if (data_length == 0) { + /* Get 11n tx parameters from MLAN */ + req->action = MLAN_ACT_GET; + cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_BG; + } else { + if (copy_from_user + (data, wrq->u.data.pointer, data_length * sizeof(int))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + cfg_11n->param.htcap_cfg.htcap = data[0]; + PRINTM(MINFO, "SET: htcapinfo:0x%x\n", data[0]); + cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_BOTH; + if (data_length == 2) { + if (data[1] != BAND_SELECT_BG && + data[1] != BAND_SELECT_A && data[1] != BAND_SELECT_BOTH) { + PRINTM(MERROR, "Invalid band selection\n"); + ret = -EINVAL; + goto done; + } + cfg_11n->param.htcap_cfg.misc_cfg = data[1]; + PRINTM(MINFO, "SET: htcapinfo band:0x%x\n", data[1]); + } + /* Update 11n tx parameters in MLAN */ + req->action = MLAN_ACT_SET; + } + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + data[0] = cfg_11n->param.htcap_cfg.htcap; + + if (req->action == MLAN_ACT_GET) { + data_length = 1; + cfg_11n->param.htcap_cfg.htcap = 0; + cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_A; + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + if (cfg_11n->param.htcap_cfg.htcap != data[0]) { + data_length = 2; + data[1] = cfg_11n->param.htcap_cfg.htcap; + PRINTM(MINFO, "GET: htcapinfo for 2.4GHz:0x%x\n", data[0]); + PRINTM(MINFO, "GET: htcapinfo for 5GHz:0x%x\n", data[1]); + } else + PRINTM(MINFO, "GET: htcapinfo:0x%x\n", data[0]); + } + + if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + goto done; + } + + wrq->u.data.length = data_length; + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Enable/Disable amsdu_aggr_ctrl + * + * @param priv Pointer to the moal_private driver data struct + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_11n_amsdu_aggr_ctrl(moal_private * priv, struct iwreq *wrq) +{ + int data[2]; + mlan_ioctl_req *req = NULL; + mlan_ds_11n_cfg *cfg_11n = NULL; + int ret = 0; + + ENTER(); + + if ((wrq->u.data.length != 0) && (wrq->u.data.length != 1)) { + PRINTM(MERROR, "Invalid number of arguments\n"); + ret = -EINVAL; + goto done; + } + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + cfg_11n = (mlan_ds_11n_cfg *) req->pbuf; + cfg_11n->sub_command = MLAN_OID_11N_CFG_AMSDU_AGGR_CTRL; + req->req_id = MLAN_IOCTL_11N_CFG; + + if (wrq->u.data.length == 0) { + /* Get 11n tx parameters from MLAN */ + req->action = MLAN_ACT_GET; + } else if (wrq->u.data.length == 1) { + if (copy_from_user(data, wrq->u.data.pointer, + wrq->u.data.length * sizeof(int))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + cfg_11n->param.amsdu_aggr_ctrl.enable = data[0]; + /* Update 11n tx parameters in MLAN */ + req->action = MLAN_ACT_SET; + } + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + data[0] = cfg_11n->param.amsdu_aggr_ctrl.enable; + data[1] = cfg_11n->param.amsdu_aggr_ctrl.curr_buf_size; + + if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + goto done; + } + wrq->u.data.length = 2; + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Set/Get 11n configuration request + * + * @param priv Pointer to the moal_private driver data struct + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_11n_tx_cfg(moal_private * priv, struct iwreq *wrq) +{ + int data[2]; + mlan_ioctl_req *req = NULL; + mlan_ds_11n_cfg *cfg_11n = NULL; + int ret = 0; + int data_length = wrq->u.data.length; + + ENTER(); + + if (data_length > 2) { + PRINTM(MERROR, "Invalid number of arguments\n"); + ret = -EINVAL; + goto done; + } + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + cfg_11n = (mlan_ds_11n_cfg *) req->pbuf; + cfg_11n->sub_command = MLAN_OID_11N_CFG_TX; + req->req_id = MLAN_IOCTL_11N_CFG; + + if (wrq->u.data.length == 0) { + /* Get 11n tx parameters from MLAN */ + req->action = MLAN_ACT_GET; + cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BG; + } else { + if (copy_from_user + (data, wrq->u.data.pointer, data_length * sizeof(int))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + cfg_11n->param.tx_cfg.httxcap = data[0]; + PRINTM(MINFO, "SET: httxcap:0x%x\n", data[0]); + cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BOTH; + if (data_length == 2) { + if (data[1] != BAND_SELECT_BG && + data[1] != BAND_SELECT_A && data[1] != BAND_SELECT_BOTH) { + PRINTM(MERROR, "Invalid band selection\n"); + ret = -EINVAL; + goto done; + } + cfg_11n->param.tx_cfg.misc_cfg = data[1]; + PRINTM(MINFO, "SET: httxcap band:0x%x\n", data[1]); + } + /* Update 11n tx parameters in MLAN */ + req->action = MLAN_ACT_SET; + } + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + data[0] = cfg_11n->param.tx_cfg.httxcap; + + if (req->action == MLAN_ACT_GET) { + data_length = 1; + cfg_11n->param.tx_cfg.httxcap = 0; + cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_A; + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + if (cfg_11n->param.tx_cfg.httxcap != data[0]) { + data_length = 2; + data[1] = cfg_11n->param.tx_cfg.httxcap; + PRINTM(MINFO, "GET: httxcap for 2.4GHz:0x%x\n", data[0]); + PRINTM(MINFO, "GET: httxcap for 5GHz:0x%x\n", data[1]); + } else + PRINTM(MINFO, "GET: httxcap:0x%x\n", data[0]); + } + + if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + goto done; + } + wrq->u.data.length = data_length; + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Enable/Disable TX Aggregation + * + * @param priv Pointer to the moal_private driver data struct + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_11n_prio_tbl(moal_private * priv, struct iwreq *wrq) +{ + int data[MAX_NUM_TID * 2], i, j; + mlan_ioctl_req *req = NULL; + mlan_ds_11n_cfg *cfg_11n = NULL; + int ret = 0; + + ENTER(); + + if ((wrq->u.data.pointer == NULL)) { + LEAVE(); + return -EINVAL; + } + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); + if (req == NULL) { + LEAVE(); + return -ENOMEM; + } + cfg_11n = (mlan_ds_11n_cfg *) req->pbuf; + cfg_11n->sub_command = MLAN_OID_11N_CFG_AGGR_PRIO_TBL; + req->req_id = MLAN_IOCTL_11N_CFG; + + if (wrq->u.data.length == 0) { + /* Get aggr priority table from MLAN */ + req->action = MLAN_ACT_GET; + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto error; + } + wrq->u.data.length = MAX_NUM_TID * 2; + for (i = 0, j = 0; i < (wrq->u.data.length); i = i + 2, ++j) { + data[i] = cfg_11n->param.aggr_prio_tbl.ampdu[j]; + data[i + 1] = cfg_11n->param.aggr_prio_tbl.amsdu[j]; + } + + if (copy_to_user(wrq->u.data.pointer, data, + sizeof(int) * wrq->u.data.length)) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + goto error; + } + } else if (wrq->u.data.length == 16) { + if (copy_from_user(data, wrq->u.data.pointer, + sizeof(int) * wrq->u.data.length)) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto error; + } + for (i = 0, j = 0; i < (wrq->u.data.length); i = i + 2, ++j) { + if ((data[i] > 7 && data[i] != 0xff) || + (data[i + 1] > 7 && data[i + 1] != 0xff)) { + PRINTM(MERROR, "Invalid priority, valid value 0-7 or 0xff.\n"); + ret = -EFAULT; + goto error; + } + cfg_11n->param.aggr_prio_tbl.ampdu[j] = data[i]; + cfg_11n->param.aggr_prio_tbl.amsdu[j] = data[i + 1]; + } + + /* Update aggr priority table in MLAN */ + req->action = MLAN_ACT_SET; + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto error; + } + } else { + PRINTM(MERROR, "Invalid number of arguments\n"); + ret = -EINVAL; + goto error; + } + + error: + if (req) + kfree(req); + + LEAVE(); + return ret; +} + +/** + * @brief Set/Get add BA Reject parameters + * + * @param priv Pointer to the moal_private driver data struct + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_addba_reject(moal_private * priv, struct iwreq *wrq) +{ + int data[MAX_NUM_TID], ret = 0, i; + mlan_ioctl_req *req = NULL; + mlan_ds_11n_cfg *cfg_11n = NULL; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); + if (req == NULL) { + LEAVE(); + return -ENOMEM; + } + cfg_11n = (mlan_ds_11n_cfg *) req->pbuf; + cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_REJECT; + req->req_id = MLAN_IOCTL_11N_CFG; + + if (wrq->u.data.length == 0) { + PRINTM(MERROR, "Addba reject moal\n"); + /* Get aggr priority table from MLAN */ + req->action = MLAN_ACT_GET; + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, + MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto error; + } + + wrq->u.data.length = MAX_NUM_TID; + for (i = 0; i < (wrq->u.data.length); ++i) { + data[i] = cfg_11n->param.addba_reject[i]; + } + + if (copy_to_user(wrq->u.data.pointer, data, + sizeof(int) * wrq->u.data.length)) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + goto error; + } + } else if (wrq->u.data.length == 8) { + if (copy_from_user(data, wrq->u.data.pointer, + sizeof(int) * wrq->u.data.length)) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto error; + } + for (i = 0; i < (wrq->u.data.length); ++i) { + if (data[i] != 0 && data[i] != 1) { + PRINTM(MERROR, "addba reject only takes argument as 0 or 1\n"); + ret = -EFAULT; + goto error; + } + cfg_11n->param.addba_reject[i] = data[i]; + } + + /* Update aggr priority table in MLAN */ + req->action = MLAN_ACT_SET; + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, + MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto error; + } + } else { + PRINTM(MERROR, "Invalid number of arguments\n"); + ret = -EINVAL; + goto error; + } + error: + if (req) + kfree(req); + + LEAVE(); + return ret; +} + +/** + * @brief Set/Get add BA parameters + * + * @param priv Pointer to the moal_private driver data struct + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_addba_para_updt(moal_private * priv, struct iwreq *wrq) +{ + int data[5], ret = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_11n_cfg *cfg_11n = NULL; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); + if (req == NULL) { + LEAVE(); + return -ENOMEM; + } + cfg_11n = (mlan_ds_11n_cfg *) req->pbuf; + cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_PARAM; + req->req_id = MLAN_IOCTL_11N_CFG; + + if (wrq->u.data.length == 0) { + /* Get Add BA parameters from MLAN */ + req->action = MLAN_ACT_GET; + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto error; + } + data[0] = cfg_11n->param.addba_param.timeout; + data[1] = cfg_11n->param.addba_param.txwinsize; + data[2] = cfg_11n->param.addba_param.rxwinsize; + data[3] = cfg_11n->param.addba_param.txamsdu; + data[4] = cfg_11n->param.addba_param.rxamsdu; + PRINTM(MINFO, + "GET: timeout:%d txwinsize:%d rxwinsize:%d txamsdu=%d, rxamsdu=%d\n", + data[0], data[1], data[2], data[3], data[4]); + wrq->u.data.length = 5; + if (copy_to_user(wrq->u.data.pointer, data, + wrq->u.data.length * sizeof(int))) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + goto error; + } + } else if (wrq->u.data.length == 5) { + if (copy_from_user + (data, wrq->u.data.pointer, wrq->u.data.length * sizeof(int))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto error; + } + if (data[0] < 0 || data[0] > MLAN_DEFAULT_BLOCK_ACK_TIMEOUT) { + PRINTM(MERROR, "Incorrect addba timeout value.\n"); + ret = -EFAULT; + goto error; + } + if (data[1] <= 0 || data[1] > MLAN_AMPDU_MAX_TXWINSIZE || data[2] <= 0 + || data[2] > MLAN_AMPDU_MAX_RXWINSIZE) { + PRINTM(MERROR, "Incorrect Tx/Rx window size.\n"); + ret = -EFAULT; + goto error; + } + cfg_11n->param.addba_param.timeout = data[0]; + cfg_11n->param.addba_param.txwinsize = data[1]; + cfg_11n->param.addba_param.rxwinsize = data[2]; + if (data[3] < 0 || data[3] > 1 || data[4] < 0 || data[4] > 1) { + PRINTM(MERROR, "Incorrect Tx/Rx amsdu.\n"); + ret = -EFAULT; + goto error; + } + cfg_11n->param.addba_param.txamsdu = data[3]; + cfg_11n->param.addba_param.rxamsdu = data[4]; + PRINTM(MINFO, + "SET: timeout:%d txwinsize:%d rxwinsize:%d txamsdu=%d rxamsdu=%d\n", + data[0], data[1], data[2], data[3], data[4]); + /* Update Add BA parameters in MLAN */ + req->action = MLAN_ACT_SET; + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = MLAN_STATUS_FAILURE; + goto error; + } + } else { + PRINTM(MERROR, "Invalid number of arguments\n"); + ret = -EINVAL; + goto error; + } + + error: + if (req) + kfree(req); + + LEAVE(); + return ret; +} + +/** + * @brief Set/Get Transmit buffer size + * + * @param priv Pointer to the moal_private driver data struct + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_txbuf_cfg(moal_private * priv, struct iwreq *wrq) +{ + int buf_size; + mlan_ioctl_req *req = NULL; + mlan_ds_11n_cfg *cfg_11n = NULL; + int ret = 0; + + ENTER(); + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + cfg_11n = (mlan_ds_11n_cfg *) req->pbuf; + cfg_11n->sub_command = MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE; + req->req_id = MLAN_IOCTL_11N_CFG; + + if (wrq->u.data.length == 0) { + /* Get Tx buffer size from MLAN */ + req->action = MLAN_ACT_GET; + } else { + ret = -EINVAL; + PRINTM(MERROR, + "Don't support set Tx buffer size after driver loaded!\n"); + goto done; + } + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + buf_size = cfg_11n->param.tx_buf_size; + if (copy_to_user(wrq->u.data.pointer, &buf_size, sizeof(buf_size))) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + goto done; + } + wrq->u.data.length = 1; + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Set/Get Host Sleep configuration + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * @param invoke_hostcmd MTRUE --invoke HostCmd, otherwise MFALSE + * + * @return 0 --success, otherwise fail + */ +static int +woal_hs_cfg(moal_private * priv, struct iwreq *wrq, BOOLEAN invoke_hostcmd) +{ + int data[3]; + int ret = 0; + mlan_ds_hs_cfg hscfg; + t_u16 action; + mlan_bss_info bss_info; + int data_length = wrq->u.data.length; + + ENTER(); + + memset(data, 0, sizeof(data)); + memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg)); + + if (data_length == 0) { + action = MLAN_ACT_GET; + } else { + action = MLAN_ACT_SET; + if (data_length >= 1 && data_length <= 3) { + if (copy_from_user + (data, wrq->u.data.pointer, sizeof(int) * data_length)) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + } else { + PRINTM(MERROR, "Invalid arguments\n"); + ret = -EINVAL; + goto done; + } + } + + /* HS config is blocked if HS is already activated */ + if (data_length && + (data[0] != HOST_SLEEP_CFG_CANCEL || invoke_hostcmd == MFALSE)) { + memset(&bss_info, 0, sizeof(bss_info)); + woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info); + if (bss_info.is_hs_configured) { + PRINTM(MERROR, "HS already configured\n"); + ret = -EFAULT; + goto done; + } + } + + /* Do a GET first if some arguments are not provided */ + if (data_length >= 1 && data_length < 3) { + woal_set_get_hs_params(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT, &hscfg); + } + + if (data_length) + hscfg.conditions = data[0]; + if (data_length >= 2) + hscfg.gpio = data[1]; + if (data_length == 3) + hscfg.gap = data[2]; + + if ((invoke_hostcmd == MTRUE) && (action == MLAN_ACT_SET)) { + /* Need to issue an extra IOCTL first to set up parameters */ + hscfg.is_invoke_hostcmd = MFALSE; + if (MLAN_STATUS_SUCCESS != + woal_set_get_hs_params(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, + &hscfg)) { + ret = -EFAULT; + goto done; + } + } + hscfg.is_invoke_hostcmd = invoke_hostcmd; + if (MLAN_STATUS_SUCCESS != + woal_set_get_hs_params(priv, action, MOAL_IOCTL_WAIT, &hscfg)) { + ret = -EFAULT; + goto done; + } + + if (action == MLAN_ACT_GET) { + data[0] = hscfg.conditions; + data[1] = hscfg.gpio; + data[2] = hscfg.gap; + wrq->u.data.length = 3; + if (copy_to_user + (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + goto done; + } + } + done: + LEAVE(); + return ret; +} + +/** + * @brief Set Host Sleep parameters + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_hs_setpara(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + int data_length = wrq->u.data.length; + + ENTER(); + + if (data_length >= 1 && data_length <= 3) { + ret = woal_hs_cfg(priv, wrq, MFALSE); + goto done; + } else { + PRINTM(MERROR, "Invalid arguments\n"); + ret = -EINVAL; + goto done; + } + done: + LEAVE(); + return ret; +} + +/** + * @brief Get/Set inactivity timeout extend + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_inactivity_timeout_ext(moal_private * priv, struct iwreq *wrq) +{ + int data[4]; + int ret = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_pm_cfg *pmcfg = NULL; + pmlan_ds_inactivity_to inac_to = NULL; + int data_length = wrq->u.data.length; + + ENTER(); + + memset(data, 0, sizeof(data)); + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + pmcfg = (mlan_ds_pm_cfg *) req->pbuf; + inac_to = &pmcfg->param.inactivity_to; + pmcfg->sub_command = MLAN_OID_PM_CFG_INACTIVITY_TO; + req->req_id = MLAN_IOCTL_PM_CFG; + + if ((data_length != 0 && data_length != 3 && data_length != 4) || + sizeof(int) * data_length > sizeof(data)) { + PRINTM(MERROR, "Invalid number of parameters\n"); + ret = -EINVAL; + goto done; + } + + req->action = MLAN_ACT_GET; + if (data_length) { + if (copy_from_user + (data, wrq->u.data.pointer, sizeof(int) * data_length)) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + req->action = MLAN_ACT_SET; + inac_to->timeout_unit = data[0]; + inac_to->unicast_timeout = data[1]; + inac_to->mcast_timeout = data[2]; + inac_to->ps_entry_timeout = data[3]; + } + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + /* Copy back current values regardless of GET/SET */ + data[0] = inac_to->timeout_unit; + data[1] = inac_to->unicast_timeout; + data[2] = inac_to->mcast_timeout; + data[3] = inac_to->ps_entry_timeout; + + if (req->action == MLAN_ACT_GET) { + wrq->u.data.length = 4; + if (copy_to_user + (wrq->u.data.pointer, data, wrq->u.data.length * sizeof(int))) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + goto done; + } + } + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Set/Get system clock + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_ecl_sys_clock(moal_private * priv, struct iwreq *wrq) +{ + int data[64]; + int ret = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_misc_cfg *cfg = NULL; + int data_length = wrq->u.data.length; + int i = 0; + + ENTER(); + + memset(data, 0, sizeof(data)); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + cfg = (mlan_ds_misc_cfg *) req->pbuf; + cfg->sub_command = MLAN_OID_MISC_SYS_CLOCK; + req->req_id = MLAN_IOCTL_MISC_CFG; + + if (!data_length) + req->action = MLAN_ACT_GET; + else if (data_length <= MLAN_MAX_CLK_NUM) { + req->action = MLAN_ACT_SET; + if (copy_from_user + (data, wrq->u.data.pointer, sizeof(int) * data_length)) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + } else { + PRINTM(MERROR, "Invalid arguments\n"); + ret = -EINVAL; + goto done; + } + + if (req->action == MLAN_ACT_GET) { + /* Get configurable clocks */ + cfg->param.sys_clock.sys_clk_type = MLAN_CLK_CONFIGURABLE; + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + /* Current system clock */ + data[0] = (int) cfg->param.sys_clock.cur_sys_clk; + wrq->u.data.length = 1; + + data_length = MIN(cfg->param.sys_clock.sys_clk_num, MLAN_MAX_CLK_NUM); + + /* Configurable clocks */ + for (i = 0; i < data_length; i++) { + data[i + wrq->u.data.length] = + (int) cfg->param.sys_clock.sys_clk[i]; + } + wrq->u.data.length += data_length; + + /* Get supported clocks */ + cfg->param.sys_clock.sys_clk_type = MLAN_CLK_SUPPORTED; + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + data_length = MIN(cfg->param.sys_clock.sys_clk_num, MLAN_MAX_CLK_NUM); + + /* Supported clocks */ + for (i = 0; i < data_length; i++) { + data[i + wrq->u.data.length] = + (int) cfg->param.sys_clock.sys_clk[i]; + } + + wrq->u.data.length += data_length; + + if (copy_to_user + (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + goto done; + } + } else { + /* Set configurable clocks */ + cfg->param.sys_clock.sys_clk_type = MLAN_CLK_CONFIGURABLE; + cfg->param.sys_clock.sys_clk_num = MIN(MLAN_MAX_CLK_NUM, data_length); + for (i = 0; i < cfg->param.sys_clock.sys_clk_num; i++) { + cfg->param.sys_clock.sys_clk[i] = (t_u16) data[i]; + } + + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + } + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Set/Get Band and Adhoc-band setting + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_band_cfg(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + unsigned int i; + int data[4]; + int user_data_len = wrq->u.data.length; + t_u32 infra_band = 0; + t_u32 adhoc_band = 0; + t_u32 adhoc_channel = 0; + t_u32 adhoc_chan_bandwidth = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_radio_cfg *radio_cfg = NULL; + + ENTER(); + + if (sizeof(int) * user_data_len > sizeof(data)) { + PRINTM(MERROR, "Too many arguments\n"); + LEAVE(); + return -EINVAL; + } + + if (user_data_len > 0) { + if (priv->media_connected == MTRUE) { + LEAVE(); + return -EOPNOTSUPP; + } + } + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto error; + } + radio_cfg = (mlan_ds_radio_cfg *) req->pbuf; + radio_cfg->sub_command = MLAN_OID_BAND_CFG; + req->req_id = MLAN_IOCTL_RADIO_CFG; + + if (wrq->u.data.length == 0) { + /* Get config_bands, adhoc_start_band and adhoc_channel values from + MLAN */ + req->action = MLAN_ACT_GET; + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto error; + } + data[0] = radio_cfg->param.band_cfg.config_bands; /* Infra Band */ + data[1] = radio_cfg->param.band_cfg.adhoc_start_band; /* Adhoc Band */ + data[2] = radio_cfg->param.band_cfg.adhoc_channel; /* Adhoc + Channel */ + wrq->u.data.length = 3; + if (radio_cfg->param.band_cfg.adhoc_start_band & BAND_GN + || radio_cfg->param.band_cfg.adhoc_start_band & BAND_AN) { + data[3] = radio_cfg->param.band_cfg.sec_chan_offset; + wrq->u.data.length = 4; + } + + if (copy_to_user + (wrq->u.data.pointer, data, sizeof(int) * wrq->u.data.length)) { + ret = -EFAULT; + goto error; + } + } else { + if (copy_from_user + (data, wrq->u.data.pointer, sizeof(int) * user_data_len)) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto error; + } + + /* To support only */ + infra_band = data[0]; + for (i = 0; i < sizeof(SupportedInfraBand); i++) + if (infra_band == SupportedInfraBand[i]) + break; + if (i == sizeof(SupportedInfraBand)) { + ret = -EINVAL; + goto error; + } + + /* Set Adhoc band */ + if (user_data_len >= 2) { + adhoc_band = data[1]; + for (i = 0; i < sizeof(SupportedAdhocBand); i++) + if (adhoc_band == SupportedAdhocBand[i]) + break; + if (i == sizeof(SupportedAdhocBand)) { + ret = -EINVAL; + goto error; + } + } + + /* Set Adhoc channel */ + if (user_data_len >= 3) { + adhoc_channel = data[2]; + if (adhoc_channel == 0) { + /* Check if specified adhoc channel is non-zero */ + ret = -EINVAL; + goto error; + } + } + if (user_data_len == 4) { + if (!(adhoc_band & (BAND_GN | BAND_AN))) { + PRINTM(MERROR, + "11n is not enabled for adhoc, can not set HT/VHT channel bandwidth\n"); + ret = -EINVAL; + goto error; + } + adhoc_chan_bandwidth = data[3]; + if ((adhoc_chan_bandwidth != CHANNEL_BW_20MHZ) && + (adhoc_chan_bandwidth != CHANNEL_BW_40MHZ_ABOVE) && + (adhoc_chan_bandwidth != CHANNEL_BW_40MHZ_BELOW) + ) { + PRINTM(MERROR, + "Invalid secondary channel bandwidth, only allowed 0, 1, 3 or 4\n"); + ret = -EINVAL; + goto error; + } + } + /* Set config_bands and adhoc_start_band values to MLAN */ + req->action = MLAN_ACT_SET; + radio_cfg->param.band_cfg.config_bands = infra_band; + radio_cfg->param.band_cfg.adhoc_start_band = adhoc_band; + radio_cfg->param.band_cfg.adhoc_channel = adhoc_channel; + radio_cfg->param.band_cfg.sec_chan_offset = adhoc_chan_bandwidth; + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto error; + } + } + + error: + if (req) + kfree(req); + + LEAVE(); + return ret; +} + +/** + * @brief Read/Write adapter registers value + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_reg_read_write(moal_private * priv, struct iwreq *wrq) +{ + int data[3]; + int ret = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_reg_mem *reg = NULL; + int data_length = wrq->u.data.length; + + ENTER(); + + memset(data, 0, sizeof(data)); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + reg = (mlan_ds_reg_mem *) req->pbuf; + reg->sub_command = MLAN_OID_REG_RW; + req->req_id = MLAN_IOCTL_REG_MEM; + + if (data_length == 2) { + req->action = MLAN_ACT_GET; + } else if (data_length == 3) { + req->action = MLAN_ACT_SET; + } else { + ret = -EINVAL; + goto done; + } + if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * data_length)) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + reg->param.reg_rw.type = (t_u32) data[0]; + reg->param.reg_rw.offset = (t_u32) data[1]; + if (data_length == 3) + reg->param.reg_rw.value = (t_u32) data[2]; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + if (req->action == MLAN_ACT_GET) { + if (copy_to_user + (wrq->u.data.pointer, ®->param.reg_rw.value, sizeof(int))) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + goto done; + } + wrq->u.data.length = 1; + } + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Read the EEPROM contents of the card + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_read_eeprom(moal_private * priv, struct iwreq *wrq) +{ + int data[2]; + int ret = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_reg_mem *reg = NULL; + int data_length = wrq->u.data.length; + + ENTER(); + + memset(data, 0, sizeof(data)); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + reg = (mlan_ds_reg_mem *) req->pbuf; + reg->sub_command = MLAN_OID_EEPROM_RD; + req->req_id = MLAN_IOCTL_REG_MEM; + + if (data_length == 2) { + req->action = MLAN_ACT_GET; + } else { + ret = -EINVAL; + goto done; + } + if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * data_length)) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + reg->param.rd_eeprom.offset = (t_u16) data[0]; + reg->param.rd_eeprom.byte_count = (t_u16) data[1]; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + if (req->action == MLAN_ACT_GET) { + wrq->u.data.length = reg->param.rd_eeprom.byte_count; + if (copy_to_user + (wrq->u.data.pointer, reg->param.rd_eeprom.value, + MIN(wrq->u.data.length, MAX_EEPROM_DATA))) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + goto done; + } + } + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Read/Write device memory value + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_mem_read_write(moal_private * priv, struct iwreq *wrq) +{ + t_u32 data[2]; + int ret = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_reg_mem *reg_mem = NULL; + int data_length = wrq->u.data.length; + + ENTER(); + + memset(data, 0, sizeof(data)); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + reg_mem = (mlan_ds_reg_mem *) req->pbuf; + reg_mem->sub_command = MLAN_OID_MEM_RW; + req->req_id = MLAN_IOCTL_REG_MEM; + + if (data_length == 1) { + PRINTM(MINFO, "MEM_RW: GET\n"); + req->action = MLAN_ACT_GET; + } else if (data_length == 2) { + PRINTM(MINFO, "MEM_RW: SET\n"); + req->action = MLAN_ACT_SET; + } else { + ret = -EINVAL; + goto done; + } + if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * data_length)) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + reg_mem->param.mem_rw.addr = (t_u32) data[0]; + if (data_length == 2) + reg_mem->param.mem_rw.value = (t_u32) data[1]; + + PRINTM(MINFO, "MEM_RW: Addr=0x%x, Value=0x%x\n", + (int) reg_mem->param.mem_rw.addr, (int) reg_mem->param.mem_rw.value); + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + if (req->action == MLAN_ACT_GET) { + if (copy_to_user + (wrq->u.data.pointer, ®_mem->param.mem_rw.value, sizeof(int))) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + goto done; + } + wrq->u.data.length = 1; + } + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Get LOG + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_get_log(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + mlan_ds_get_stats stats; + char *buf = NULL; + + ENTER(); + + PRINTM(MINFO, " GET STATS\n"); + if (!(buf = kmalloc(GETLOG_BUFSIZE, GFP_KERNEL))) { + PRINTM(MERROR, "kmalloc failed!\n"); + ret = -ENOMEM; + goto done; + } + + memset(&stats, 0, sizeof(mlan_ds_get_stats)); + if (MLAN_STATUS_SUCCESS != + woal_get_stats_info(priv, MOAL_IOCTL_WAIT, &stats)) { + ret = -EFAULT; + goto done; + } + + if (wrq->u.data.pointer) { + sprintf(buf, "\n" + "mcasttxframe %u\n" + "failed %u\n" + "retry %u\n" + "multiretry %u\n" + "framedup %u\n" + "rtssuccess %u\n" + "rtsfailure %u\n" + "ackfailure %u\n" + "rxfrag %u\n" + "mcastrxframe %u\n" + "fcserror %u\n" + "txframe %u\n" + "wepicverrcnt-1 %u\n" + "wepicverrcnt-2 %u\n" + "wepicverrcnt-3 %u\n" + "wepicverrcnt-4 %u\n", + stats.mcast_tx_frame, + stats.failed, + stats.retry, + stats.multi_retry, + stats.frame_dup, + stats.rts_success, + stats.rts_failure, + stats.ack_failure, + stats.rx_frag, + stats.mcast_rx_frame, + stats.fcs_error, + stats.tx_frame, + stats.wep_icv_error[0], + stats.wep_icv_error[1], + stats.wep_icv_error[2], stats.wep_icv_error[3]); + wrq->u.data.length = strlen(buf) + 1; + if (copy_to_user(wrq->u.data.pointer, buf, wrq->u.data.length)) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + } + } + done: + if (buf) + kfree(buf); + LEAVE(); + return ret; +} + +/** + * @brief Deauthenticate + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_deauth(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + struct sockaddr saddr; + + ENTER(); + if (wrq->u.data.length) { + /* Deauth mentioned BSSID */ + if (copy_from_user(&saddr, wrq->u.data.pointer, sizeof(saddr))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + if (MLAN_STATUS_SUCCESS != + woal_disconnect(priv, MOAL_IOCTL_WAIT, (t_u8 *) saddr.sa_data)) { + ret = -EFAULT; + goto done; + } + } else { + if (MLAN_STATUS_SUCCESS != woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL)) + ret = -EFAULT; + } + done: + LEAVE(); + return ret; +} + +/** + * @brief Set/Get TX power configurations + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_tx_power_cfg(moal_private * priv, struct iwreq *wrq) +{ + int data[5], user_data_len; + int ret = 0; + mlan_bss_info bss_info; + mlan_ds_power_cfg *pcfg = NULL; + mlan_ioctl_req *req = NULL; + ENTER(); + + memset(&bss_info, 0, sizeof(bss_info)); + woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info); + + memset(data, 0, sizeof(data)); + user_data_len = wrq->u.data.length; + + if (user_data_len) { + if (sizeof(int) * user_data_len > sizeof(data)) { + PRINTM(MERROR, "Too many arguments\n"); + ret = -EINVAL; + goto done; + } + if (copy_from_user + (data, wrq->u.data.pointer, sizeof(int) * user_data_len)) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + switch (user_data_len) { + case 1: + if (data[0] != 0xFF) + ret = -EINVAL; + break; + case 2: + case 4: + if (data[0] == 0xFF) { + ret = -EINVAL; + break; + } + if ((unsigned int) data[1] < bss_info.min_power_level) { + PRINTM(MERROR, + "The set powercfg rate value %d dBm is out of range (%d dBm-%d dBm)!\n", + data[1], (int) bss_info.min_power_level, + (int) bss_info.max_power_level); + ret = -EINVAL; + break; + } + if (user_data_len == 4) { + if (data[1] > data[2]) { + PRINTM(MERROR, "Min power should be less than maximum!\n"); + ret = -EINVAL; + break; + } + if (data[3] < 0) { + PRINTM(MERROR, "Step should not less than 0!\n"); + ret = -EINVAL; + break; + } + if ((unsigned int) data[2] > bss_info.max_power_level) { + PRINTM(MERROR, + "The set powercfg rate value %d dBm is out of range (%d dBm-%d dBm)!\n", + data[2], (int) bss_info.min_power_level, + (int) bss_info.max_power_level); + ret = -EINVAL; + break; + } + if (data[3] > data[2] - data[1]) { + PRINTM(MERROR, + "Step should not greater than power difference!\n"); + ret = -EINVAL; + break; + } + } + break; + default: + ret = -EINVAL; + break; + } + if (ret) + goto done; + } + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_power_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + pcfg = (mlan_ds_power_cfg *) req->pbuf; + pcfg->sub_command = MLAN_OID_POWER_CFG_EXT; + req->req_id = MLAN_IOCTL_POWER_CFG; + if (!user_data_len) + req->action = MLAN_ACT_GET; + else { + req->action = MLAN_ACT_SET; + pcfg->param.power_ext.len = user_data_len; + memcpy((t_u8 *) & pcfg->param.power_ext.power_data, (t_u8 *) data, + sizeof(data)); + } + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + if (!user_data_len) { + if (copy_to_user + (wrq->u.data.pointer, (t_u8 *) & pcfg->param.power_ext.power_data, + sizeof(int) * pcfg->param.power_ext.len)) { + ret = -EFAULT; + goto done; + } + wrq->u.data.length = pcfg->param.power_ext.len; + } + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Get Tx/Rx data rates + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_get_txrx_rate(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + mlan_ds_rate *rate = NULL; + mlan_ioctl_req *req = NULL; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + rate = (mlan_ds_rate *) req->pbuf; + rate->sub_command = MLAN_OID_GET_DATA_RATE; + req->req_id = MLAN_IOCTL_RATE; + req->action = MLAN_ACT_GET; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + if (copy_to_user + (wrq->u.data.pointer, (t_u8 *) & rate->param.data_rate, + sizeof(int) * 2)) { + ret = -EFAULT; + goto done; + } + wrq->u.data.length = 2; + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Turn on/off the sdio clock + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0/MLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int +woal_sdio_clock_ioctl(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + int data = 2; + /* Initialize the clock state as on */ + static int clock_state = 1; + + ENTER(); + + if (wrq->u.data.length) { + if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + } else { + wrq->u.data.length = sizeof(clock_state) / sizeof(int); + if (copy_to_user(wrq->u.data.pointer, &clock_state, sizeof(int))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + goto done; + } + switch (data) { + case CMD_DISABLED: + PRINTM(MINFO, "SDIO clock is turned off\n"); + ret = woal_sdio_set_bus_clock(priv->phandle, MFALSE); + clock_state = data; + break; + case CMD_ENABLED: + PRINTM(MINFO, "SDIO clock is turned on\n"); + ret = woal_sdio_set_bus_clock(priv->phandle, MTRUE); + clock_state = data; + break; + default: + ret = -EINVAL; + PRINTM(MINFO, "sdioclock: wrong parameter\n"); + break; + } + done: + LEAVE(); + return ret; +} + +/** + * @brief Set/Get beacon interval + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_beacon_interval(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + mlan_ds_bss *bss = NULL; + mlan_ioctl_req *req = NULL; + int bcn = 0; + + ENTER(); + + if (wrq->u.data.length) { + if (copy_from_user(&bcn, wrq->u.data.pointer, sizeof(int))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + if ((bcn < MLAN_MIN_BEACON_INTERVAL) || + (bcn > MLAN_MAX_BEACON_INTERVAL)) { + ret = -EINVAL; + goto done; + } + } + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + bss = (mlan_ds_bss *) req->pbuf; + bss->sub_command = MLAN_OID_IBSS_BCN_INTERVAL; + req->req_id = MLAN_IOCTL_BSS; + if (!wrq->u.data.length) + req->action = MLAN_ACT_GET; + else { + req->action = MLAN_ACT_SET; + bss->param.bcn_interval = bcn; + } + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + if (copy_to_user + (wrq->u.data.pointer, (t_u8 *) & bss->param.bcn_interval, + sizeof(int))) { + ret = -EFAULT; + goto done; + } + wrq->u.data.length = 1; + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Set/Get ATIM window + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_atim_window(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + mlan_ds_bss *bss = NULL; + mlan_ioctl_req *req = NULL; + int atim = 0; + + ENTER(); + + if (wrq->u.data.length) { + if (copy_from_user(&atim, wrq->u.data.pointer, sizeof(int))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + if ((atim < 0) || (atim > MLAN_MAX_ATIM_WINDOW)) { + ret = -EINVAL; + goto done; + } + } + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + bss = (mlan_ds_bss *) req->pbuf; + bss->sub_command = MLAN_OID_IBSS_ATIM_WINDOW; + req->req_id = MLAN_IOCTL_BSS; + if (!wrq->u.data.length) + req->action = MLAN_ACT_GET; + else { + req->action = MLAN_ACT_SET; + bss->param.atim_window = atim; + } + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + if (copy_to_user + (wrq->u.data.pointer, (t_u8 *) & bss->param.atim_window, sizeof(int))) { + ret = -EFAULT; + goto done; + } + wrq->u.data.length = 1; + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Set/Get TX data rate + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_get_txrate(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + mlan_ds_rate *rate = NULL; + mlan_ioctl_req *req = NULL; + int rateindex = 0; + + ENTER(); + if (wrq->u.data.length) { + if (copy_from_user(&rateindex, wrq->u.data.pointer, sizeof(int))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + } + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + rate = (mlan_ds_rate *) req->pbuf; + rate->param.rate_cfg.rate_type = MLAN_RATE_INDEX; + rate->sub_command = MLAN_OID_RATE_CFG; + req->req_id = MLAN_IOCTL_RATE; + if (!wrq->u.data.length) + req->action = MLAN_ACT_GET; + else { + req->action = MLAN_ACT_SET; + if (rateindex == AUTO_RATE) + rate->param.rate_cfg.is_rate_auto = 1; + else { + if ((rateindex != MLAN_RATE_INDEX_MCS32) && + ((rateindex < 0) || (rateindex > MLAN_RATE_INDEX_MCS15))) { + ret = -EINVAL; + goto done; + } + } + rate->param.rate_cfg.rate = rateindex; + } + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } else { + if (wrq->u.data.length) + priv->rate_index = rateindex; + } + if (!wrq->u.data.length) { + if (rate->param.rate_cfg.is_rate_auto) + rateindex = AUTO_RATE; + else + rateindex = rate->param.rate_cfg.rate; + wrq->u.data.length = 1; + if (copy_to_user(wrq->u.data.pointer, &rateindex, sizeof(int))) { + ret = -EFAULT; + } + } + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Set/Get region code + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_get_regioncode(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + mlan_ds_misc_cfg *cfg = NULL; + mlan_ioctl_req *req = NULL; + int region = 0; + + ENTER(); + + if (wrq->u.data.length) { + if (copy_from_user(®ion, wrq->u.data.pointer, sizeof(int))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + } + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + cfg = (mlan_ds_misc_cfg *) req->pbuf; + cfg->sub_command = MLAN_OID_MISC_REGION; + req->req_id = MLAN_IOCTL_MISC_CFG; + if (!wrq->u.data.length) + req->action = MLAN_ACT_GET; + else { + req->action = MLAN_ACT_SET; + cfg->param.region_code = region; + } + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + if (!wrq->u.data.length) { + wrq->u.data.length = 1; + if (copy_to_user + (wrq->u.data.pointer, &cfg->param.region_code, sizeof(int))) + ret = -EFAULT; + } + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Set/Get radio + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_get_radio(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + mlan_bss_info bss_info; + int option = 0; + + ENTER(); + + memset(&bss_info, 0, sizeof(bss_info)); + + if (wrq->u.data.length) { + /* Set radio */ + if (copy_from_user(&option, wrq->u.data.pointer, sizeof(int))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + if (MLAN_STATUS_SUCCESS != woal_set_radio(priv, (t_u8) option)) + ret = -EFAULT; + } else { + /* Get radio status */ + woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info); + wrq->u.data.length = 1; + if (copy_to_user + (wrq->u.data.pointer, &bss_info.radio_on, + sizeof(bss_info.radio_on))) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + } + } + done: + LEAVE(); + return ret; +} + +#ifdef DEBUG_LEVEL1 +/** + * @brief Get/Set the bit mask of driver debug message control + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to wrq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_drv_dbg(moal_private * priv, struct iwreq *wrq) +{ + int data[4]; + int ret = 0; + + ENTER(); + + if (!wrq->u.data.length) { + data[0] = drvdbg; + /* Return the current driver debug bit masks */ + if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + goto drvdbgexit; + } + wrq->u.data.length = 1; + } else if (wrq->u.data.length < 3) { + /* Get the driver debug bit masks from user */ + if (copy_from_user + (data, wrq->u.data.pointer, sizeof(int) * wrq->u.data.length)) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto drvdbgexit; + } + drvdbg = data[0]; + /* Set the driver debug bit masks into mlan */ + woal_set_drvdbg(priv, drvdbg); + } else { + PRINTM(MERROR, "Invalid parameter number\n"); + goto drvdbgexit; + } + + printk(KERN_ALERT "drvdbg = 0x%08x\n", drvdbg); +#ifdef DEBUG_LEVEL2 + printk(KERN_ALERT "MINFO (%08x) %s\n", MINFO, (drvdbg & MINFO) ? "X" : ""); + printk(KERN_ALERT "MWARN (%08x) %s\n", MWARN, (drvdbg & MWARN) ? "X" : ""); + printk(KERN_ALERT "MENTRY (%08x) %s\n", MENTRY, + (drvdbg & MENTRY) ? "X" : ""); +#endif + printk(KERN_ALERT "MIF_D (%08x) %s\n", MIF_D, (drvdbg & MIF_D) ? "X" : ""); + printk(KERN_ALERT "MFW_D (%08x) %s\n", MFW_D, (drvdbg & MFW_D) ? "X" : ""); + printk(KERN_ALERT "MEVT_D (%08x) %s\n", MEVT_D, + (drvdbg & MEVT_D) ? "X" : ""); + printk(KERN_ALERT "MCMD_D (%08x) %s\n", MCMD_D, + (drvdbg & MCMD_D) ? "X" : ""); + printk(KERN_ALERT "MDAT_D (%08x) %s\n", MDAT_D, + (drvdbg & MDAT_D) ? "X" : ""); + printk(KERN_ALERT "MIOCTL (%08x) %s\n", MIOCTL, + (drvdbg & MIOCTL) ? "X" : ""); + printk(KERN_ALERT "MINTR (%08x) %s\n", MINTR, (drvdbg & MINTR) ? "X" : ""); + printk(KERN_ALERT "MEVENT (%08x) %s\n", MEVENT, + (drvdbg & MEVENT) ? "X" : ""); + printk(KERN_ALERT "MCMND (%08x) %s\n", MCMND, (drvdbg & MCMND) ? "X" : ""); + printk(KERN_ALERT "MDATA (%08x) %s\n", MDATA, (drvdbg & MDATA) ? "X" : ""); + printk(KERN_ALERT "MERROR (%08x) %s\n", MERROR, + (drvdbg & MERROR) ? "X" : ""); + printk(KERN_ALERT "MFATAL (%08x) %s\n", MFATAL, + (drvdbg & MFATAL) ? "X" : ""); + printk(KERN_ALERT "MMSG (%08x) %s\n", MMSG, (drvdbg & MMSG) ? "X" : ""); + + drvdbgexit: + LEAVE(); + return ret; +} +#endif /* DEBUG_LEVEL1 */ + +/** + * @brief Set/Get QoS configuration + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_get_qos_cfg(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + mlan_ds_wmm_cfg *cfg = NULL; + mlan_ioctl_req *req = NULL; + int data = 0; + + ENTER(); + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + cfg = (mlan_ds_wmm_cfg *) req->pbuf; + cfg->sub_command = MLAN_OID_WMM_CFG_QOS; + req->req_id = MLAN_IOCTL_WMM_CFG; + if (wrq->u.data.length) { + if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + req->action = MLAN_ACT_SET; + cfg->param.qos_cfg = (t_u8) data; + } else + req->action = MLAN_ACT_GET; + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + if (!wrq->u.data.length) { + data = (int) cfg->param.qos_cfg; + if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) { + ret = -EFAULT; + goto done; + } + wrq->u.data.length = 1; + } + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Set/Get WWS mode + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_wws_cfg(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + mlan_ds_misc_cfg *wws = NULL; + mlan_ioctl_req *req = NULL; + int data = 0; + + ENTER(); + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + wws = (mlan_ds_misc_cfg *) req->pbuf; + wws->sub_command = MLAN_OID_MISC_WWS; + req->req_id = MLAN_IOCTL_MISC_CFG; + if (wrq->u.data.length) { + if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + if (data != CMD_DISABLED && data != CMD_ENABLED) { + ret = -EINVAL; + goto done; + } + req->action = MLAN_ACT_SET; + wws->param.wws_cfg = data; + } else + req->action = MLAN_ACT_GET; + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + if (!wrq->u.data.length) { + data = wws->param.wws_cfg; + if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) { + ret = -EFAULT; + goto done; + } + wrq->u.data.length = 1; + } + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Set/Get sleep period + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_sleep_pd(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + mlan_ds_pm_cfg *pm_cfg = NULL; + mlan_ioctl_req *req = NULL; + int data = 0; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + pm_cfg = (mlan_ds_pm_cfg *) req->pbuf; + pm_cfg->sub_command = MLAN_OID_PM_CFG_SLEEP_PD; + req->req_id = MLAN_IOCTL_PM_CFG; + if (wrq->u.data.length) { + if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + if ((data <= MAX_SLEEP_PERIOD && data >= MIN_SLEEP_PERIOD) || + (data == 0) + || (data == SLEEP_PERIOD_RESERVED_FF) + ) { + req->action = MLAN_ACT_SET; + pm_cfg->param.sleep_period = data; + } else { + ret = -EINVAL; + goto done; + } + } else + req->action = MLAN_ACT_GET; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + if (!wrq->u.data.length) { + data = pm_cfg->param.sleep_period; + if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) { + ret = -EFAULT; + goto done; + } + wrq->u.data.length = 1; + } + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Configure sleep parameters + * + * @param priv A pointer to moal_private structure + * @param req A pointer to ifreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_sleep_params_ioctl(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_pm_cfg *pm = NULL; + mlan_ds_sleep_params *psleep_params = NULL; + int data[6] = { 0 }, i; +#ifdef DEBUG_LEVEL1 + char err_str[][35] = { {"sleep clock error in ppm"}, + {"wakeup offset in usec"}, + {"clock stabilization time in usec"}, + {"value of reserved for debug"} + }; +#endif + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg)); + if (req == NULL) { + LEAVE(); + return -ENOMEM; + } + + pm = (mlan_ds_pm_cfg *) req->pbuf; + pm->sub_command = MLAN_OID_PM_CFG_SLEEP_PARAMS; + req->req_id = MLAN_IOCTL_PM_CFG; + psleep_params = (pmlan_ds_sleep_params) & pm->param.sleep_params; + + if (wrq->u.data.length == 0) { + req->action = MLAN_ACT_GET; + } else if (wrq->u.data.length == 6) { + if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * + wrq->u.data.length)) { + /* copy_from_user failed */ + PRINTM(MERROR, "S_PARAMS: copy from user failed\n"); + LEAVE(); + return -EINVAL; + } +#define MIN_VAL 0x0000 +#define MAX_VAL 0xFFFF + for (i = 0; i < 6; i++) { + if ((i == 3) || (i == 4)) { + /* These two cases are handled below the loop */ + continue; + } + if (data[i] < MIN_VAL || data[i] > MAX_VAL) { + PRINTM(MERROR, "Invalid %s (0-65535)!\n", err_str[i]); + ret = -EINVAL; + goto done; + } + } + if (data[3] < 0 || data[3] > 2) { + PRINTM(MERROR, "Invalid control periodic calibration (0-2)!\n"); + ret = -EINVAL; + goto done; + } + if (data[4] < 0 || data[4] > 2) { + PRINTM(MERROR, "Invalid control of external sleep clock (0-2)!\n"); + ret = -EINVAL; + goto done; + } + req->action = MLAN_ACT_SET; + psleep_params->error = data[0]; + psleep_params->offset = data[1]; + psleep_params->stable_time = data[2]; + psleep_params->cal_control = data[3]; + psleep_params->ext_sleep_clk = data[4]; + psleep_params->reserved = data[5]; + } else { + ret = -EINVAL; + goto done; + } + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + data[0] = psleep_params->error; + data[1] = psleep_params->offset; + data[2] = psleep_params->stable_time; + data[3] = psleep_params->cal_control; + data[4] = psleep_params->ext_sleep_clk; + data[5] = psleep_params->reserved; + wrq->u.data.length = 6; + + if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * + wrq->u.data.length)) { + PRINTM(MERROR, "QCONFIG: copy to user failed\n"); + ret = -EFAULT; + goto done; + } + + done: + if (req) + kfree(req); + + LEAVE(); + return ret; +} + +/** + * @brief Set/get user provisioned local power constraint + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * @return 0 --success, otherwise fail + */ +static int +woal_set_get_11h_local_pwr_constraint(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0, data = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_11h_cfg *ds_11hcfg = NULL; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + ds_11hcfg = (mlan_ds_11h_cfg *) req->pbuf; + if (wrq->u.data.length) { + if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { + PRINTM(MINFO, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + ds_11hcfg->param.usr_local_power_constraint = (t_s8) data; + req->action = MLAN_ACT_SET; + } else + req->action = MLAN_ACT_GET; + + ds_11hcfg->sub_command = MLAN_OID_11H_LOCAL_POWER_CONSTRAINT; + req->req_id = MLAN_IOCTL_11H_CFG; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + /* Copy response to user */ + if (req->action == MLAN_ACT_GET) { + data = (int) ds_11hcfg->param.usr_local_power_constraint; + if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) { + PRINTM(MINFO, "Copy to user failed\n"); + ret = -EFAULT; + goto done; + } + wrq->u.data.length = 1; + } + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Set/get HT stream configurations + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * @return 0 --success, otherwise fail + */ +static int +woal_ht_stream_cfg_ioctl(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0, data = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_11n_cfg *cfg = NULL; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + cfg = (mlan_ds_11n_cfg *) req->pbuf; + if (wrq->u.data.length) { + if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { + PRINTM(MINFO, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + if (data != HT_STREAM_MODE_1X1 && data != HT_STREAM_MODE_2X2) { + PRINTM(MINFO, "Invalid argument\n"); + ret = -EINVAL; + goto done; + } + cfg->param.stream_cfg = data; + req->action = MLAN_ACT_SET; + } else + req->action = MLAN_ACT_GET; + + cfg->sub_command = MLAN_OID_11N_CFG_STREAM_CFG; + req->req_id = MLAN_IOCTL_11N_CFG; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + /* Copy response to user */ + data = (int) cfg->param.stream_cfg; + if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) { + PRINTM(MINFO, "Copy to user failed\n"); + ret = -EFAULT; + goto done; + } + wrq->u.data.length = 1; + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Set/get MAC control configuration + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * @return 0 --success, otherwise fail + */ +static int +woal_mac_control_ioctl(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0, data = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_misc_cfg *cfg = NULL; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + cfg = (mlan_ds_misc_cfg *) req->pbuf; + if (wrq->u.data.length) { + if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { + PRINTM(MINFO, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + /* Validation will be done later */ + cfg->param.mac_ctrl = data; + req->action = MLAN_ACT_SET; + } else + req->action = MLAN_ACT_GET; + + cfg->sub_command = MLAN_OID_MISC_MAC_CONTROL; + req->req_id = MLAN_IOCTL_MISC_CFG; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + /* Copy response to user */ + data = (int) cfg->param.mac_ctrl; + if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) { + PRINTM(MINFO, "Copy to user failed\n"); + ret = -EFAULT; + goto done; + } + wrq->u.data.length = 1; + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Get thermal reading + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * @return 0 --success, otherwise fail + */ +static int +woal_thermal_ioctl(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0, data = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_misc_cfg *cfg = NULL; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + cfg = (mlan_ds_misc_cfg *) req->pbuf; + if (wrq->u.data.length) { + PRINTM(MERROR, "Set is not supported for this command\n"); + ret = -EINVAL; + goto done; + } + req->action = MLAN_ACT_GET; + + cfg->sub_command = MLAN_OID_MISC_THERMAL; + req->req_id = MLAN_IOCTL_MISC_CFG; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + /* Copy response to user */ + data = (int) cfg->param.thermal; + if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) { + PRINTM(MINFO, "Copy to user failed\n"); + ret = -EFAULT; + goto done; + } + wrq->u.data.length = 1; + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +#if defined(REASSOCIATION) +/** + * @brief Set/Get reassociation settings + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_get_reassoc(moal_private * priv, struct iwreq *wrq) +{ + moal_handle *handle = priv->phandle; + int ret = 0; + int data = 0; + + ENTER(); + + if (wrq->u.data.length) { + if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + if (data == 0) { + handle->reassoc_on &= ~MBIT(priv->bss_index); + priv->reassoc_on = MFALSE; + priv->reassoc_required = MFALSE; + if (!handle->reassoc_on && handle->is_reassoc_timer_set == MTRUE) { + woal_cancel_timer(&handle->reassoc_timer); + handle->is_reassoc_timer_set = MFALSE; + } + } else { + handle->reassoc_on |= MBIT(priv->bss_index); + priv->reassoc_on = MTRUE; + } + } else { + data = (int) (priv->reassoc_on); + if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) { + ret = -EFAULT; + goto done; + } + wrq->u.data.length = 1; + } + + done: + LEAVE(); + return ret; +} +#endif /* REASSOCIATION */ + +/** + * @brief implement WMM enable command + * + * @param priv Pointer to the moal_private driver data struct + * @param wrq Pointer to user data + * + * @return 0 --success, otherwise fail + */ +static int +woal_wmm_enable_ioctl(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + mlan_ds_wmm_cfg *wmm = NULL; + mlan_ioctl_req *req = NULL; + int data = 0; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + wmm = (mlan_ds_wmm_cfg *) req->pbuf; + req->req_id = MLAN_IOCTL_WMM_CFG; + wmm->sub_command = MLAN_OID_WMM_CFG_ENABLE; + + if (wrq->u.data.length) { + /* Set WMM configuration */ + if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + if ((data < CMD_DISABLED) || (data > CMD_ENABLED)) { + ret = -EINVAL; + goto done; + } + req->action = MLAN_ACT_SET; + if (data == CMD_DISABLED) + wmm->param.wmm_enable = MFALSE; + else + wmm->param.wmm_enable = MTRUE; + } else { + /* Get WMM status */ + req->action = MLAN_ACT_GET; + } + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + if (wrq->u.data.pointer) { + if (copy_to_user + (wrq->u.data.pointer, &wmm->param.wmm_enable, + sizeof(wmm->param.wmm_enable))) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + goto done; + } + wrq->u.data.length = 1; + } + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Implement 802.11D enable command + * + * @param priv Pointer to the moal_private driver data struct + * @param wrq Pointer to user data + * + * @return 0 --success, otherwise fail + */ +static int +woal_11d_enable_ioctl(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + mlan_ds_11d_cfg *pcfg_11d = NULL; + mlan_ioctl_req *req = NULL; + int data = 0; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + pcfg_11d = (mlan_ds_11d_cfg *) req->pbuf; + req->req_id = MLAN_IOCTL_11D_CFG; + pcfg_11d->sub_command = MLAN_OID_11D_CFG_ENABLE; + if (wrq->u.data.length) { + /* Set 11D configuration */ + if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + if ((data < CMD_DISABLED) || (data > CMD_ENABLED)) { + ret = -EINVAL; + goto done; + } + if (data == CMD_DISABLED) + pcfg_11d->param.enable_11d = MFALSE; + else + pcfg_11d->param.enable_11d = MTRUE; + req->action = MLAN_ACT_SET; + } else { + req->action = MLAN_ACT_GET; + } + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + if (wrq->u.data.pointer) { + if (copy_to_user + (wrq->u.data.pointer, &pcfg_11d->param.enable_11d, + sizeof(pcfg_11d->param.enable_11d))) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + goto done; + } + wrq->u.data.length = 1; + } + done: + if (req) + kfree(req); + + LEAVE(); + return ret; +} + +/** + * @brief Implement 802.11D clear chan table command + * + * @param priv Pointer to the moal_private driver data struct + * @param wrq Pointer to user data + * + * @return 0 --success, otherwise fail + */ +static int +woal_11d_clr_chan_table(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + mlan_ds_11d_cfg *pcfg_11d = NULL; + mlan_ioctl_req *req = NULL; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + pcfg_11d = (mlan_ds_11d_cfg *) req->pbuf; + req->req_id = MLAN_IOCTL_11D_CFG; + pcfg_11d->sub_command = MLAN_OID_11D_CLR_CHAN_TABLE; + req->action = MLAN_ACT_SET; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + done: + if (req) + kfree(req); + + LEAVE(); + return ret; +} + +/** + * @brief Control WPS Session Enable/Disable + * + * @param priv Pointer to the moal_private driver data struct + * @param wrq Pointer to user data + * + * @return 0 --success, otherwise fail + */ +static int +woal_wps_cfg_ioctl(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + mlan_ds_wps_cfg *pwps = NULL; + mlan_ioctl_req *req = NULL; + char buf[8]; + struct iwreq *wreq = (struct iwreq *) wrq; + + ENTER(); + + PRINTM(MINFO, "WOAL_WPS_SESSION\n"); + + memset(buf, 0, sizeof(buf)); + if (copy_from_user(buf, wreq->u.data.pointer, + MIN(sizeof(buf) - 1, wreq->u.data.length))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wps_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + pwps = (mlan_ds_wps_cfg *) req->pbuf; + req->req_id = MLAN_IOCTL_WPS_CFG; + req->action = MLAN_ACT_SET; + pwps->sub_command = MLAN_OID_WPS_CFG_SESSION; + if (buf[0] == 1) + pwps->param.wps_session = MLAN_WPS_CFG_SESSION_START; + else + pwps->param.wps_session = MLAN_WPS_CFG_SESSION_END; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Set WPA passphrase and SSID + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to user data + * + * @return 0 --success, otherwise fail + */ +static int +woal_passphrase(moal_private * priv, struct iwreq *wrq) +{ + t_u16 len = 0; + static char buf[256]; + char *begin, *end, *opt; + int ret = 0, action = -1, i; + mlan_ds_sec_cfg *sec = NULL; + mlan_ioctl_req *req = NULL; + t_u8 zero_mac[] = { 0, 0, 0, 0, 0, 0 }; + t_u8 *mac = NULL; + + ENTER(); + + if (!wrq->u.data.length || wrq->u.data.length >= sizeof(buf)) { + PRINTM(MERROR, "Argument missing or too long for setpassphrase\n"); + ret = -EINVAL; + goto done; + } + + if (copy_from_user(buf, wrq->u.data.pointer, wrq->u.data.length)) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + buf[wrq->u.data.length] = '\0'; + + /* Parse the buf to get the cmd_action */ + begin = buf; + end = woal_strsep(&begin, ';', '/'); + if (end) + action = woal_atox(end); + if (action < 0 || action > 2 || end[1] != '\0') { + PRINTM(MERROR, "Invalid action argument %s\n", end); + ret = -EINVAL; + goto done; + } + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + sec = (mlan_ds_sec_cfg *) req->pbuf; + sec->sub_command = MLAN_OID_SEC_CFG_PASSPHRASE; + req->req_id = MLAN_IOCTL_SEC_CFG; + if (action == 0) + req->action = MLAN_ACT_GET; + else + req->action = MLAN_ACT_SET; + while (begin) { + end = woal_strsep(&begin, ';', '/'); + opt = woal_strsep(&end, '=', '/'); + if (!opt || !end || !end[0]) { + PRINTM(MERROR, "Invalid option\n"); + ret = -EINVAL; + break; + } else if (!strnicmp(opt, "ssid", strlen(opt))) { + if (strlen(end) > MLAN_MAX_SSID_LENGTH) { + PRINTM(MERROR, "SSID length exceeds max length\n"); + ret = -EFAULT; + break; + } + sec->param.passphrase.ssid.ssid_len = strlen(end); + strncpy((char *) sec->param.passphrase.ssid.ssid, end, strlen(end)); + PRINTM(MINFO, "ssid=%s, len=%d\n", sec->param.passphrase.ssid.ssid, + (int) sec->param.passphrase.ssid.ssid_len); + } else if (!strnicmp(opt, "bssid", strlen(opt))) { + woal_mac2u8((t_u8 *) & sec->param.passphrase.bssid, end); + } else if (!strnicmp(opt, "psk", strlen(opt)) && + req->action == MLAN_ACT_SET) { + if (strlen(end) != MLAN_PMK_HEXSTR_LENGTH) { + PRINTM(MERROR, "Invalid PMK length\n"); + ret = -EINVAL; + break; + } + woal_ascii2hex((t_u8 *) (sec->param.passphrase.psk.pmk.pmk), end, + MLAN_PMK_HEXSTR_LENGTH / 2); + sec->param.passphrase.psk_type = MLAN_PSK_PMK; + } else if (!strnicmp(opt, "passphrase", strlen(opt)) && + req->action == MLAN_ACT_SET) { + if (strlen(end) < MLAN_MIN_PASSPHRASE_LENGTH || + strlen(end) > MLAN_MAX_PASSPHRASE_LENGTH) { + PRINTM(MERROR, "Invalid length for passphrase\n"); + ret = -EINVAL; + break; + } + sec->param.passphrase.psk_type = MLAN_PSK_PASSPHRASE; + strncpy(sec->param.passphrase.psk.passphrase.passphrase, end, + sizeof(sec->param.passphrase.psk.passphrase.passphrase)); + sec->param.passphrase.psk.passphrase.passphrase_len = strlen(end); + PRINTM(MINFO, "passphrase=%s, len=%d\n", + sec->param.passphrase.psk.passphrase.passphrase, + (int) sec->param.passphrase.psk.passphrase.passphrase_len); + } else { + PRINTM(MERROR, "Invalid option %s\n", opt); + ret = -EINVAL; + break; + } + } + if (ret) + goto done; + + if (action == 2) + sec->param.passphrase.psk_type = MLAN_PSK_CLEAR; + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + if (action == 0) { + memset(buf, 0, sizeof(buf)); + if (sec->param.passphrase.ssid.ssid_len) { + len += sprintf(buf + len, "ssid:"); + memcpy(buf + len, sec->param.passphrase.ssid.ssid, + sec->param.passphrase.ssid.ssid_len); + len += sec->param.passphrase.ssid.ssid_len; + len += sprintf(buf + len, " "); + } + if (memcmp(&sec->param.passphrase.bssid, zero_mac, sizeof(zero_mac))) { + mac = (t_u8 *) & sec->param.passphrase.bssid; + len += sprintf(buf + len, "bssid:"); + for (i = 0; i < ETH_ALEN - 1; ++i) + len += sprintf(buf + len, "%02x:", mac[i]); + len += sprintf(buf + len, "%02x ", mac[i]); + } + if (sec->param.passphrase.psk_type == MLAN_PSK_PMK) { + len += sprintf(buf + len, "psk:"); + for (i = 0; i < MLAN_MAX_KEY_LENGTH; ++i) + len += + sprintf(buf + len, "%02x", + sec->param.passphrase.psk.pmk.pmk[i]); + len += sprintf(buf + len, "\n"); + } + if (sec->param.passphrase.psk_type == MLAN_PSK_PASSPHRASE) { + len += + sprintf(buf + len, "passphrase:%s \n", + sec->param.passphrase.psk.passphrase.passphrase); + } + if (wrq->u.data.pointer) { + if (copy_to_user(wrq->u.data.pointer, buf, MIN(len, sizeof(buf)))) { + PRINTM(MERROR, "Copy to user failed, len %d\n", len); + ret = -EFAULT; + goto done; + } + wrq->u.data.length = len; + } + + } + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Get esupp mode + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_get_esupp_mode(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + mlan_ds_sec_cfg *sec = NULL; + mlan_ioctl_req *req = NULL; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + sec = (mlan_ds_sec_cfg *) req->pbuf; + sec->sub_command = MLAN_OID_SEC_CFG_ESUPP_MODE; + req->req_id = MLAN_IOCTL_SEC_CFG; + req->action = MLAN_ACT_GET; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + if (copy_to_user + (wrq->u.data.pointer, (t_u8 *) & sec->param.esupp_mode, + sizeof(int) * 3)) { + ret = -EFAULT; + goto done; + } + wrq->u.data.length = 3; + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** AES key length */ +#define AES_KEY_LEN 16 +/** + * @brief Adhoc AES control + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to user data + * + * @return 0 --success, otherwise fail + */ +static int +woal_adhoc_aes_ioctl(moal_private * priv, struct iwreq *wrq) +{ + static char buf[256]; + int ret = 0, action = -1; + unsigned int i; + t_u8 key_ascii[32]; + t_u8 key_hex[16]; + t_u8 *tmp; + mlan_bss_info bss_info; + mlan_ds_sec_cfg *sec = NULL; + mlan_ioctl_req *req = NULL; + t_u8 bcast_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + ENTER(); + + memset(key_ascii, 0x00, sizeof(key_ascii)); + memset(key_hex, 0x00, sizeof(key_hex)); + + /* Get current BSS information */ + memset(&bss_info, 0, sizeof(bss_info)); + woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info); + if (bss_info.bss_mode != MLAN_BSS_MODE_IBSS || + bss_info.media_connected == MTRUE) { + PRINTM(MERROR, "STA is connected or not in IBSS mode.\n"); + ret = -EOPNOTSUPP; + goto done; + } + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + if (wrq->u.data.length) { + if (wrq->u.data.length >= sizeof(buf)) { + PRINTM(MERROR, "Too many arguments\n"); + ret = -EINVAL; + goto done; + } + if (copy_from_user(buf, wrq->u.data.pointer, wrq->u.data.length)) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + buf[wrq->u.data.length] = '\0'; + + if (wrq->u.data.length == 1) { + /* Get Adhoc AES Key */ + req->req_id = MLAN_IOCTL_SEC_CFG; + req->action = MLAN_ACT_GET; + sec = (mlan_ds_sec_cfg *) req->pbuf; + sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY; + sec->param.encrypt_key.key_len = AES_KEY_LEN; + sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_UNICAST; + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + memcpy(key_hex, sec->param.encrypt_key.key_material, + sizeof(key_hex)); + HEXDUMP("Adhoc AES Key (HEX)", key_hex, sizeof(key_hex)); + + wrq->u.data.length = sizeof(key_ascii) + 1; + + tmp = key_ascii; + for (i = 0; i < sizeof(key_hex); i++) + tmp += sprintf((char *) tmp, "%02x", key_hex[i]); + } else if (wrq->u.data.length >= 2) { + /* Parse the buf to get the cmd_action */ + action = woal_atox(&buf[0]); + if (action < 1 || action > 2) { + PRINTM(MERROR, "Invalid action argument %d\n", action); + ret = -EINVAL; + goto done; + } + + req->req_id = MLAN_IOCTL_SEC_CFG; + req->action = MLAN_ACT_SET; + sec = (mlan_ds_sec_cfg *) req->pbuf; + sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY; + + if (action == 1) { + /* Set Adhoc AES Key */ + memcpy(key_ascii, &buf[2], sizeof(key_ascii)); + woal_ascii2hex(key_hex, (char *) key_ascii, sizeof(key_hex)); + HEXDUMP("Adhoc AES Key (HEX)", key_hex, sizeof(key_hex)); + + sec->param.encrypt_key.key_len = AES_KEY_LEN; + sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_UNICAST; + sec->param.encrypt_key.key_flags = + KEY_FLAG_SET_TX_KEY | KEY_FLAG_GROUP_KEY; + memcpy(sec->param.encrypt_key.mac_addr, (u8 *) bcast_addr, + ETH_ALEN); + memcpy(sec->param.encrypt_key.key_material, key_hex, + sec->param.encrypt_key.key_len); + + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + } else if (action == 2) { + /* Clear Adhoc AES Key */ + sec->param.encrypt_key.key_len = AES_KEY_LEN; + sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_UNICAST; + sec->param.encrypt_key.key_flags = KEY_FLAG_REMOVE_KEY; + memcpy(sec->param.encrypt_key.mac_addr, (u8 *) bcast_addr, + ETH_ALEN); + memset(sec->param.encrypt_key.key_material, 0, + sizeof(sec->param.encrypt_key.key_material)); + + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + } else { + PRINTM(MERROR, "Invalid argument\n"); + ret = -EINVAL; + goto done; + } + } + + HEXDUMP("Adhoc AES Key (ASCII)", key_ascii, sizeof(key_ascii)); + wrq->u.data.length = sizeof(key_ascii); + if (wrq->u.data.pointer) { + if (copy_to_user(wrq->u.data.pointer, &key_ascii, + sizeof(key_ascii))) { + PRINTM(MERROR, "copy_to_user failed\n"); + ret = -EFAULT; + goto done; + } + } + } + + done: + if (req) + kfree(req); + + LEAVE(); + return ret; +} + +/** + * @brief arpfilter ioctl function + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * @return 0 --success, otherwise fail + */ +static int +woal_arp_filter(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + mlan_ds_misc_cfg *misc = NULL; + mlan_ioctl_req *req = NULL; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + misc = (mlan_ds_misc_cfg *) req->pbuf; + misc->sub_command = MLAN_OID_MISC_GEN_IE; + req->req_id = MLAN_IOCTL_MISC_CFG; + req->action = MLAN_ACT_SET; + misc->param.gen_ie.type = MLAN_IE_TYPE_ARP_FILTER; + misc->param.gen_ie.len = wrq->u.data.length; + + /* get the whole command from user */ + if (copy_from_user + (misc->param.gen_ie.ie_data, wrq->u.data.pointer, wrq->u.data.length)) { + PRINTM(MERROR, "copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Set/get IP address + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * @return 0 --success, otherwise fail + */ +static int +woal_set_get_ip_addr(moal_private * priv, struct iwreq *wrq) +{ + char buf[IPADDR_MAX_BUF]; + struct iwreq *wreq = (struct iwreq *) wrq; + mlan_ioctl_req *ioctl_req = NULL; + mlan_ds_misc_cfg *misc = NULL; + int ret = 0, op_code = 0, data_length = wrq->u.data.length; + + ENTER(); + + memset(buf, 0, IPADDR_MAX_BUF); + ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (ioctl_req == NULL) { + ret = -ENOMEM; + goto done; + } + misc = (mlan_ds_misc_cfg *) ioctl_req->pbuf; + + if (data_length <= 1) { /* GET */ + ioctl_req->action = MLAN_ACT_GET; + } else { + if (copy_from_user(buf, wreq->u.data.pointer, + MIN(IPADDR_MAX_BUF - 1, wreq->u.data.length))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + /* Make sure we have the operation argument */ + if (data_length > 2 && buf[1] != ';') { + PRINTM(MERROR, "No operation argument. Separate with ';'\n"); + ret = -EINVAL; + goto done; + } else { + buf[1] = '\0'; + } + ioctl_req->action = MLAN_ACT_SET; + /* only one IP is supported in current firmware */ + memset(misc->param.ipaddr_cfg.ip_addr[0], 0, IPADDR_LEN); + in4_pton(&buf[2], MIN((IPADDR_MAX_BUF - 3), (wreq->u.data.length - 2)), + misc->param.ipaddr_cfg.ip_addr[0], ' ', NULL); + /* only one IP is supported in current firmware */ + misc->param.ipaddr_cfg.ip_addr_num = 1; + misc->param.ipaddr_cfg.ip_addr_type = IPADDR_TYPE_IPV4; + } + if (woal_atoi(&op_code, &buf[0]) != MLAN_STATUS_SUCCESS) { + ret = -EINVAL; + goto done; + } + misc->param.ipaddr_cfg.op_code = (t_u32) op_code; + ioctl_req->req_id = MLAN_IOCTL_MISC_CFG; + misc->sub_command = MLAN_OID_MISC_IP_ADDR; + + /* Send ioctl to mlan */ + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + if (ioctl_req->action == MLAN_ACT_GET) { + snprintf(buf, IPADDR_MAX_BUF, "%d;%d.%d.%d.%d", + misc->param.ipaddr_cfg.op_code, + misc->param.ipaddr_cfg.ip_addr[0][0], + misc->param.ipaddr_cfg.ip_addr[0][1], + misc->param.ipaddr_cfg.ip_addr[0][2], + misc->param.ipaddr_cfg.ip_addr[0][3]); + wrq->u.data.length = IPADDR_MAX_BUF; + if (copy_to_user(wrq->u.data.pointer, buf, IPADDR_MAX_BUF)) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + } + } + + done: + if (ioctl_req) + kfree(ioctl_req); + LEAVE(); + return ret; +} + +/** + * @brief Set/Get Transmit beamforming capabilities + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 -- success, otherwise fail + */ +static int +woal_tx_bf_cap_ioctl(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0, data_length = wrq->u.data.length; + mlan_ioctl_req *req = NULL; + mlan_ds_11n_cfg *bf_cfg = NULL; + int bf_cap = 0; + + ENTER(); + + if (data_length > 1) { + PRINTM(MERROR, "Invalid no of arguments!\n"); + ret = -EINVAL; + goto done; + } + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + bf_cfg = (mlan_ds_11n_cfg *) req->pbuf; + req->req_id = MLAN_IOCTL_11N_CFG; + bf_cfg->sub_command = MLAN_OID_11N_CFG_TX_BF_CAP; + req->action = MLAN_ACT_GET; + if (data_length) { /* SET */ + if (copy_from_user(&bf_cap, wrq->u.data.pointer, sizeof(int))) { + PRINTM(MERROR, "copy from user failed\n"); + ret = -EFAULT; + goto done; + } + bf_cfg->param.tx_bf_cap = bf_cap; + req->action = MLAN_ACT_SET; + } + + /* Send IOCTL request to MLAN */ + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + bf_cap = bf_cfg->param.tx_bf_cap; + if (copy_to_user(wrq->u.data.pointer, &bf_cap, sizeof(int))) { + ret = -EFAULT; + goto done; + } + wrq->u.data.length = 1; + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/* Maximum input output characters in group WOAL_SET_GET_256_CHAR */ +#define MAX_IN_OUT_CHAR 256 +/** Tx BF Global conf argument index */ +#define BF_ENABLE_PARAM 1 +#define SOUND_ENABLE_PARAM 2 +#define FB_TYPE_PARAM 3 +#define SNR_THRESHOLD_PARAM 4 +#define SOUND_INTVL_PARAM 5 +#define BF_MODE_PARAM 6 +#define MAX_TX_BF_GLOBAL_ARGS 6 +#define BF_CFG_ACT_GET 0 +#define BF_CFG_ACT_SET 1 + +/** + * @brief Set/Get Transmit beamforming configuration + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 -- success, otherwise fail + */ +static int +woal_tx_bf_cfg_ioctl(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0, data_length = wrq->u.data.length; + int bf_action = 0, interval = 0; + int snr = 0, i, tmp_val; + t_u8 buf[MAX_IN_OUT_CHAR], char_count = 0; + t_u8 *str, *token, *pos; + t_u16 action = 0; + + mlan_ds_11n_tx_bf_cfg bf_cfg; + mlan_trigger_sound_args *bf_sound = NULL; + mlan_tx_bf_peer_args *tx_bf_peer = NULL; + mlan_snr_thr_args *bf_snr = NULL; + mlan_bf_periodicity_args *bf_periodicity = NULL; + mlan_bf_global_cfg_args *bf_global = NULL; + + ENTER(); + + memset(&bf_cfg, 0, sizeof(bf_cfg)); + /* Pointer to corresponding buffer */ + bf_sound = bf_cfg.body.bf_sound; + tx_bf_peer = bf_cfg.body.tx_bf_peer; + bf_snr = bf_cfg.body.bf_snr; + bf_periodicity = bf_cfg.body.bf_periodicity; + bf_global = &bf_cfg.body.bf_global_cfg; + + /* Total characters in buffer */ + char_count = data_length - 1; + memset(buf, 0, sizeof(buf)); + if (char_count) { + if (data_length > sizeof(buf)) { + PRINTM(MERROR, "Too many arguments\n"); + ret = -EINVAL; + goto done; + } + if (copy_from_user(buf, wrq->u.data.pointer, data_length)) { + PRINTM(MERROR, "copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + if (char_count > 1 && buf[1] != ';') { + PRINTM(MERROR, "No action argument. Separate with ';'\n"); + ret = -EINVAL; + goto done; + } + /* Replace ';' with NULL in the string to separate args */ + for (i = 0; i < char_count; i++) { + if (buf[i] == ';') + buf[i] = '\0'; + } + /* The first byte represents the beamforming action */ + if (woal_atoi(&bf_action, &buf[0]) != MLAN_STATUS_SUCCESS) { + ret = -EINVAL; + goto done; + } + switch (bf_action) { + case BF_GLOBAL_CONFIGURATION: + if (char_count == 1) { + action = MLAN_ACT_GET; + bf_cfg.action = BF_CFG_ACT_GET; + } else { + action = MLAN_ACT_SET; + bf_cfg.action = BF_CFG_ACT_SET; + /* Eliminate action field */ + token = &buf[2]; + for (i = 1, str = &buf[2]; token != NULL; i++) { + token = strstr(str, " "); + pos = str; + if (token != NULL) { + *token = '\0'; + str = token + 1; + } + woal_atoi(&tmp_val, pos); + switch (i) { + case BF_ENABLE_PARAM: + bf_global->bf_enbl = (t_u8) tmp_val; + break; + case SOUND_ENABLE_PARAM: + bf_global->sounding_enbl = (t_u8) tmp_val; + break; + case FB_TYPE_PARAM: + bf_global->fb_type = (t_u8) tmp_val; + break; + case SNR_THRESHOLD_PARAM: + bf_global->snr_threshold = (t_u8) tmp_val; + break; + case SOUND_INTVL_PARAM: + bf_global->sounding_interval = (t_u16) tmp_val; + break; + case BF_MODE_PARAM: + bf_global->bf_mode = (t_u8) tmp_val; + break; + default: + PRINTM(MERROR, "Invalid Argument\n"); + ret = -EINVAL; + goto done; + } + } + } + break; + case TRIGGER_SOUNDING_FOR_PEER: + /* First arg = 2 BfAction Second arg = 17 MAC "00:50:43:20:BF:64" */ + if (char_count != 19) { + PRINTM(MERROR, "Invalid argument\n"); + ret = -EINVAL; + goto done; + } + woal_mac2u8(bf_sound->peer_mac, &buf[2]); + action = MLAN_ACT_SET; + bf_cfg.action = BF_CFG_ACT_SET; + break; + case SET_GET_BF_PERIODICITY: + /* First arg = 2 BfAction Second arg = 18 MAC "00:50:43:20:BF:64;" + Third arg = 1 (min char) TX BF interval 10 (max char) u32 + maximum value 4294967295 */ + if (char_count < 19 || char_count > 30) { + PRINTM(MERROR, "Invalid argument\n"); + ret = -EINVAL; + goto done; + } + + woal_mac2u8(bf_periodicity->peer_mac, &buf[2]); + if (char_count == 19) { + action = MLAN_ACT_GET; + bf_cfg.action = BF_CFG_ACT_GET; + } else { + action = MLAN_ACT_SET; + bf_cfg.action = BF_CFG_ACT_SET; + if (woal_atoi(&interval, &buf[20]) != MLAN_STATUS_SUCCESS) { + ret = -EINVAL; + goto done; + } + bf_periodicity->interval = interval; + } + break; + case TX_BF_FOR_PEER_ENBL: + /* Handle only SET operation here First arg = 2 BfAction Second arg + = 18 MAC "00:50:43:20:BF:64;" Third arg = 2 enable/disable bf + Fourth arg = 2 enable/disable sounding Fifth arg = 1 FB Type */ + if (char_count != 25 && char_count != 1) { + PRINTM(MERROR, "Invalid argument\n"); + ret = -EINVAL; + goto done; + } + if (char_count == 1) { + action = MLAN_ACT_GET; + bf_cfg.action = BF_CFG_ACT_GET; + } else { + woal_mac2u8(tx_bf_peer->peer_mac, &buf[2]); + woal_atoi(&tmp_val, &buf[20]); + tx_bf_peer->bf_enbl = (t_u8) tmp_val; + woal_atoi(&tmp_val, &buf[22]); + tx_bf_peer->sounding_enbl = (t_u8) tmp_val; + woal_atoi(&tmp_val, &buf[24]); + tx_bf_peer->fb_type = (t_u8) tmp_val; + action = MLAN_ACT_SET; + bf_cfg.action = BF_CFG_ACT_SET; + } + break; + case SET_SNR_THR_PEER: + /* First arg = 2 BfAction Second arg = 18 MAC "00:50:43:20:BF:64;" + Third arg = 1/2 SNR u8 - can be 1/2 charerters */ + if (char_count != 1 && !(char_count == 21 || char_count == 22)) { + PRINTM(MERROR, "Invalid argument\n"); + ret = -EINVAL; + goto done; + } + if (char_count == 1) { + action = MLAN_ACT_GET; + bf_cfg.action = BF_CFG_ACT_GET; + } else { + woal_mac2u8(bf_snr->peer_mac, &buf[2]); + if (woal_atoi(&snr, &buf[20]) != MLAN_STATUS_SUCCESS) { + ret = -EINVAL; + goto done; + } + bf_snr->snr = snr; + action = MLAN_ACT_SET; + bf_cfg.action = BF_CFG_ACT_SET; + } + break; + default: + ret = -EINVAL; + goto done; + } + + /* Save the value */ + bf_cfg.bf_action = bf_action; + if (MLAN_STATUS_SUCCESS != + woal_set_get_tx_bf_cfg(priv, action, &bf_cfg)) { + ret = -EFAULT; + goto done; + } + } else { + ret = -EINVAL; + goto done; + } + + if (action == MLAN_ACT_GET) { + data_length = 0; + memset(buf, 0, sizeof(buf)); + switch (bf_action) { + case BF_GLOBAL_CONFIGURATION: + data_length += + sprintf(buf + data_length, "%d ", (int) bf_global->bf_enbl); + data_length += + sprintf(buf + data_length, "%d ", + (int) bf_global->sounding_enbl); + data_length += + sprintf(buf + data_length, "%d ", (int) bf_global->fb_type); + data_length += + sprintf(buf + data_length, "%d ", + (int) bf_global->snr_threshold); + data_length += + sprintf(buf + data_length, "%d ", + (int) bf_global->sounding_interval); + data_length += + sprintf(buf + data_length, "%d ", (int) bf_global->bf_mode); + break; + case TRIGGER_SOUNDING_FOR_PEER: + data_length += sprintf(buf + data_length, + "%02x:%02x:%02x:%02x:%02x:%02x", + bf_sound->peer_mac[0], bf_sound->peer_mac[1], + bf_sound->peer_mac[2], bf_sound->peer_mac[3], + bf_sound->peer_mac[4], + bf_sound->peer_mac[5]); + data_length += sprintf(buf + data_length, "%c", ';'); + data_length += sprintf(buf + data_length, "%d", bf_sound->status); + break; + case SET_GET_BF_PERIODICITY: + data_length += sprintf(buf + data_length, + "%02x:%02x:%02x:%02x:%02x:%02x", + bf_periodicity->peer_mac[0], + bf_periodicity->peer_mac[1], + bf_periodicity->peer_mac[2], + bf_periodicity->peer_mac[3], + bf_periodicity->peer_mac[4], + bf_periodicity->peer_mac[5]); + data_length += sprintf(buf + data_length, "%c", ' '); + data_length += + sprintf(buf + data_length, "%d", bf_periodicity->interval); + break; + case TX_BF_FOR_PEER_ENBL: + for (i = 0; i < bf_cfg.no_of_peers; i++) { + data_length += sprintf(buf + data_length, + "%02x:%02x:%02x:%02x:%02x:%02x", + tx_bf_peer->peer_mac[0], + tx_bf_peer->peer_mac[1], + tx_bf_peer->peer_mac[2], + tx_bf_peer->peer_mac[3], + tx_bf_peer->peer_mac[4], + tx_bf_peer->peer_mac[5]); + data_length += sprintf(buf + data_length, "%c", ' '); + data_length += + sprintf(buf + data_length, "%d;", tx_bf_peer->bf_enbl); + data_length += + sprintf(buf + data_length, "%d;", + tx_bf_peer->sounding_enbl); + data_length += + sprintf(buf + data_length, "%d ", tx_bf_peer->fb_type); + tx_bf_peer++; + } + break; + case SET_SNR_THR_PEER: + for (i = 0; i < bf_cfg.no_of_peers; i++) { + data_length += sprintf(buf + data_length, + "%02x:%02x:%02x:%02x:%02x:%02x", + bf_snr->peer_mac[0], bf_snr->peer_mac[1], + bf_snr->peer_mac[2], bf_snr->peer_mac[3], + bf_snr->peer_mac[4], + bf_snr->peer_mac[5]); + data_length += sprintf(buf + data_length, "%c", ';'); + data_length += sprintf(buf + data_length, "%d", bf_snr->snr); + data_length += sprintf(buf + data_length, "%c", ' '); + bf_snr++; + } + break; + default: + ret = -EINVAL; + goto done; + } + buf[data_length] = '\0'; + } + + wrq->u.data.length = data_length; + if (copy_to_user(wrq->u.data.pointer, buf, wrq->u.data.length)) { + ret = -EFAULT; + goto done; + } + + done: + LEAVE(); + return ret; +} + +/** + * @brief Create a brief scan resp to relay basic BSS info to the app layer + * + * When the beacon/probe response has not been buffered, use the saved BSS + * information available to provide a minimum response for the application + * ioctl retrieval routines. Include: + * - Timestamp + * - Beacon Period + * - Capabilities (including WMM Element if available) + * - SSID + * + * @param ppbuffer Output parameter: Buffer used to create basic scan rsp + * @param pbss_desc Pointer to a BSS entry in the scan table to create + * scan response from for delivery to the application layer + * + * @return N/A + */ +static void +wlan_scan_create_brief_table_entry(t_u8 ** ppbuffer, + BSSDescriptor_t * pbss_desc) +{ + t_u8 *ptmp_buf = *ppbuffer; + t_u8 tmp_ssid_hdr[2]; + t_u8 ie_len = 0; + + ENTER(); + + if (copy_to_user(ptmp_buf, pbss_desc->time_stamp, + sizeof(pbss_desc->time_stamp))) { + PRINTM(MINFO, "Copy to user failed\n"); + LEAVE(); + return; + } + ptmp_buf += sizeof(pbss_desc->time_stamp); + + if (copy_to_user(ptmp_buf, &pbss_desc->beacon_period, + sizeof(pbss_desc->beacon_period))) { + PRINTM(MINFO, "Copy to user failed\n"); + LEAVE(); + return; + } + ptmp_buf += sizeof(pbss_desc->beacon_period); + + if (copy_to_user + (ptmp_buf, &pbss_desc->cap_info, sizeof(pbss_desc->cap_info))) { + PRINTM(MINFO, "Copy to user failed\n"); + LEAVE(); + return; + } + ptmp_buf += sizeof(pbss_desc->cap_info); + + tmp_ssid_hdr[0] = 0; /* Element ID for SSID is zero */ + tmp_ssid_hdr[1] = pbss_desc->ssid.ssid_len; + if (copy_to_user(ptmp_buf, tmp_ssid_hdr, sizeof(tmp_ssid_hdr))) { + PRINTM(MINFO, "Copy to user failed\n"); + LEAVE(); + return; + } + ptmp_buf += sizeof(tmp_ssid_hdr); + + if (copy_to_user(ptmp_buf, pbss_desc->ssid.ssid, pbss_desc->ssid.ssid_len)) { + PRINTM(MINFO, "Copy to user failed\n"); + LEAVE(); + return; + } + ptmp_buf += pbss_desc->ssid.ssid_len; + + if (pbss_desc->wmm_ie.vend_hdr.element_id == WMM_IE) { + ie_len = sizeof(IEEEtypes_Header_t) + pbss_desc->wmm_ie.vend_hdr.len; + if (copy_to_user(ptmp_buf, &pbss_desc->wmm_ie, ie_len)) { + PRINTM(MINFO, "Copy to user failed\n"); + LEAVE(); + return; + } + + ptmp_buf += ie_len; + } + + if (pbss_desc->pwpa_ie) { + if ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE) { + ie_len = + sizeof(IEEEtypes_Header_t) + + (*(pbss_desc->pwpa_ie)).vend_hdr.len; + if (copy_to_user(ptmp_buf, pbss_desc->pwpa_ie, ie_len)) { + PRINTM(MINFO, "Copy to user failed\n"); + LEAVE(); + return; + } + } + + ptmp_buf += ie_len; + } + + if (pbss_desc->prsn_ie) { + if ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == RSN_IE) { + ie_len = + sizeof(IEEEtypes_Header_t) + + (*(pbss_desc->prsn_ie)).ieee_hdr.len; + if (copy_to_user(ptmp_buf, pbss_desc->prsn_ie, ie_len)) { + PRINTM(MINFO, "Copy to user failed\n"); + LEAVE(); + return; + } + } + + ptmp_buf += ie_len; + } + + *ppbuffer = ptmp_buf; + LEAVE(); +} + +/** + * @brief Create a wlan_ioctl_get_scan_table_entry for a given BSS + * Descriptor for inclusion in the ioctl response to the user space + * application. + * + * + * @param pbss_desc Pointer to a BSS entry in the scan table to form + * scan response from for delivery to the application layer + * @param ppbuffer Output parameter: Buffer used to output scan return struct + * @param pspace_left Output parameter: Number of bytes available in the + * response buffer. + * + * @return MLAN_STATUS_SUCCESS, or < 0 with IOCTL error code + */ +static int +wlan_get_scan_table_ret_entry(BSSDescriptor_t * pbss_desc, + t_u8 ** ppbuffer, int *pspace_left) +{ + wlan_ioctl_get_scan_table_entry *prsp_entry; + wlan_ioctl_get_scan_table_entry tmp_rsp_entry; + int space_needed; + t_u8 *pcurrent; + int variable_size; + + const int fixed_size = sizeof(wlan_ioctl_get_scan_table_entry); + + ENTER(); + + pcurrent = *ppbuffer; + + /* The variable size returned is the stored beacon size */ + variable_size = pbss_desc->beacon_buf_size; + + /* If we stored a beacon and its size was zero, set the variable size + return value to the size of the brief scan response + wlan_scan_create_brief_table_entry creates. Also used if we are not + configured to store beacons in the first place */ + if (!variable_size) { + variable_size = pbss_desc->ssid.ssid_len + 2; + variable_size += (sizeof(pbss_desc->beacon_period) + + sizeof(pbss_desc->time_stamp) + + sizeof(pbss_desc->cap_info)); + if (pbss_desc->wmm_ie.vend_hdr.element_id == WMM_IE) { + variable_size += (sizeof(IEEEtypes_Header_t) + + pbss_desc->wmm_ie.vend_hdr.len); + } + + if (pbss_desc->pwpa_ie) { + if ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE) { + variable_size += (sizeof(IEEEtypes_Header_t) + + (*(pbss_desc->pwpa_ie)).vend_hdr.len); + } + } + + if (pbss_desc->prsn_ie) { + if ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == RSN_IE) { + variable_size += (sizeof(IEEEtypes_Header_t) + + (*(pbss_desc->prsn_ie)).ieee_hdr.len); + } + } + } + + space_needed = fixed_size + variable_size; + + PRINTM(MINFO, "GetScanTable: need(%d), left(%d)\n", + space_needed, *pspace_left); + + if (space_needed >= *pspace_left) { + *pspace_left = 0; + LEAVE(); + return -E2BIG; + } + + *pspace_left -= space_needed; + + tmp_rsp_entry.fixed_field_length = (sizeof(tmp_rsp_entry) + - + sizeof(tmp_rsp_entry.fixed_field_length) + - + sizeof(tmp_rsp_entry.bss_info_length)); + + memcpy(tmp_rsp_entry.fixed_fields.bssid, + pbss_desc->mac_address, sizeof(prsp_entry->fixed_fields.bssid)); + + tmp_rsp_entry.fixed_fields.rssi = pbss_desc->rssi; + tmp_rsp_entry.fixed_fields.channel = pbss_desc->channel; + tmp_rsp_entry.fixed_fields.network_tsf = pbss_desc->network_tsf; + tmp_rsp_entry.bss_info_length = variable_size; + + /* + * Copy fixed fields to user space + */ + if (copy_to_user(pcurrent, &tmp_rsp_entry, fixed_size)) { + PRINTM(MINFO, "Copy to user failed\n"); + LEAVE(); + return -EFAULT; + } + + pcurrent += fixed_size; + + if (pbss_desc->pbeacon_buf) { + /* + * Copy variable length elements to user space + */ + if (copy_to_user(pcurrent, pbss_desc->pbeacon_buf, + pbss_desc->beacon_buf_size)) { + PRINTM(MINFO, "Copy to user failed\n"); + LEAVE(); + return -EFAULT; + } + + pcurrent += pbss_desc->beacon_buf_size; + } else { + wlan_scan_create_brief_table_entry(&pcurrent, pbss_desc); + } + + *ppbuffer = pcurrent; + + LEAVE(); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Retrieve the scan response/beacon table + * + * @param wrq A pointer to iwreq structure + * @param scan_resp A pointer to mlan_scan_resp structure + * @param scan_start argument + * + * @return MLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int +moal_ret_get_scan_table_ioctl(struct iwreq *wrq, + mlan_scan_resp * scan_resp, t_u32 scan_start) +{ + pBSSDescriptor_t pbss_desc, scan_table; + wlan_ioctl_get_scan_table_info *prsp_info; + int ret_code; + int ret_len; + int space_left; + t_u8 *pcurrent; + t_u8 *pbuffer_end; + t_u32 num_scans_done; + + ENTER(); + + num_scans_done = 0; + ret_code = MLAN_STATUS_SUCCESS; + + prsp_info = (wlan_ioctl_get_scan_table_info *) wrq->u.data.pointer; + pcurrent = (t_u8 *) prsp_info->scan_table_entry_buf; + + pbuffer_end = wrq->u.data.pointer + wrq->u.data.length - 1; + space_left = pbuffer_end - pcurrent; + scan_table = (BSSDescriptor_t *) (scan_resp->pscan_table); + + PRINTM(MINFO, "GetScanTable: scan_start req = %d\n", scan_start); + PRINTM(MINFO, "GetScanTable: length avail = %d\n", wrq->u.data.length); + + if (!scan_start) { + PRINTM(MINFO, "GetScanTable: get current BSS Descriptor\n"); + + /* Use to get current association saved descriptor */ + pbss_desc = scan_table; + + ret_code = wlan_get_scan_table_ret_entry(pbss_desc, + &pcurrent, &space_left); + + if (ret_code == MLAN_STATUS_SUCCESS) { + num_scans_done = 1; + } + } else { + scan_start--; + + while (space_left + && (scan_start + num_scans_done < scan_resp->num_in_scan_table) + && (ret_code == MLAN_STATUS_SUCCESS)) { + + pbss_desc = (scan_table + (scan_start + num_scans_done)); + + PRINTM(MINFO, "GetScanTable: get current BSS Descriptor [%d]\n", + scan_start + num_scans_done); + + ret_code = wlan_get_scan_table_ret_entry(pbss_desc, + &pcurrent, &space_left); + + if (ret_code == MLAN_STATUS_SUCCESS) { + num_scans_done++; + } + } + } + + prsp_info->scan_number = num_scans_done; + ret_len = pcurrent - (t_u8 *) wrq->u.data.pointer; + + wrq->u.data.length = ret_len; + + /* Return ret_code (EFAULT or E2BIG) in the case where no scan results were + successfully encoded. */ + LEAVE(); + return (num_scans_done ? MLAN_STATUS_SUCCESS : ret_code); +} + +/** + * @brief Get scan table ioctl + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +static mlan_status +woal_get_scan_table_ioctl(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_scan *scan = NULL; + t_u32 scan_start; + mlan_status status = MLAN_STATUS_SUCCESS; + + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + scan = (mlan_ds_scan *) req->pbuf; + req->req_id = MLAN_IOCTL_SCAN; + req->action = MLAN_ACT_GET; + + /* get the whole command from user */ + if (copy_from_user(&scan_start, wrq->u.data.pointer, sizeof(scan_start))) { + PRINTM(MERROR, "copy from user failed\n"); + ret = -EFAULT; + goto done; + } + if (scan_start) { + scan->sub_command = MLAN_OID_SCAN_NORMAL; + } else { + scan->sub_command = MLAN_OID_SCAN_GET_CURRENT_BSS; + } + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); + if (status == MLAN_STATUS_SUCCESS) { + status = moal_ret_get_scan_table_ioctl(wrq, + &scan->param.scan_resp, + scan_start); + } + done: + if (req && (status != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return status; +} + +/** + * @brief Set user scan + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +static mlan_status +woal_set_user_scan_ioctl(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_scan *scan = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + union iwreq_data wrqu; + moal_handle *handle = priv->phandle; + + ENTER(); + + if (handle->scan_pending_on_block == MTRUE) { + PRINTM(MINFO, "scan already in processing...\n"); + LEAVE(); + return ret; + } + if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->async_sem)) { + PRINTM(MERROR, "Acquire semaphore error, request_scan\n"); + LEAVE(); + return MLAN_STATUS_FAILURE; + } + handle->scan_pending_on_block = MTRUE; + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan) + wrq->u.data.length); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + scan = (mlan_ds_scan *) req->pbuf; + scan->sub_command = MLAN_OID_SCAN_USER_CONFIG; + req->req_id = MLAN_IOCTL_SCAN; + req->action = MLAN_ACT_SET; + + if (copy_from_user(scan->param.user_scan.scan_cfg_buf, + wrq->u.data.pointer, wrq->u.data.length)) { + PRINTM(MINFO, "Copy from user failed\n"); + LEAVE(); + return -EFAULT; + } + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); + if (status == MLAN_STATUS_SUCCESS) { + memset(&wrqu, 0, sizeof(union iwreq_data)); + wireless_send_event(priv->netdev, SIOCGIWSCAN, &wrqu, NULL); + } + handle->scan_pending_on_block = MFALSE; + MOAL_REL_SEMAPHORE(&handle->async_sem); + + done: + if (req && (status != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return status; +} + +/** + * @brief Cmd52 read/write register + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * @return MLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int +woal_cmd52rdwr_ioctl(moal_private * priv, struct iwreq *wrq) +{ + t_u8 rw = 0, func, data = 0; + int buf[3], reg, ret = MLAN_STATUS_SUCCESS; + int data_length = wrq->u.data.length; + + ENTER(); + + if (data_length < 2 || data_length > 3) { + PRINTM(MERROR, "Invalid number of arguments\n"); + ret = -EINVAL; + goto done; + } + + if (copy_from_user(buf, wrq->u.data.pointer, sizeof(int) * data_length)) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + func = (t_u8) buf[0]; + if (func > 7) { + PRINTM(MERROR, "Invalid function number!\n"); + ret = -EINVAL; + goto done; + } + reg = (t_u32) buf[1]; + if (data_length == 2) { + rw = 0; /* CMD52 read */ + PRINTM(MINFO, "Cmd52 read, func=%d, reg=0x%08X\n", func, reg); + } + if (data_length == 3) { + rw = 1; /* CMD52 write */ + data = (t_u8) buf[2]; + PRINTM(MINFO, "Cmd52 write, func=%d, reg=0x%08X, data=0x%02X\n", func, + reg, data); + } + + if (!rw) { + sdio_claim_host(((struct sdio_mmc_card *) priv->phandle->card)->func); + if (func) + data = + sdio_readb(((struct sdio_mmc_card *) priv->phandle->card)->func, + reg, &ret); + else + data = + sdio_f0_readb(((struct sdio_mmc_card *) priv->phandle->card)-> + func, reg, &ret); + sdio_release_host(((struct sdio_mmc_card *) priv->phandle->card)->func); + if (ret) { + PRINTM(MERROR, "sdio_readb: reading register 0x%X failed\n", reg); + goto done; + } + } else { + sdio_claim_host(((struct sdio_mmc_card *) priv->phandle->card)->func); + if (func) + sdio_writeb(((struct sdio_mmc_card *) priv->phandle->card)->func, + data, reg, &ret); + else + sdio_f0_writeb(((struct sdio_mmc_card *) priv->phandle->card)->func, + data, reg, &ret); + sdio_release_host(((struct sdio_mmc_card *) priv->phandle->card)->func); + if (ret) { + PRINTM(MERROR, "sdio_writeb: writing register 0x%X failed\n", reg); + goto done; + } + } + + buf[0] = data; + wrq->u.data.length = 1; + if (copy_to_user(wrq->u.data.pointer, buf, sizeof(int))) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + goto done; + } + + done: + LEAVE(); + return ret; +} + +/** + * @brief Cmd53 read/write register + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * @return MLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int +woal_cmd53rdwr_ioctl(moal_private * priv, struct iwreq *wrq) +{ + t_u8 *buf = NULL; + t_u8 rw, func, mode; + t_u16 blklen = 0, blknum = 0; + int reg = 0, pattern_len = 0, pos = 0, ret = MLAN_STATUS_SUCCESS; + t_u32 total_len = 0; + t_u8 *data = NULL; + + ENTER(); + + if (!(buf = (t_u8 *) kmalloc(WOAL_2K_BYTES, GFP_KERNEL))) { + PRINTM(MERROR, "Cannot allocate buffer for command!\n"); + ret = -EFAULT; + goto done; + } + if (!(data = (t_u8 *) kmalloc(WOAL_2K_BYTES, GFP_KERNEL))) { + PRINTM(MERROR, "Cannot allocate buffer for command!\n"); + ret = -EFAULT; + goto done; + } + if (wrq->u.data.length > WOAL_2K_BYTES) { + PRINTM(MERROR, "Data lengh is too large!\n"); + ret = -EINVAL; + goto done; + } + if (copy_from_user(buf, wrq->u.data.pointer, wrq->u.data.length)) { + PRINTM(MINFO, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + rw = buf[0]; /* read/write (0/1) */ + func = buf[1]; /* func (0/1/2) */ + reg = buf[5]; /* address */ + reg = (reg << 8) + buf[4]; + reg = (reg << 8) + buf[3]; + reg = (reg << 8) + buf[2]; + mode = buf[6]; /* byte mode/block mode (0/1) */ + blklen = buf[8]; /* block size */ + blklen = (blklen << 8) + buf[7]; + blknum = buf[10]; /* block number or byte number */ + blknum = (blknum << 8) + buf[9]; + + if (mode != BYTE_MODE) + mode = BLOCK_MODE; + total_len = (mode == BLOCK_MODE) ? blknum * blklen : blknum; + if (total_len > WOAL_2K_BYTES) { + PRINTM(MERROR, "Total data length is too large!\n"); + ret = -EINVAL; + goto done; + } + PRINTM(MINFO, "CMD53 read/write, func = %d, addr = %#x, mode = %d, " + "block size = %d, block(byte) number = %d\n", + func, reg, mode, blklen, blknum); + + if (!rw) { + sdio_claim_host(((struct sdio_mmc_card *) priv->phandle->card)->func); + if (sdio_readsb + (((struct sdio_mmc_card *) priv->phandle->card)->func, data, reg, + total_len)) + PRINTM(MERROR, "sdio_readsb: reading memory 0x%x failed\n", reg); + sdio_release_host(((struct sdio_mmc_card *) priv->phandle->card)->func); + + if (copy_to_user(wrq->u.data.pointer, data, total_len)) { + PRINTM(MINFO, "Copy to user failed\n"); + ret = -EFAULT; + goto done; + } + wrq->u.data.length = total_len; + } else { + pattern_len = wrq->u.data.length - 11; + if (pattern_len > total_len) + pattern_len = total_len; + memset(data, 0, sizeof(data)); + + /* Copy/duplicate the pattern to data buffer */ + for (pos = 0; pos < total_len; pos++) + data[pos] = buf[11 + (pos % pattern_len)]; + + sdio_claim_host(((struct sdio_mmc_card *) priv->phandle->card)->func); + if (sdio_writesb + (((struct sdio_mmc_card *) priv->phandle->card)->func, reg, data, + total_len)) + PRINTM(MERROR, "sdio_writesb: writing memory 0x%x failed\n", reg); + sdio_release_host(((struct sdio_mmc_card *) priv->phandle->card)->func); + } + + done: + if (buf) + kfree(buf); + if (data) + kfree(data); + LEAVE(); + return ret; +} + +#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR) +/** + * @brief Set SDIO Multi-point aggregation control parameters + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0/MLAN_STATUS_PENDING --success, otherwise fail + */ +static int +woal_do_sdio_mpa_ctrl(moal_private * priv, struct iwreq *wrq) +{ + int data[6], data_length = wrq->u.data.length; + int ret = 0; + mlan_ds_misc_cfg *misc = NULL; + mlan_ioctl_req *req = NULL; + + ENTER(); + + if (sizeof(int) * wrq->u.data.length > sizeof(data)) { + PRINTM(MERROR, "Too many arguments\n"); + ret = -EINVAL; + goto done; + } + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + misc = (mlan_ds_misc_cfg *) req->pbuf; + memset(misc, 0, sizeof(mlan_ds_misc_cfg)); + + misc->sub_command = MLAN_OID_MISC_SDIO_MPA_CTRL; + req->req_id = MLAN_IOCTL_MISC_CFG; + + /* Get the values first, then modify these values if user had modified them + */ + + req->action = MLAN_ACT_GET; + if ((ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) != + MLAN_STATUS_SUCCESS) { + PRINTM(MERROR, "woal_request_ioctl returned %d\n", ret); + ret = -EFAULT; + goto done; + } + + if (data_length == 0) { + data[0] = misc->param.mpa_ctrl.tx_enable; + data[1] = misc->param.mpa_ctrl.rx_enable; + data[2] = misc->param.mpa_ctrl.tx_buf_size; + data[3] = misc->param.mpa_ctrl.rx_buf_size; + data[4] = misc->param.mpa_ctrl.tx_max_ports; + data[5] = misc->param.mpa_ctrl.rx_max_ports; + + PRINTM(MINFO, "Get Param: %d %d %d %d %d %d\n", data[0], data[1], + data[2], data[3], data[4], data[5]); + + if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) { + ret = -EFAULT; + goto done; + } + wrq->u.data.length = sizeof(data) / sizeof(int); + goto done; + } + + if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * data_length)) { + PRINTM(MINFO, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + switch (data_length) { + case 6: + misc->param.mpa_ctrl.rx_max_ports = data[5]; + case 5: + misc->param.mpa_ctrl.tx_max_ports = data[4]; + case 4: + misc->param.mpa_ctrl.rx_buf_size = data[3]; + case 3: + misc->param.mpa_ctrl.tx_buf_size = data[2]; + case 2: + misc->param.mpa_ctrl.rx_enable = data[1]; + case 1: + /* Set cmd */ + req->action = MLAN_ACT_SET; + + PRINTM(MINFO, "Set Param: %d %d %d %d %d %d\n", data[0], data[1], + data[2], data[3], data[4], data[5]); + + misc->param.mpa_ctrl.tx_enable = data[0]; + break; + default: + PRINTM(MERROR, "Default case error\n"); + ret = -EINVAL; + goto done; + } + + if ((ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT) != + MLAN_STATUS_SUCCESS)) { + PRINTM(MERROR, "woal_request_ioctl returned %d\n", ret); + ret = -EFAULT; + goto done; + } + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} +#endif /* SDIO_MULTI_PORT_TX_AGGR || SDIO_MULTI_PORT_RX_AGGR */ + +/** + * @brief Set/Get scan configuration parameters + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_get_scan_cfg(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + int arg_len = 7; + int data[arg_len]; + mlan_ds_scan *scan = NULL; + mlan_ioctl_req *req = NULL; + + ENTER(); + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + if (wrq->u.data.length > arg_len) { + ret = -EINVAL; + goto done; + } + scan = (mlan_ds_scan *) req->pbuf; + scan->sub_command = MLAN_OID_SCAN_CONFIG; + req->req_id = MLAN_IOCTL_SCAN; + memset(data, 0, sizeof(data)); + if (wrq->u.data.length) { + if (copy_from_user + (data, wrq->u.data.pointer, (wrq->u.data.length * sizeof(int)))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + if ((data[0] < 0) || (data[0] > MLAN_SCAN_TYPE_PASSIVE)) { + PRINTM(MERROR, "Invalid argument for scan type\n"); + ret = -EINVAL; + goto done; + } + if ((data[1] < 0) || (data[1] > MLAN_SCAN_MODE_ANY)) { + PRINTM(MERROR, "Invalid argument for scan mode\n"); + ret = -EINVAL; + goto done; + } + if ((data[2] < 0) || (data[2] > MAX_PROBES)) { + PRINTM(MERROR, "Invalid argument for scan probes\n"); + ret = -EINVAL; + goto done; + } + if (((data[3] < 0) || (data[3] > MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME)) || + ((data[4] < 0) || (data[4] > MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME)) || + ((data[5] < 0) || (data[5] > MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME))) { + PRINTM(MERROR, "Invalid argument for scan time\n"); + ret = -EINVAL; + goto done; + } + if ((data[6] < 0) || (data[6] > 1)) { + PRINTM(MERROR, "Invalid argument for extended scan\n"); + ret = -EINVAL; + goto done; + } + req->action = MLAN_ACT_SET; + memcpy(&scan->param.scan_cfg, data, sizeof(data)); + } else + req->action = MLAN_ACT_GET; + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + if (!wrq->u.data.length) { + memcpy(data, &scan->param.scan_cfg, sizeof(data)); + if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) { + ret = -EFAULT; + goto done; + } + wrq->u.data.length = sizeof(data) / sizeof(int); + } + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Set/Get PS configuration parameters + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_get_ps_cfg(moal_private * priv, struct iwreq *wrq) +{ + int data[7], ret = 0; + mlan_ds_pm_cfg *pm_cfg = NULL; + mlan_ioctl_req *req = NULL; + int allowed = 3; + int i = 3; + + ENTER(); + + allowed++; /* For ad-hoc awake period parameter */ + allowed++; /* For beacon missing timeout parameter */ + allowed += 2; /* For delay to PS and PS mode parameters */ + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + if (wrq->u.data.length > allowed) { + ret = -EINVAL; + goto done; + } + pm_cfg = (mlan_ds_pm_cfg *) req->pbuf; + pm_cfg->sub_command = MLAN_OID_PM_CFG_PS_CFG; + req->req_id = MLAN_IOCTL_PM_CFG; + memset(data, 0, sizeof(data)); + if (wrq->u.data.length) { + if (copy_from_user + (data, wrq->u.data.pointer, (wrq->u.data.length * sizeof(int)))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + if ((data[0] < PS_NULL_DISABLE)) { + PRINTM(MERROR, "Invalid argument for PS null interval\n"); + ret = -EINVAL; + goto done; + } + if ((data[1] != MRVDRV_IGNORE_MULTIPLE_DTIM) + && (data[1] != MRVDRV_MATCH_CLOSEST_DTIM) + && ((data[1] < MRVDRV_MIN_MULTIPLE_DTIM) + || (data[1] > MRVDRV_MAX_MULTIPLE_DTIM))) { + PRINTM(MERROR, "Invalid argument for multiple DTIM\n"); + ret = -EINVAL; + goto done; + } + + if ((data[2] < MRVDRV_MIN_LISTEN_INTERVAL) + && (data[2] != MRVDRV_LISTEN_INTERVAL_DISABLE)) { + PRINTM(MERROR, "Invalid argument for listen interval\n"); + ret = -EINVAL; + goto done; + } + + if ((data[i] != SPECIAL_ADHOC_AWAKE_PD) && + ((data[i] < MIN_ADHOC_AWAKE_PD) || + (data[i] > MAX_ADHOC_AWAKE_PD))) { + PRINTM(MERROR, "Invalid argument for adhoc awake period\n"); + ret = -EINVAL; + goto done; + } + i++; + if ((data[i] != DISABLE_BCN_MISS_TO) && + ((data[i] < MIN_BCN_MISS_TO) || (data[i] > MAX_BCN_MISS_TO))) { + PRINTM(MERROR, "Invalid argument for beacon miss timeout\n"); + ret = -EINVAL; + goto done; + } + i++; + if (wrq->u.data.length < allowed - 1) + data[i] = DELAY_TO_PS_UNCHANGED; + else if ((data[i] < MIN_DELAY_TO_PS) || (data[i] > MAX_DELAY_TO_PS)) { + PRINTM(MERROR, "Invalid argument for delay to PS\n"); + ret = -EINVAL; + goto done; + } + i++; + if ((data[i] != PS_MODE_UNCHANGED) && (data[i] != PS_MODE_AUTO) && + (data[i] != PS_MODE_POLL) && (data[i] != PS_MODE_NULL)) { + PRINTM(MERROR, "Invalid argument for PS mode\n"); + ret = -EINVAL; + goto done; + } + i++; + req->action = MLAN_ACT_SET; + memcpy(&pm_cfg->param.ps_cfg, data, + MIN(sizeof(pm_cfg->param.ps_cfg), sizeof(data))); + } else + req->action = MLAN_ACT_GET; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + memcpy(data, &pm_cfg->param.ps_cfg, + MIN((sizeof(int) * allowed), sizeof(pm_cfg->param.ps_cfg))); + if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * allowed)) { + ret = -EFAULT; + goto done; + } + wrq->u.data.length = allowed; + + if (req->action == MLAN_ACT_SET) { + pm_cfg = (mlan_ds_pm_cfg *) req->pbuf; + pm_cfg->sub_command = MLAN_OID_PM_CFG_IEEE_PS; + pm_cfg->param.ps_mode = 1; + req->req_id = MLAN_IOCTL_PM_CFG; + req->action = MLAN_ACT_SET; + woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); + } + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Private IOCTL entry to send an ADDTS TSPEC + * + * Receive a ADDTS command from the application. The command structure + * contains a TSPEC and timeout in milliseconds. The timeout is performed + * in the firmware after the ADDTS command frame is sent. + * + * The TSPEC is received in the API as an opaque block. The firmware will + * send the entire data block, including the bytes after the TSPEC. This + * is done to allow extra IEs to be packaged with the TSPEC in the ADDTS + * action frame. + * + * The IOCTL structure contains two return fields: + * - The firmware command result, which indicates failure and timeouts + * - The IEEE Status code which contains the corresponding value from + * any ADDTS response frame received. + * + * In addition, the opaque TSPEC data block passed in is replaced with the + * TSPEC received in the ADDTS response frame. In case of failure, the + * AP may modify the TSPEC on return and in the case of success, the + * medium time is returned as calculated by the AP. Along with the TSPEC, + * any IEs that are sent in the ADDTS response are also returned and can be + * parsed using the IOCTL length as an indicator of extra elements. + * + * The return value to the application layer indicates a driver execution + * success or failure. A successful return could still indicate a firmware + * failure or AP negotiation failure via the commandResult field copied + * back to the application. + * + * @param priv Pointer to the mlan_private driver data struct + * @param wrq A pointer to iwreq structure containing the + * wlan_ioctl_wmm_addts_req_t struct for this ADDTS request + * + * @return 0 if successful; IOCTL error code otherwise + */ +static int +woal_wmm_addts_req_ioctl(moal_private * priv, struct iwreq *wrq) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_wmm_cfg *cfg = NULL; + wlan_ioctl_wmm_addts_req_t addts_ioctl; + int ret = 0; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + req->req_id = MLAN_IOCTL_WMM_CFG; + cfg = (mlan_ds_wmm_cfg *) req->pbuf; + cfg->sub_command = MLAN_OID_WMM_CFG_ADDTS; + + memset(&addts_ioctl, 0x00, sizeof(addts_ioctl)); + + if (wrq->u.data.length) { + if (copy_from_user(&addts_ioctl, wrq->u.data.pointer, + MIN(wrq->u.data.length, sizeof(addts_ioctl)))) { + PRINTM(MERROR, "TSPEC: ADDTS copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + cfg->param.addts.timeout = addts_ioctl.timeout_ms; + cfg->param.addts.ie_data_len = (t_u8) addts_ioctl.ie_data_len; + + memcpy(cfg->param.addts.ie_data, + addts_ioctl.ie_data, cfg->param.addts.ie_data_len); + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, + MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + addts_ioctl.cmd_result = cfg->param.addts.result; + addts_ioctl.ieee_status_code = (t_u8) cfg->param.addts.status_code; + addts_ioctl.ie_data_len = cfg->param.addts.ie_data_len; + + memcpy(addts_ioctl.ie_data, + cfg->param.addts.ie_data, cfg->param.addts.ie_data_len); + + wrq->u.data.length = (sizeof(addts_ioctl) + - sizeof(addts_ioctl.ie_data) + + cfg->param.addts.ie_data_len); + + if (copy_to_user(wrq->u.data.pointer, &addts_ioctl, wrq->u.data.length)) { + PRINTM(MERROR, "TSPEC: ADDTS copy to user failed\n"); + ret = -EFAULT; + goto done; + } + } + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Private IOCTL entry to send a DELTS TSPEC + * + * Receive a DELTS command from the application. The command structure + * contains a TSPEC and reason code along with space for a command result + * to be returned. The information is packaged is sent to the wlan_cmd.c + * firmware command prep and send routines for execution in the firmware. + * + * The reason code is not used for WMM implementations but is indicated in + * the 802.11e specification. + * + * The return value to the application layer indicates a driver execution + * success or failure. A successful return could still indicate a firmware + * failure via the cmd_result field copied back to the application. + * + * @param priv Pointer to the mlan_private driver data struct + * @param wrq A pointer to iwreq structure containing the + * wlan_ioctl_wmm_delts_req_t struct for this DELTS request + * + * @return 0 if successful; IOCTL error code otherwise + */ +static int +woal_wmm_delts_req_ioctl(moal_private * priv, struct iwreq *wrq) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_wmm_cfg *cfg = NULL; + wlan_ioctl_wmm_delts_req_t delts_ioctl; + int ret = 0; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + req->req_id = MLAN_IOCTL_WMM_CFG; + cfg = (mlan_ds_wmm_cfg *) req->pbuf; + cfg->sub_command = MLAN_OID_WMM_CFG_DELTS; + + memset(&delts_ioctl, 0x00, sizeof(delts_ioctl)); + + if (wrq->u.data.length) { + if (copy_from_user(&delts_ioctl, wrq->u.data.pointer, + MIN(wrq->u.data.length, sizeof(delts_ioctl)))) { + PRINTM(MERROR, "TSPEC: DELTS copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + cfg->param.delts.status_code = (t_u32) delts_ioctl.ieee_reason_code; + cfg->param.delts.ie_data_len = (t_u8) delts_ioctl.ie_data_len; + + memcpy(cfg->param.delts.ie_data, + delts_ioctl.ie_data, cfg->param.delts.ie_data_len); + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, + MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + /* Return the firmware command result back to the application layer */ + delts_ioctl.cmd_result = cfg->param.delts.result; + wrq->u.data.length = sizeof(delts_ioctl); + + if (copy_to_user(wrq->u.data.pointer, &delts_ioctl, wrq->u.data.length)) { + PRINTM(MERROR, "TSPEC: DELTS copy to user failed\n"); + ret = -EFAULT; + goto done; + } + } + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Private IOCTL entry to get/set a specified AC Queue's parameters + * + * Receive a AC Queue configuration command which is used to get, set, or + * default the parameters associated with a specific WMM AC Queue. + * + * @param priv Pointer to the mlan_private driver data struct + * @param wrq A pointer to iwreq structure containing the + * wlan_ioctl_wmm_queue_config_t struct + * + * @return 0 if successful; IOCTL error code otherwise + */ +static int +woal_wmm_queue_config_ioctl(moal_private * priv, struct iwreq *wrq) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_wmm_cfg *pwmm = NULL; + mlan_ds_wmm_queue_config *pqcfg = NULL; + wlan_ioctl_wmm_queue_config_t qcfg_ioctl; + int ret = 0; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + req->req_id = MLAN_IOCTL_WMM_CFG; + pwmm = (mlan_ds_wmm_cfg *) req->pbuf; + pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_CONFIG; + + memset(&qcfg_ioctl, 0x00, sizeof(qcfg_ioctl)); + pqcfg = (mlan_ds_wmm_queue_config *) & pwmm->param.q_cfg; + + if (wrq->u.data.length) { + if (copy_from_user(&qcfg_ioctl, wrq->u.data.pointer, + MIN(wrq->u.data.length, sizeof(qcfg_ioctl)))) { + PRINTM(MERROR, "QCONFIG: copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + pqcfg->action = qcfg_ioctl.action; + pqcfg->access_category = qcfg_ioctl.access_category; + pqcfg->msdu_lifetime_expiry = qcfg_ioctl.msdu_lifetime_expiry; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, + MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + memset(&qcfg_ioctl, 0x00, sizeof(qcfg_ioctl)); + qcfg_ioctl.action = pqcfg->action; + qcfg_ioctl.access_category = pqcfg->access_category; + qcfg_ioctl.msdu_lifetime_expiry = pqcfg->msdu_lifetime_expiry; + wrq->u.data.length = sizeof(qcfg_ioctl); + + if (copy_to_user(wrq->u.data.pointer, &qcfg_ioctl, wrq->u.data.length)) { + PRINTM(MERROR, "QCONFIG: copy to user failed\n"); + ret = -EFAULT; + goto done; + } + } + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Private IOCTL entry to get and start/stop queue stats on a WMM AC + * + * Receive a AC Queue statistics command from the application for a specific + * WMM AC. The command can: + * - Turn stats on + * - Turn stats off + * - Collect and clear the stats + * + * @param priv Pointer to the moal_private driver data struct + * @param wrq A pointer to iwreq structure containing the + * wlan_ioctl_wmm_queue_stats_t struct + * + * @return 0 if successful; IOCTL error code otherwise + */ +static int +woal_wmm_queue_stats_ioctl(moal_private * priv, struct iwreq *wrq) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_wmm_cfg *pwmm = NULL; + mlan_ds_wmm_queue_stats *pqstats = NULL; + wlan_ioctl_wmm_queue_stats_t qstats_ioctl; + int ret = 0; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + req->req_id = MLAN_IOCTL_WMM_CFG; + pwmm = (mlan_ds_wmm_cfg *) req->pbuf; + pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_STATS; + + memset(&qstats_ioctl, 0x00, sizeof(qstats_ioctl)); + pqstats = (mlan_ds_wmm_queue_stats *) & pwmm->param.q_stats; + + if (wrq->u.data.length) { + if (copy_from_user(&qstats_ioctl, wrq->u.data.pointer, + MIN(wrq->u.data.length, sizeof(qstats_ioctl)))) { + PRINTM(MERROR, "QSTATS: copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + memcpy((void *) pqstats, (void *) &qstats_ioctl, sizeof(qstats_ioctl)); + PRINTM(MINFO, "QSTATS: IOCTL [%d,%d]\n", qstats_ioctl.action, + qstats_ioctl.user_priority); + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, + MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + memset(&qstats_ioctl, 0x00, sizeof(qstats_ioctl)); + memcpy((void *) &qstats_ioctl, (void *) pqstats, sizeof(qstats_ioctl)); + wrq->u.data.length = sizeof(qstats_ioctl); + + if (copy_to_user + (wrq->u.data.pointer, &qstats_ioctl, wrq->u.data.length)) { + PRINTM(MERROR, "QSTATS: copy to user failed\n"); + ret = -EFAULT; + goto done; + } + } + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Private IOCTL entry to get the status of the WMM queues + * + * Return the following information for each WMM AC: + * - WMM IE Acm Required + * - Firmware Flow Required + * - Firmware Flow Established + * - Firmware Queue Enabled + * - Firmware Delivery Enabled + * - Firmware Trigger Enabled + * + * @param priv Pointer to the moal_private driver data struct + * @param wrq A pointer to iwreq structure containing the + * wlan_ioctl_wmm_queue_status_t struct for request + * + * @return 0 if successful; IOCTL error code otherwise + */ +static int +woal_wmm_queue_status_ioctl(moal_private * priv, struct iwreq *wrq) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_wmm_cfg *pwmm = NULL; + wlan_ioctl_wmm_queue_status_t qstatus_ioctl; + int ret = 0; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + req->req_id = MLAN_IOCTL_WMM_CFG; + pwmm = (mlan_ds_wmm_cfg *) req->pbuf; + pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_STATUS; + + if (wrq->u.data.length == sizeof(qstatus_ioctl)) { + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + memset(&qstatus_ioctl, 0x00, sizeof(qstatus_ioctl)); + memcpy((void *) &qstatus_ioctl, (void *) &pwmm->param.q_status, + sizeof(qstatus_ioctl)); + wrq->u.data.length = sizeof(qstatus_ioctl); + } else { + wrq->u.data.length = 0; + } + + if (copy_to_user(wrq->u.data.pointer, &qstatus_ioctl, wrq->u.data.length)) { + PRINTM(MERROR, "QSTATUS: copy to user failed\n"); + ret = -EFAULT; + goto done; + } + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Private IOCTL entry to get the status of the WMM Traffic Streams + * + * @param priv Pointer to the moal_private driver data struct + * @param wrq A pointer to iwreq structure containing the + * wlan_ioctl_wmm_ts_status_t struct for request + * + * @return 0 if successful; IOCTL error code otherwise + */ +static int +woal_wmm_ts_status_ioctl(moal_private * priv, struct iwreq *wrq) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_wmm_cfg *pwmm = NULL; + wlan_ioctl_wmm_ts_status_t ts_status_ioctl; + int ret = 0; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + req->req_id = MLAN_IOCTL_WMM_CFG; + pwmm = (mlan_ds_wmm_cfg *) req->pbuf; + pwmm->sub_command = MLAN_OID_WMM_CFG_TS_STATUS; + + memset(&ts_status_ioctl, 0x00, sizeof(ts_status_ioctl)); + + if (wrq->u.data.length == sizeof(ts_status_ioctl)) { + if (copy_from_user(&ts_status_ioctl, wrq->u.data.pointer, + MIN(wrq->u.data.length, sizeof(ts_status_ioctl)))) { + PRINTM(MERROR, "TS_STATUS: copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + memset(&pwmm->param.ts_status, 0x00, sizeof(ts_status_ioctl)); + pwmm->param.ts_status.tid = ts_status_ioctl.tid; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, + MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + memset(&ts_status_ioctl, 0x00, sizeof(ts_status_ioctl)); + memcpy((void *) &ts_status_ioctl, (void *) &pwmm->param.ts_status, + sizeof(ts_status_ioctl)); + wrq->u.data.length = sizeof(ts_status_ioctl); + } else { + wrq->u.data.length = 0; + } + + if (copy_to_user(wrq->u.data.pointer, &ts_status_ioctl, wrq->u.data.length)) { + PRINTM(MERROR, "TS_STATUS: copy to user failed\n"); + ret = -EFAULT; + goto done; + } + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Private IOCTL entry to get the By-passed TX packet from upper layer + * + * @param priv Pointer to the moal_private driver data struct + * @param wrq A pointer to iwreq structure containing the packet + * + * @return 0 if successful; IOCTL error code otherwise + */ +static int +woal_bypassed_packet_ioctl(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + struct sk_buff *skb = NULL; + struct ethhdr *eth; + t_u16 moreLen = 0, copyLen = 0; + ENTER(); + +#define MLAN_BYPASS_PKT_EXTRA_OFFSET (4) + + copyLen = wrq->u.data.length; + moreLen = MLAN_MIN_DATA_HEADER_LEN + MLAN_BYPASS_PKT_EXTRA_OFFSET + + sizeof(mlan_buffer); + + skb = alloc_skb(copyLen + moreLen, GFP_KERNEL); + if (skb == NULL) { + PRINTM(MERROR, "kmalloc no memory !!\n"); + LEAVE(); + return -ENOMEM; + } + + skb_reserve(skb, moreLen); + + if (copy_from_user(skb_put(skb, copyLen), wrq->u.data.pointer, copyLen)) { + PRINTM(MERROR, "PortBlock: copy from user failed\n"); + dev_kfree_skb_any(skb); + ret = -EFAULT; + goto done; + } + + eth = (struct ethhdr *) skb->data; + eth->h_proto = __constant_htons(eth->h_proto); + skb->dev = priv->netdev; + + HEXDUMP("Bypass TX Data", skb->data, MIN(skb->len, 100)); + + woal_hard_start_xmit(skb, priv->netdev); + done: + LEAVE(); + return ret; +} + +/** + * @brief Set/Get auth type + * + * @param priv Pointer to the moal_private driver data struct + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_auth_type(moal_private * priv, struct iwreq *wrq) +{ + int auth_type; + t_u32 auth_mode; + int ret = 0; + + ENTER(); + if (wrq->u.data.length == 0) { + if (MLAN_STATUS_SUCCESS != + woal_get_auth_mode(priv, MOAL_IOCTL_WAIT, &auth_mode)) { + ret = -EFAULT; + goto done; + } + auth_type = auth_mode; + if (copy_to_user(wrq->u.data.pointer, &auth_type, sizeof(auth_type))) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + goto done; + } + wrq->u.data.length = 1; + } else { + if (copy_from_user(&auth_type, wrq->u.data.pointer, sizeof(auth_type))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + PRINTM(MINFO, "SET: auth_type %d\n", auth_type); + if (((auth_type < MLAN_AUTH_MODE_OPEN) || + (auth_type > MLAN_AUTH_MODE_SHARED)) + && (auth_type != MLAN_AUTH_MODE_AUTO)) { + ret = -EINVAL; + goto done; + } + auth_mode = auth_type; + if (MLAN_STATUS_SUCCESS != + woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_mode)) { + ret = -EFAULT; + goto done; + } + } + done: + LEAVE(); + return ret; +} + +/** + * @brief Set/Get Port Control mode + * + * @param priv Pointer to the moal_private driver data struct + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_port_ctrl(moal_private * priv, struct iwreq *wrq) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_sec_cfg *sec = NULL; + int ret = 0; + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + sec = (mlan_ds_sec_cfg *) req->pbuf; + sec->sub_command = MLAN_OID_SEC_CFG_PORT_CTRL_ENABLED; + req->req_id = MLAN_IOCTL_SEC_CFG; + + if (wrq->u.data.length) { + if (copy_from_user(&sec->param.port_ctrl_enabled, + wrq->u.data.pointer, sizeof(int)) != 0) { + PRINTM(MERROR, "port_ctrl:Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + req->action = MLAN_ACT_SET; + } else { + req->action = MLAN_ACT_GET; + } + + /* Send IOCTL request to MLAN */ + if (woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT) != MLAN_STATUS_SUCCESS) { + ret = -EFAULT; + goto done; + } + + if (!wrq->u.data.length) { + if (copy_to_user(wrq->u.data.pointer, &sec->param.port_ctrl_enabled, + sizeof(int))) { + PRINTM(MERROR, "port_ctrl:Copy to user failed\n"); + ret = -EFAULT; + goto done; + } + wrq->u.data.length = 1; + } + + done: + if (req) + kfree(req); + + LEAVE(); + return ret; +} + +#if defined(DFS_TESTING_SUPPORT) +/** + * @brief Set/Get DFS Testing settings + * + * @param priv Pointer to the moal_private driver data struct + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_dfs_testing(moal_private * priv, struct iwreq *wrq) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_11h_cfg *ds_11hcfg = NULL; + int ret = 0; + int data[4]; + int data_length = wrq->u.data.length; + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + ds_11hcfg = (mlan_ds_11h_cfg *) req->pbuf; + ds_11hcfg->sub_command = MLAN_OID_11H_DFS_TESTING; + req->req_id = MLAN_IOCTL_11H_CFG; + + if (!data_length) { + req->action = MLAN_ACT_GET; + } else if (data_length == 4) { + if (copy_from_user + (data, wrq->u.data.pointer, sizeof(int) * data_length)) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + if ((unsigned) data[0] > 0xFFFF) { + PRINTM(MERROR, "The maximum user CAC is 65535 msec.\n"); + ret = -EINVAL; + goto done; + } + if ((unsigned) data[1] > 0xFFFF) { + PRINTM(MERROR, "The maximum user NOP is 65535 sec.\n"); + ret = -EINVAL; + goto done; + } + if ((unsigned) data[3] > 0xFF) { + PRINTM(MERROR, "The maximum user fixed channel is 255.\n"); + ret = -EINVAL; + goto done; + } + ds_11hcfg->param.dfs_testing.usr_cac_period_msec = (t_u16) data[0]; + ds_11hcfg->param.dfs_testing.usr_nop_period_sec = (t_u16) data[1]; + ds_11hcfg->param.dfs_testing.usr_no_chan_change = data[2] ? 1 : 0; + ds_11hcfg->param.dfs_testing.usr_fixed_new_chan = (t_u8) data[3]; + priv->phandle->cac_period_jiffies = (t_u16) data[0] * HZ / 1000; + req->action = MLAN_ACT_SET; + } else { + PRINTM(MERROR, "Invalid number of args!\n"); + ret = -EINVAL; + goto done; + } + + /* Send IOCTL request to MLAN */ + if (woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT) != MLAN_STATUS_SUCCESS) { + ret = -EFAULT; + goto done; + } + + if (!data_length) { + data[0] = ds_11hcfg->param.dfs_testing.usr_cac_period_msec; + data[1] = ds_11hcfg->param.dfs_testing.usr_nop_period_sec; + data[2] = ds_11hcfg->param.dfs_testing.usr_no_chan_change; + data[3] = ds_11hcfg->param.dfs_testing.usr_fixed_new_chan; + if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int) * 4)) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + goto done; + } + wrq->u.data.length = 4; + } + + done: + if (req) + kfree(req); + + LEAVE(); + return ret; +} +#endif /* DFS_SUPPORT && DFS_TESTING_SUPPORT */ + +/** + * @brief Set/Get Mgmt Frame passthru mask + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 -- success, otherwise fail + */ +static int +woal_mgmt_frame_passthru_ctrl(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0, data_length = wrq->u.data.length; + mlan_ioctl_req *req = NULL; + mlan_ds_misc_cfg *mgmt_cfg = NULL; + int mask = 0; + + ENTER(); + + if (data_length > 1) { + PRINTM(MERROR, "Invalid no of arguments!\n"); + ret = -EINVAL; + goto done; + } + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + mgmt_cfg = (mlan_ds_misc_cfg *) req->pbuf; + req->req_id = MLAN_IOCTL_MISC_CFG; + mgmt_cfg->sub_command = MLAN_OID_MISC_RX_MGMT_IND; + + if (data_length) { /* SET */ + if (copy_from_user(&mask, wrq->u.data.pointer, sizeof(int))) { + PRINTM(MERROR, "copy from user failed\n"); + ret = -EFAULT; + goto done; + } + mgmt_cfg->param.mgmt_subtype_mask = mask; + req->action = MLAN_ACT_SET; + } else { + req->action = MLAN_ACT_GET; + } + + /* Send IOCTL request to MLAN */ + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + mask = mgmt_cfg->param.mgmt_subtype_mask; + if (copy_to_user(wrq->u.data.pointer, &mask, sizeof(int))) { + ret = -EFAULT; + goto done; + } + wrq->u.data.length = 1; + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Set/Get Tx/Rx antenna + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_get_tx_rx_ant(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + mlan_ds_radio_cfg *radio = NULL; + mlan_ioctl_req *req = NULL; + int data[2] = { 0 }; + + ENTER(); + + if (wrq->u.data.length > 2) { + PRINTM(MERROR, "Invalid number of argument!\n"); + ret = -EFAULT; + goto done; + } + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + radio = (mlan_ds_radio_cfg *) req->pbuf; + radio->sub_command = MLAN_OID_ANT_CFG; + req->req_id = MLAN_IOCTL_RADIO_CFG; + if (wrq->u.data.length) { + if (copy_from_user(data, wrq->u.data.pointer, sizeof(data))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + radio->param.ant_cfg.tx_antenna = data[0]; + radio->param.ant_cfg.rx_antenna = data[0]; + if (wrq->u.data.length == 2) + radio->param.ant_cfg.rx_antenna = data[1]; + req->action = MLAN_ACT_SET; + } else + req->action = MLAN_ACT_GET; + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + if (!wrq->u.data.length) { + wrq->u.data.length = 1; + data[0] = radio->param.ant_cfg.tx_antenna; + data[1] = radio->param.ant_cfg.rx_antenna; + if (data[0] && data[1] && (data[0] != data[1])) + wrq->u.data.length = 2; + if (copy_to_user(wrq->u.data.pointer, data, sizeof(data))) { + ret = -EFAULT; + goto done; + } + } + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/******************************************************** + Global Functions +********************************************************/ +/** + * @brief ioctl function - entry point + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @param cmd Command + * + * @return 0 --success, otherwise fail + */ +int +woal_wext_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + struct iwreq *wrq = (struct iwreq *) req; + int ret = 0; + + if (!IS_STA_WEXT(cfg80211_wext)) + return -EOPNOTSUPP; + + ENTER(); + + PRINTM(MINFO, "woal_wext_do_ioctl: ioctl cmd = 0x%x\n", cmd); + switch (cmd) { + case WOAL_SETONEINT_GETWORDCHAR: + switch (wrq->u.data.flags) { + case WOAL_VERSION: /* Get driver version */ + ret = woal_get_driver_version(priv, req); + break; + case WOAL_VEREXT: /* Get extended driver version */ + ret = woal_get_driver_verext(priv, req); + break; + default: + ret = -EOPNOTSUPP; + break; + } + break; + case WOAL_SETNONE_GETNONE: + switch (wrq->u.data.flags) { + case WOAL_WARMRESET: + ret = woal_warm_reset(priv); + break; + case WOAL_11D_CLR_CHAN_TABLE: + ret = woal_11d_clr_chan_table(priv, wrq); + break; + default: + ret = -EOPNOTSUPP; + break; + } + break; + case WOAL_SETONEINT_GETONEINT: + switch (wrq->u.data.flags) { + case WOAL_SET_GET_TXRATE: + ret = woal_set_get_txrate(priv, wrq); + break; + case WOAL_SET_GET_REGIONCODE: + ret = woal_set_get_regioncode(priv, wrq); + break; + case WOAL_SET_RADIO: + ret = woal_set_get_radio(priv, wrq); + break; + case WOAL_WMM_ENABLE: + ret = woal_wmm_enable_ioctl(priv, wrq); + break; + case WOAL_11D_ENABLE: + ret = woal_11d_enable_ioctl(priv, wrq); + break; + case WOAL_SET_GET_QOS_CFG: + ret = woal_set_get_qos_cfg(priv, wrq); + break; +#if defined(REASSOCIATION) + case WOAL_SET_GET_REASSOC: + ret = woal_set_get_reassoc(priv, wrq); + break; +#endif /* REASSOCIATION */ + case WOAL_TXBUF_CFG: + ret = woal_txbuf_cfg(priv, wrq); + break; + case WOAL_SET_GET_WWS_CFG: + ret = woal_wws_cfg(priv, wrq); + break; + case WOAL_SLEEP_PD: + ret = woal_sleep_pd(priv, wrq); + break; + case WOAL_AUTH_TYPE: + ret = woal_auth_type(priv, wrq); + break; + case WOAL_PORT_CTRL: + ret = woal_port_ctrl(priv, wrq); + break; +#if defined(WIFI_DIRECT_SUPPORT) +#if defined(STA_SUPPORT) && defined(UAP_SUPPORT) + case WOAL_SET_GET_BSS_ROLE: + ret = woal_set_get_bss_role(priv, wrq); + break; +#endif +#endif + case WOAL_SET_GET_11H_LOCAL_PWR_CONSTRAINT: + ret = woal_set_get_11h_local_pwr_constraint(priv, wrq); + break; + case WOAL_HT_STREAM_CFG: + ret = woal_ht_stream_cfg_ioctl(priv, wrq); + break; + case WOAL_MAC_CONTROL: + ret = woal_mac_control_ioctl(priv, wrq); + break; + case WOAL_THERMAL: + ret = woal_thermal_ioctl(priv, wrq); + break; + default: + ret = -EOPNOTSUPP; + break; + } + break; + + case WOAL_SET_GET_SIXTEEN_INT: + switch ((int) wrq->u.data.flags) { + case WOAL_TX_POWERCFG: + ret = woal_tx_power_cfg(priv, wrq); + break; +#ifdef DEBUG_LEVEL1 + case WOAL_DRV_DBG: + ret = woal_drv_dbg(priv, wrq); + break; +#endif + case WOAL_BEACON_INTERVAL: + ret = woal_beacon_interval(priv, wrq); + break; + case WOAL_ATIM_WINDOW: + ret = woal_atim_window(priv, wrq); + break; + case WOAL_SIGNAL: + ret = woal_get_signal(priv, wrq); + break; + case WOAL_DEEP_SLEEP: + ret = woal_deep_sleep_ioctl(priv, wrq); + break; + case WOAL_11N_TX_CFG: + ret = woal_11n_tx_cfg(priv, wrq); + break; + case WOAL_11N_AMSDU_AGGR_CTRL: + ret = woal_11n_amsdu_aggr_ctrl(priv, wrq); + break; + case WOAL_11N_HTCAP_CFG: + ret = woal_11n_htcap_cfg(priv, wrq); + break; + case WOAL_PRIO_TBL: + ret = woal_11n_prio_tbl(priv, wrq); + break; + case WOAL_ADDBA_UPDT: + ret = woal_addba_para_updt(priv, wrq); + break; + case WOAL_ADDBA_REJECT: + ret = woal_addba_reject(priv, wrq); + break; + case WOAL_TX_BF_CAP: + ret = woal_tx_bf_cap_ioctl(priv, wrq); + break; + case WOAL_HS_CFG: + ret = woal_hs_cfg(priv, wrq, MTRUE); + break; + case WOAL_HS_SETPARA: + ret = woal_hs_setpara(priv, wrq); + break; + case WOAL_REG_READ_WRITE: + ret = woal_reg_read_write(priv, wrq); + break; + case WOAL_INACTIVITY_TIMEOUT_EXT: + ret = woal_inactivity_timeout_ext(priv, wrq); + break; + case WOAL_SDIO_CLOCK: + ret = woal_sdio_clock_ioctl(priv, wrq); + break; + case WOAL_CMD_52RDWR: + ret = woal_cmd52rdwr_ioctl(priv, wrq); + break; + case WOAL_BAND_CFG: + ret = woal_band_cfg(priv, wrq); + break; + case WOAL_SCAN_CFG: + ret = woal_set_get_scan_cfg(priv, wrq); + break; + case WOAL_PS_CFG: + ret = woal_set_get_ps_cfg(priv, wrq); + break; + case WOAL_MEM_READ_WRITE: + ret = woal_mem_read_write(priv, wrq); + break; +#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR) + case WOAL_SDIO_MPA_CTRL: + ret = woal_do_sdio_mpa_ctrl(priv, wrq); + break; +#endif + case WOAL_SLEEP_PARAMS: + ret = woal_sleep_params_ioctl(priv, wrq); + break; +#if defined(DFS_TESTING_SUPPORT) + case WOAL_DFS_TESTING: + ret = woal_dfs_testing(priv, wrq); + break; +#endif + case WOAL_MGMT_FRAME_CTRL: + ret = woal_mgmt_frame_passthru_ctrl(priv, wrq); + break; + case WOAL_SET_GET_TX_RX_ANT: + ret = woal_set_get_tx_rx_ant(priv, wrq); + break; + default: + ret = -EINVAL; + break; + } + break; + + case WOALGETLOG: + ret = woal_get_log(priv, wrq); + break; + + case WOAL_SET_GET_256_CHAR: + switch (wrq->u.data.flags) { + case WOAL_PASSPHRASE: + ret = woal_passphrase(priv, wrq); + break; + case WOAL_ADHOC_AES: + ret = woal_adhoc_aes_ioctl(priv, wrq); + break; + case WOAL_WMM_QUEUE_STATUS: + ret = woal_wmm_queue_status_ioctl(priv, wrq); + break; + + case WOAL_WMM_TS_STATUS: + ret = woal_wmm_ts_status_ioctl(priv, wrq); + break; + case WOAL_IP_ADDRESS: + ret = woal_set_get_ip_addr(priv, wrq); + break; + case WOAL_TX_BF_CFG: + ret = woal_tx_bf_cfg_ioctl(priv, wrq); + break; + default: + ret = -EINVAL; + break; + } + break; + + case WOAL_SETADDR_GETNONE: + switch ((int) wrq->u.data.flags) { + case WOAL_DEAUTH: + ret = woal_deauth(priv, wrq); + break; + default: + ret = -EINVAL; + break; + } + break; + + case WOAL_SETNONE_GETTWELVE_CHAR: + /* + * We've not used IW_PRIV_TYPE_FIXED so sub-ioctl number is + * in flags of iwreq structure, otherwise it will be in + * mode member of iwreq structure. + */ + switch ((int) wrq->u.data.flags) { + case WOAL_WPS_SESSION: + ret = woal_wps_cfg_ioctl(priv, wrq); + break; + default: + ret = -EINVAL; + break; + } + break; + case WOAL_SETNONE_GET_FOUR_INT: + switch ((int) wrq->u.data.flags) { + case WOAL_DATA_RATE: + ret = woal_get_txrx_rate(priv, wrq); + break; + case WOAL_ESUPP_MODE: + ret = woal_get_esupp_mode(priv, wrq); + break; + default: + ret = -EINVAL; + break; + } + break; + + case WOAL_SET_GET_64_INT: + switch ((int) wrq->u.data.flags) { + case WOAL_ECL_SYS_CLOCK: + ret = woal_ecl_sys_clock(priv, wrq); + break; + } + + break; + + case WOAL_HOST_CMD: + ret = woal_host_command(priv, wrq); + break; + case WOAL_ARP_FILTER: + ret = woal_arp_filter(priv, wrq); + break; + case WOAL_SET_INTS_GET_CHARS: + switch ((int) wrq->u.data.flags) { + case WOAL_READ_EEPROM: + ret = woal_read_eeprom(priv, wrq); + break; + } + break; + case WOAL_SET_GET_2K_BYTES: + switch ((int) wrq->u.data.flags) { + case WOAL_CMD_53RDWR: + ret = woal_cmd53rdwr_ioctl(priv, wrq); + break; + case WOAL_SET_USER_SCAN: + ret = woal_set_user_scan_ioctl(priv, wrq); + break; + case WOAL_GET_SCAN_TABLE: + ret = woal_get_scan_table_ioctl(priv, wrq); + break; + case WOAL_WMM_ADDTS: + ret = woal_wmm_addts_req_ioctl(priv, wrq); + break; + case WOAL_WMM_DELTS: + ret = woal_wmm_delts_req_ioctl(priv, wrq); + break; + case WOAL_WMM_QUEUE_CONFIG: + ret = woal_wmm_queue_config_ioctl(priv, wrq); + break; + case WOAL_WMM_QUEUE_STATS: + ret = woal_wmm_queue_stats_ioctl(priv, wrq); + break; + case WOAL_BYPASSED_PACKET: + ret = woal_bypassed_packet_ioctl(priv, wrq); + break; + default: + ret = -EINVAL; + break; + } + break; + +#ifdef UAP_WEXT + case WOAL_FROYO_START: + break; + case WOAL_FROYO_WL_FW_RELOAD: + break; + case WOAL_FROYO_STOP: + if (IS_UAP_WEXT(cfg80211_wext) && MLAN_STATUS_SUCCESS != + woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL)) { + ret = -EFAULT; + } + break; +#endif + default: + ret = -EINVAL; + break; + } + + LEAVE(); + return ret; +} + +/** + * @brief Get mode + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option (MOAL_WAIT or MOAL_NO_WAIT) + * + * @return Wireless mode + */ +t_u32 +woal_get_mode(moal_private * priv, t_u8 wait_option) +{ + int ret = 0; + mlan_ds_bss *bss = NULL; + mlan_ioctl_req *req = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + t_u32 mode = priv->w_stats.status; + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + bss = (mlan_ds_bss *) req->pbuf; + bss->sub_command = MLAN_OID_BSS_MODE; + req->req_id = MLAN_IOCTL_BSS; + req->action = MLAN_ACT_GET; + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, wait_option); + if (status == MLAN_STATUS_SUCCESS) { + switch (bss->param.bss_mode) { + case MLAN_BSS_MODE_INFRA: + mode = IW_MODE_INFRA; + break; + case MLAN_BSS_MODE_IBSS: + mode = IW_MODE_ADHOC; + break; + default: + mode = IW_MODE_AUTO; + break; + } + } + done: + if (req && (status != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return mode; +} + +/** + * @brief Get statistics information + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * @param stats A pointer to mlan_ds_get_stats structure + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_get_stats_info(moal_private * priv, t_u8 wait_option, + mlan_ds_get_stats * stats) +{ + int ret = 0; + mlan_ds_get_info *info = NULL; + mlan_ioctl_req *req = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + info = (mlan_ds_get_info *) req->pbuf; + info->sub_command = MLAN_OID_GET_STATS; + req->req_id = MLAN_IOCTL_GET_INFO; + req->action = MLAN_ACT_GET; + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, wait_option); + if (status == MLAN_STATUS_SUCCESS) { + if (stats) + memcpy(stats, &info->param.stats, sizeof(mlan_ds_get_stats)); + priv->w_stats.discard.fragment = info->param.stats.fcs_error; + priv->w_stats.discard.retries = info->param.stats.retry; + priv->w_stats.discard.misc = info->param.stats.ack_failure; + } + done: + if (req && (status != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return status; +} + +/** + * @brief Get data rates + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * @param m_rates A pointer to moal_802_11_rates structure + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_get_data_rates(moal_private * priv, t_u8 wait_option, + moal_802_11_rates * m_rates) +{ + int ret = 0; + mlan_ds_rate *rate = NULL; + mlan_ioctl_req *req = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + rate = (mlan_ds_rate *) req->pbuf; + rate->sub_command = MLAN_OID_SUPPORTED_RATES; + req->req_id = MLAN_IOCTL_RATE; + req->action = MLAN_ACT_GET; + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, wait_option); + if (status == MLAN_STATUS_SUCCESS) { + if (m_rates) + m_rates->num_of_rates = + woal_copy_rates(m_rates->rates, m_rates->num_of_rates, + rate->param.rates, MLAN_SUPPORTED_RATES); + } + done: + if (req && (status != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return status; +} + +/** + * @brief Get channel list + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * @param chan_list A pointer to mlan_chan_list structure + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_get_channel_list(moal_private * priv, t_u8 wait_option, + mlan_chan_list * chan_list) +{ + int ret = 0; + mlan_ds_bss *bss = NULL; + mlan_ioctl_req *req = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + bss = (mlan_ds_bss *) req->pbuf; + bss->sub_command = MLAN_OID_BSS_CHANNEL_LIST; + req->req_id = MLAN_IOCTL_BSS; + req->action = MLAN_ACT_GET; + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, wait_option); + if (status == MLAN_STATUS_SUCCESS) { + if (chan_list) { + memcpy(chan_list, &bss->param.chanlist, sizeof(mlan_chan_list)); + } + } + done: + if (req && (status != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return status; +} + +/** + * @brief Handle get info resp + * + * @param priv Pointer to moal_private structure + * @param info Pointer to mlan_ds_get_info structure + * + * @return N/A + */ +void +woal_ioctl_get_info_resp(moal_private * priv, mlan_ds_get_info * info) +{ + ENTER(); + switch (info->sub_command) { + case MLAN_OID_GET_STATS: + priv->w_stats.discard.fragment = info->param.stats.fcs_error; + priv->w_stats.discard.retries = info->param.stats.retry; + priv->w_stats.discard.misc = info->param.stats.ack_failure; + break; + case MLAN_OID_GET_SIGNAL: + if (info->param.signal.selector & BCN_RSSI_AVG_MASK) + priv->w_stats.qual.level = info->param.signal.bcn_rssi_avg; + if (info->param.signal.selector & BCN_NF_AVG_MASK) + priv->w_stats.qual.noise = info->param.signal.bcn_nf_avg; + break; + default: + break; + } + LEAVE(); +} + +/** + * @brief Handle get BSS resp + * + * @param priv Pointer to moal_private structure + * @param bss Pointer to mlan_ds_bss structure + * + * @return N/A + */ +void +woal_ioctl_get_bss_resp(moal_private * priv, mlan_ds_bss * bss) +{ + t_u32 mode = 0; + + ENTER(); + + switch (bss->sub_command) { + case MLAN_OID_BSS_MODE: + if (bss->param.bss_mode == MLAN_BSS_MODE_INFRA) + mode = IW_MODE_INFRA; + else if (bss->param.bss_mode == MLAN_BSS_MODE_IBSS) + mode = IW_MODE_ADHOC; + else + mode = IW_MODE_AUTO; + priv->w_stats.status = mode; + break; + default: + break; + } + + LEAVE(); + return; +} diff --git a/drivers/net/wireless/sd8797/mlinux/moal_priv.h b/drivers/net/wireless/sd8797/mlinux/moal_priv.h new file mode 100644 index 000000000000..de491f6d6a29 --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/moal_priv.h @@ -0,0 +1,715 @@ +/** @file moal_priv.h + * + * @brief This file contains definition for extended private IOCTL call. + * + * Copyright (C) 2008-2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +/******************************************************** +Change log: + 10/31/2008: initial version +********************************************************/ + +#ifndef _WOAL_PRIV_H_ +#define _WOAL_PRIV_H_ + +/** Command disabled */ +#define CMD_DISABLED 0 +/** Command enabled */ +#define CMD_ENABLED 1 +/** Command get */ +#define CMD_GET 2 + +/** 2K bytes */ +#define WOAL_2K_BYTES 2000 + +/** PRIVATE CMD ID */ +#define WOAL_IOCTL (SIOCIWFIRSTPRIV) /* 0x8BE0 defined in + wireless.h */ + +/** Private command ID to set one int/get word char */ +#define WOAL_SETONEINT_GETWORDCHAR (WOAL_IOCTL + 1) +/** Private command ID to get version */ +#define WOAL_VERSION 1 +/** Private command ID to get extended version */ +#define WOAL_VEREXT 2 + +/** Private command ID to set/get none */ +#define WOAL_SETNONE_GETNONE (WOAL_IOCTL + 2) +/** Private command ID for warm reset */ +#define WOAL_WARMRESET 1 +/** Private command ID to clear 11d chan table */ +#define WOAL_11D_CLR_CHAN_TABLE 4 + +/** Private command ID to set/get sixteen int */ +#define WOAL_SET_GET_SIXTEEN_INT (WOAL_IOCTL + 3) +/** Private command ID to set/get TX power configurations */ +#define WOAL_TX_POWERCFG 1 +#ifdef DEBUG_LEVEL1 +/** Private command ID to set/get driver debug */ +#define WOAL_DRV_DBG 2 +#endif +/** Private command ID to set/get beacon interval */ +#define WOAL_BEACON_INTERVAL 3 +/** Private command ID to set/get ATIM window */ +#define WOAL_ATIM_WINDOW 4 +/** Private command ID to get RSSI */ +#define WOAL_SIGNAL 5 +/** Private command ID to set/get Deep Sleep mode */ +#define WOAL_DEEP_SLEEP 7 +/** Private command ID for 11n ht configration */ +#define WOAL_11N_TX_CFG 8 +/** Private command ID for 11n usr ht configration */ +#define WOAL_11N_HTCAP_CFG 9 +/** Private command ID for TX Aggregation */ +#define WOAL_PRIO_TBL 10 +/** Private command ID for Updating ADDBA variables */ +#define WOAL_ADDBA_UPDT 11 +/** Private command ID to set/get Host Sleep configuration */ +#define WOAL_HS_CFG 12 +/** Private command ID to set Host Sleep parameters */ +#define WOAL_HS_SETPARA 13 +/** Private command ID to read/write registers */ +#define WOAL_REG_READ_WRITE 14 +/** Private command ID to set/get band/adhocband */ +#define WOAL_BAND_CFG 15 +/** Private command ID for TX Aggregation */ +#define WOAL_11N_AMSDU_AGGR_CTRL 17 +/** Private command ID to set/get Inactivity timeout */ +#define WOAL_INACTIVITY_TIMEOUT_EXT 18 +/** Private command ID to turn on/off sdio clock */ +#define WOAL_SDIO_CLOCK 19 +/** Private command ID to read/write Command 52 */ +#define WOAL_CMD_52RDWR 20 +/** Private command ID to set/get scan configuration parameter */ +#define WOAL_SCAN_CFG 21 +/** Private command ID to set/get PS configuration parameter */ +#define WOAL_PS_CFG 22 +/** Private command ID to read/write memory */ +#define WOAL_MEM_READ_WRITE 23 +#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR) +/** Private command ID to control SDIO MP-A */ +#define WOAL_SDIO_MPA_CTRL 25 +#endif +/** Private command ID for Updating ADDBA variables */ +#define WOAL_ADDBA_REJECT 27 +/** Private command ID to set/get sleep parameters */ +#define WOAL_SLEEP_PARAMS 28 +/** Private command ID to set/get TX BF capabilities */ +#define WOAL_TX_BF_CAP 31 +#if defined(DFS_TESTING_SUPPORT) +/** Private command ID to set/get dfs testing settings */ +#define WOAL_DFS_TESTING 33 +#endif +/** Private command ID to set/get tx/rx antenna */ +#define WOAL_SET_GET_TX_RX_ANT 35 +/** Private command ID to set/get management frame passthru mask */ +#define WOAL_MGMT_FRAME_CTRL 36 + +/** Private command ID to set one int/get one int */ +#define WOAL_SETONEINT_GETONEINT (WOAL_IOCTL + 5) +/** Private command ID to set/get Tx rate */ +#define WOAL_SET_GET_TXRATE 1 +/** Private command ID to set/get region code */ +#define WOAL_SET_GET_REGIONCODE 2 +/** Private command ID to turn on/off radio */ +#define WOAL_SET_RADIO 3 +/** Private command ID to enable WMM */ +#define WOAL_WMM_ENABLE 4 +/** Private command ID to enable 802.11D */ +#define WOAL_11D_ENABLE 5 +/** Private command ID to set/get QoS configuration */ +#define WOAL_SET_GET_QOS_CFG 7 +#if defined(REASSOCIATION) +/** Private command ID to set/get reassociation setting */ +#define WOAL_SET_GET_REASSOC 9 +#endif /* REASSOCIATION */ +/** Private command ID for Updating Transmit buffer configration */ +#define WOAL_TXBUF_CFG 10 +/** Private command ID to set/get WWS mode */ +#define WOAL_SET_GET_WWS_CFG 12 +/** Private command ID to set/get sleep period */ +#define WOAL_SLEEP_PD 13 +/** Private command ID to set/get auth type */ +#define WOAL_AUTH_TYPE 18 +/** Private command ID to set/get port control */ +#define WOAL_PORT_CTRL 19 +#if defined(WIFI_DIRECT_SUPPORT) +#if defined(STA_SUPPORT) && defined(UAP_SUPPORT) +/** Private command ID for set/get BSS role */ +#define WOAL_SET_GET_BSS_ROLE 21 +#endif +#endif +/** Private command ID for set/get 11h local power constraint */ +#define WOAL_SET_GET_11H_LOCAL_PWR_CONSTRAINT 22 +/** Private command ID to set/get 11N HT stream configuration */ +#define WOAL_HT_STREAM_CFG 23 +/** Private command ID to set/get MAC control */ +#define WOAL_MAC_CONTROL 24 +/** Private command ID to get thermal value */ +#define WOAL_THERMAL 25 + +/** Private command ID to get log */ +#define WOALGETLOG (WOAL_IOCTL + 7) + +/** Private command ID to set a wext address variable */ +#define WOAL_SETADDR_GETNONE (WOAL_IOCTL + 8) +/** Private command ID to send deauthentication */ +#define WOAL_DEAUTH 1 + +/** Private command to get/set 256 chars */ +#define WOAL_SET_GET_256_CHAR (WOAL_IOCTL + 9) +/** Private command to read/write passphrase */ +#define WOAL_PASSPHRASE 1 +/** Private command to get/set Ad-Hoc AES */ +#define WOAL_ADHOC_AES 2 +/** Private command ID to get WMM queue status */ +#define WOAL_WMM_QUEUE_STATUS 4 +/** Private command ID to get Traffic stream status */ +#define WOAL_WMM_TS_STATUS 5 +#define WOAL_IP_ADDRESS 7 +/** Private command ID to set/get TX bemaforming */ +#define WOAL_TX_BF_CFG 8 + +/** Get log buffer size */ +#define GETLOG_BUFSIZE 512 + +/** Private command ID to set none/get twelve chars*/ +#define WOAL_SETNONE_GETTWELVE_CHAR (WOAL_IOCTL + 11) +/** Private command ID for WPS session */ +#define WOAL_WPS_SESSION 1 + +/** Private command ID to set none/get four int */ +#define WOAL_SETNONE_GET_FOUR_INT (WOAL_IOCTL + 13) +/** Private command ID to get data rates */ +#define WOAL_DATA_RATE 1 +/** Private command ID to get E-Supplicant mode */ +#define WOAL_ESUPP_MODE 2 + +/** Private command to get/set 64 ints */ +#define WOAL_SET_GET_64_INT (WOAL_IOCTL + 15) +/** Private command ID to set/get ECL system clock */ +#define WOAL_ECL_SYS_CLOCK 1 + +/** Private command ID for hostcmd */ +#define WOAL_HOST_CMD (WOAL_IOCTL + 17) + +/** Private command ID for arpfilter */ +#define WOAL_ARP_FILTER (WOAL_IOCTL + 19) + +/** Private command ID to set ints and get chars */ +#define WOAL_SET_INTS_GET_CHARS (WOAL_IOCTL + 21) +/** Private command ID to read EEPROM data */ +#define WOAL_READ_EEPROM 1 + +/** Private command ID to set/get 2K bytes */ +#define WOAL_SET_GET_2K_BYTES (WOAL_IOCTL + 23) + +/** Private command ID to read/write Command 53 */ +#define WOAL_CMD_53RDWR 2 + +/** Private command ID for setuserscan */ +#define WOAL_SET_USER_SCAN 3 +/** Private command ID for getscantable */ +#define WOAL_GET_SCAN_TABLE 4 + +/** Private command ID to request ADDTS */ +#define WOAL_WMM_ADDTS 7 +/** Private command ID to request DELTS */ +#define WOAL_WMM_DELTS 8 +/** Private command ID to queue configuration */ +#define WOAL_WMM_QUEUE_CONFIG 9 +/** Private command ID to queue stats */ +#define WOAL_WMM_QUEUE_STATS 10 +/** Private command ID to Bypass auth packet */ +#define WOAL_BYPASSED_PACKET 11 + +#ifdef UAP_WEXT +/** The following command IDs are for Froyo app */ +/** Private command ID to start driver */ +#define WOAL_FROYO_START (WOAL_IOCTL + 28) +/** Private command ID to reload FW */ +#define WOAL_FROYO_WL_FW_RELOAD (WOAL_IOCTL + 29) +/** Private command ID to stop driver */ +#define WOAL_FROYO_STOP (WOAL_IOCTL + 30) +#endif + +/** + * iwpriv ioctl handlers + */ +static const struct iw_priv_args woal_private_args[] = { + { + WOAL_SETONEINT_GETWORDCHAR, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_CHAR | 128, + ""}, + { + WOAL_VERSION, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_CHAR | 128, + "version"}, + { + WOAL_VEREXT, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_CHAR | 128, + "verext"}, + { + WOAL_SETNONE_GETNONE, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + ""}, + { + WOAL_WARMRESET, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "warmreset"}, + { + WOAL_SETONEINT_GETONEINT, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + ""}, + { + WOAL_SET_GET_TXRATE, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + "txratecfg"}, + { + WOAL_SET_GET_REGIONCODE, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + "regioncode"}, + { + WOAL_SET_RADIO, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + "radioctrl"}, + { + WOAL_WMM_ENABLE, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + "wmmcfg"}, + { + WOAL_11D_ENABLE, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + "11dcfg"}, + { + WOAL_11D_CLR_CHAN_TABLE, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "11dclrtbl"}, + { + WOAL_SET_GET_QOS_CFG, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + "qoscfg"}, + { + WOAL_SET_GET_WWS_CFG, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + "wwscfg"}, +#if defined(REASSOCIATION) + { + WOAL_SET_GET_REASSOC, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + "reassoctrl"}, +#endif + { + WOAL_TXBUF_CFG, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + "txbufcfg"}, + { + WOAL_SLEEP_PD, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + "sleeppd"}, + { + WOAL_AUTH_TYPE, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + "authtype"}, + { + WOAL_PORT_CTRL, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + "port_ctrl"}, +#if defined(WIFI_DIRECT_SUPPORT) +#if defined(STA_SUPPORT) && defined(UAP_SUPPORT) + { + WOAL_SET_GET_BSS_ROLE, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + "bssrole"}, +#endif +#endif + { + WOAL_SET_GET_11H_LOCAL_PWR_CONSTRAINT, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + "powercons"}, + { + WOAL_HT_STREAM_CFG, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + "htstreamcfg"}, + { + WOAL_MAC_CONTROL, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + "macctrl"}, + { + WOAL_THERMAL, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + "thermal"}, + { + WOAL_SET_GET_SIXTEEN_INT, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + ""}, + { + WOAL_TX_POWERCFG, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "txpowercfg"}, +#ifdef DEBUG_LEVEL1 + { + WOAL_DRV_DBG, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "drvdbg"}, +#endif + { + WOAL_BEACON_INTERVAL, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "bcninterval"}, + { + WOAL_ATIM_WINDOW, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "atimwindow"}, + { + WOAL_SIGNAL, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "getsignal"}, + { + WOAL_DEEP_SLEEP, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "deepsleep", + }, + { + WOAL_11N_TX_CFG, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "httxcfg"}, + { + WOAL_11N_HTCAP_CFG, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "htcapinfo"}, + { + WOAL_PRIO_TBL, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "aggrpriotbl"}, + { + WOAL_11N_AMSDU_AGGR_CTRL, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "amsduaggrctrl"}, + { + WOAL_ADDBA_UPDT, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "addbapara"}, + { + WOAL_ADDBA_REJECT, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "addbareject"}, + { + WOAL_TX_BF_CAP, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "httxbfcap"}, + { + WOAL_HS_CFG, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "hscfg"}, + { + WOAL_HS_SETPARA, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "hssetpara"}, + { + WOAL_REG_READ_WRITE, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "regrdwr"}, + { + WOAL_BAND_CFG, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "bandcfg"}, + { + WOAL_INACTIVITY_TIMEOUT_EXT, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "inactivityto"}, + { + WOAL_SDIO_CLOCK, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "sdioclock"}, + { + WOAL_CMD_52RDWR, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "sdcmd52rw"}, + { + WOAL_SCAN_CFG, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "scancfg"}, + { + WOAL_PS_CFG, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "pscfg"}, + { + WOAL_MEM_READ_WRITE, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "memrdwr"}, +#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR) + { + WOAL_SDIO_MPA_CTRL, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "mpactrl"}, +#endif + { + WOAL_SLEEP_PARAMS, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "sleepparams"}, +#if defined(DFS_TESTING_SUPPORT) + { + WOAL_DFS_TESTING, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "dfstesting"}, +#endif + { + WOAL_MGMT_FRAME_CTRL, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "mgmtframectrl"}, + { + WOAL_SET_GET_TX_RX_ANT, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "antcfg"}, + { + WOALGETLOG, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_CHAR | GETLOG_BUFSIZE, + "getlog"}, + { + WOAL_SETADDR_GETNONE, + IW_PRIV_TYPE_ADDR | 1, + IW_PRIV_TYPE_NONE, + ""}, + { + WOAL_DEAUTH, + IW_PRIV_TYPE_ADDR | 1, + IW_PRIV_TYPE_NONE, + "deauth"}, + { + WOAL_SET_GET_256_CHAR, + IW_PRIV_TYPE_CHAR | 256, + IW_PRIV_TYPE_CHAR | 256, + ""}, + { + WOAL_PASSPHRASE, + IW_PRIV_TYPE_CHAR | 256, + IW_PRIV_TYPE_CHAR | 256, + "passphrase"}, + { + WOAL_ADHOC_AES, + IW_PRIV_TYPE_CHAR | 256, + IW_PRIV_TYPE_CHAR | 256, + "adhocaes"}, + { + WOAL_WMM_QUEUE_STATUS, + IW_PRIV_TYPE_CHAR | 256, + IW_PRIV_TYPE_CHAR | 256, + "qstatus"}, + { + WOAL_WMM_TS_STATUS, + IW_PRIV_TYPE_CHAR | 256, + IW_PRIV_TYPE_CHAR | 256, + "ts_status"}, + { + WOAL_IP_ADDRESS, + IW_PRIV_TYPE_CHAR | 256, + IW_PRIV_TYPE_CHAR | 256, + "ipaddr"}, + { + WOAL_TX_BF_CFG, + IW_PRIV_TYPE_CHAR | 256, + IW_PRIV_TYPE_CHAR | 256, + "httxbfcfg"}, + { + WOAL_SETNONE_GETTWELVE_CHAR, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_CHAR | 12, + ""}, + { + WOAL_WPS_SESSION, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_CHAR | 12, + "wpssession"}, + { + WOAL_SETNONE_GET_FOUR_INT, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | 4, + ""}, + { + WOAL_DATA_RATE, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | 4, + "getdatarate"}, + { + WOAL_ESUPP_MODE, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_INT | 4, + "esuppmode"}, + { + WOAL_SET_GET_64_INT, + IW_PRIV_TYPE_INT | 64, + IW_PRIV_TYPE_INT | 64, + ""}, + { + WOAL_ECL_SYS_CLOCK, + IW_PRIV_TYPE_INT | 64, + IW_PRIV_TYPE_INT | 64, + "sysclock"}, + { + WOAL_HOST_CMD, + IW_PRIV_TYPE_BYTE | 2047, + IW_PRIV_TYPE_BYTE | 2047, + "hostcmd"}, + { + WOAL_ARP_FILTER, + IW_PRIV_TYPE_BYTE | 2047, + IW_PRIV_TYPE_BYTE | 2047, + "arpfilter"}, + { + WOAL_SET_INTS_GET_CHARS, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_BYTE | 256, + ""}, + { + WOAL_READ_EEPROM, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_BYTE | 256, + "rdeeprom"}, + { + WOAL_SET_GET_2K_BYTES, + IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, + IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, + ""}, + { + WOAL_CMD_53RDWR, + IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, + IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, + "sdcmd53rw"}, + { + WOAL_SET_USER_SCAN, + IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, + IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, + "setuserscan"}, + { + WOAL_GET_SCAN_TABLE, + IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, + IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, + "getscantable"}, + { + WOAL_WMM_ADDTS, + IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, + IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, + "addts"}, + { + WOAL_WMM_DELTS, + IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, + IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, + "delts"}, + { + WOAL_WMM_QUEUE_CONFIG, + IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, + IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, + "qconfig"}, + { + WOAL_WMM_QUEUE_STATS, + IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, + IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, + "qstats"}, + { + WOAL_BYPASSED_PACKET, + IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, + IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, + "pb_bypass"}, +#ifdef UAP_WEXT + { + WOAL_FROYO_START, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "START"}, + { + WOAL_FROYO_STOP, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "STOP"}, + { + WOAL_FROYO_WL_FW_RELOAD, + IW_PRIV_TYPE_CHAR | 256, + IW_PRIV_TYPE_CHAR | 256, + "WL_FW_RELOAD"}, +#endif +}; + +/** moal_802_11_rates */ +typedef struct _moal_802_11_rates +{ + /** Num of rates */ + t_u8 num_of_rates; + /** Rates */ + t_u8 rates[MLAN_SUPPORTED_RATES]; +} moal_802_11_rates; + +#if defined(STA_WEXT) || defined(UAP_WEXT) +int woal_wext_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd); +#endif + +#endif /* _WOAL_PRIV_H_ */ diff --git a/drivers/net/wireless/sd8797/mlinux/moal_proc.c b/drivers/net/wireless/sd8797/mlinux/moal_proc.c new file mode 100644 index 000000000000..cd292351f827 --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/moal_proc.c @@ -0,0 +1,631 @@ +/** @file moal_proc.c + * + * @brief This file contains functions for proc file. + * + * Copyright (C) 2008-2010, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +/******************************************************** +Change log: + 10/21/2008: initial version +********************************************************/ + +#include "moal_main.h" +#ifdef UAP_SUPPORT +#include "moal_uap.h" +#endif +#include "moal_sdio.h" + +/******************************************************** + Local Variables +********************************************************/ +#ifdef CONFIG_PROC_FS +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) +#define PROC_DIR NULL +#define MWLAN_PROC_DIR "mwlan/" +/** Proc top level directory entry */ +struct proc_dir_entry *proc_mwlan = NULL; +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) +#define PROC_DIR &proc_root +#else +#define PROC_DIR proc_net +#endif + +#ifdef STA_SUPPORT +static char *szModes[] = { + "Unknown", + "Managed", + "Ad-hoc", + "Auto", +}; +#endif + +extern int drv_mode; + +/******************************************************** + Global Variables +********************************************************/ + +/******************************************************** + Local Functions +********************************************************/ +/** + * @brief Proc read function for info + * + * @param page Pointer to buffer + * @param start Read data starting position + * @param offset Offset + * @param count Counter + * @param eof End of file flag + * @param data Data to output + * + * @return Number of output data + */ +static int +woal_info_proc_read(char *page, char **start, off_t offset, + int count, int *eof, void *data) +{ + char *p = page; + struct net_device *netdev = data; + char fmt[MLAN_MAX_VER_STR_LEN]; + moal_private *priv = (moal_private *) netdev_priv(netdev); +#ifdef STA_SUPPORT + int i = 0; + moal_handle *handle = priv->phandle; + mlan_bss_info info; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) + struct dev_mc_list *mcptr = netdev->mc_list; + int mc_count = netdev->mc_count; +#else + struct netdev_hw_addr *mcptr = NULL; + int mc_count = netdev_mc_count(netdev); +#endif /* < 2.6.35 */ +#else +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) + int i = 0; +#endif /* >= 2.6.34 */ +#endif +#ifdef UAP_SUPPORT + mlan_ds_uap_stats ustats; +#endif + + ENTER(); + + if (offset) { + *eof = 1; + goto exit; + } + memset(fmt, 0, sizeof(fmt)); +#ifdef UAP_SUPPORT + if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) { + p += sprintf(p, "driver_name = " "\"uap\"\n"); + woal_uap_get_version(priv, fmt, sizeof(fmt) - 1); + if (MLAN_STATUS_SUCCESS != + woal_uap_get_stats(priv, MOAL_PROC_WAIT, &ustats)) { + *eof = 1; + goto exit; + } + } +#endif /* UAP_SUPPORT */ +#ifdef STA_SUPPORT + if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) { + woal_get_version(handle, fmt, sizeof(fmt) - 1); + memset(&info, 0, sizeof(info)); + if (MLAN_STATUS_SUCCESS != + woal_get_bss_info(priv, MOAL_PROC_WAIT, &info)) { + *eof = 1; + goto exit; + } + p += sprintf(p, "driver_name = " "\"wlan\"\n"); + } +#endif + p += sprintf(p, "driver_version = %s", fmt); + p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name); +#if defined(WIFI_DIRECT_SUPPORT) + if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) { + if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) + p += sprintf(p, "bss_mode = \"WIFIDIRECT-Client\"\n"); + else + p += sprintf(p, "bss_mode = \"WIFIDIRECT-GO\"\n"); + } +#endif +#ifdef STA_SUPPORT + if (priv->bss_type == MLAN_BSS_TYPE_STA) + p += sprintf(p, "bss_mode =\"%s\"\n", szModes[info.bss_mode]); +#endif + p += sprintf(p, "media_state=\"%s\"\n", + ((priv->media_connected == + MFALSE) ? "Disconnected" : "Connected")); + p += sprintf(p, "mac_address=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n", + netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], + netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); +#ifdef STA_SUPPORT + if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) { + p += sprintf(p, "multicast_count=\"%d\"\n", mc_count); + p += sprintf(p, "essid=\"%s\"\n", info.ssid.ssid); + p += sprintf(p, "bssid=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n", + info.bssid[0], info.bssid[1], + info.bssid[2], info.bssid[3], + info.bssid[4], info.bssid[5]); + p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan); + p += sprintf(p, "region_code = \"%02x\"\n", (t_u8) info.region_code); + + /* + * Put out the multicast list + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) + for (i = 0; i < netdev->mc_count; i++) { + p += sprintf(p, + "multicast_address[%d]=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n", + i, + mcptr->dmi_addr[0], mcptr->dmi_addr[1], + mcptr->dmi_addr[2], mcptr->dmi_addr[3], + mcptr->dmi_addr[4], mcptr->dmi_addr[5]); + + mcptr = mcptr->next; + } +#else + netdev_for_each_mc_addr(mcptr, netdev) + p += sprintf(p, + "multicast_address[%d]=\"%02x:%02x:%02x:%02x:%02x:%02x\"\n", + i++, + mcptr->addr[0], mcptr->addr[1], + mcptr->addr[2], mcptr->addr[3], + mcptr->addr[4], mcptr->addr[5]); +#endif /* < 2.6.35 */ + } +#endif + p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes); + p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes); + p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets); + p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets); + p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped); + p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped); + p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors); + p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors); + p += sprintf(p, "carrier %s\n", + ((netif_carrier_ok(priv->netdev)) ? "on" : "off")); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) + for (i = 0; i < netdev->num_tx_queues; i++) { + p += sprintf(p, "tx queue %d: %s\n", i, + ((netif_tx_queue_stopped(netdev_get_tx_queue(netdev, 0))) ? + "stopped" : "started")); + } +#else + p += sprintf(p, "tx queue %s\n", + ((netif_queue_stopped(priv->netdev)) ? "stopped" : "started")); +#endif +#ifdef UAP_SUPPORT + if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) { + p += sprintf(p, "tkip_mic_failures = %u\n", ustats.tkip_mic_failures); + p += sprintf(p, "ccmp_decrypt_errors = %u\n", + ustats.ccmp_decrypt_errors); + p += sprintf(p, "wep_undecryptable_count = %u\n", + ustats.wep_undecryptable_count); + p += sprintf(p, "wep_icv_error_count = %u\n", + ustats.wep_icv_error_count); + p += sprintf(p, "decrypt_failure_count = %u\n", + ustats.decrypt_failure_count); + p += sprintf(p, "mcast_tx_count = %u\n", ustats.mcast_tx_count); + p += sprintf(p, "failed_count = %u\n", ustats.failed_count); + p += sprintf(p, "retry_count = %u\n", ustats.retry_count); + p += sprintf(p, "multiple_retry_count = %u\n", + ustats.multi_retry_count); + p += sprintf(p, "frame_duplicate_count = %u\n", ustats.frame_dup_count); + p += sprintf(p, "rts_success_count = %u\n", ustats.rts_success_count); + p += sprintf(p, "rts_failure_count = %u\n", ustats.rts_failure_count); + p += sprintf(p, "ack_failure_count = %u\n", ustats.ack_failure_count); + p += sprintf(p, "rx_fragment_count = %u\n", ustats.rx_fragment_count); + p += sprintf(p, "mcast_rx_frame_count = %u\n", + ustats.mcast_rx_frame_count); + p += sprintf(p, "fcs_error_count = %u\n", ustats.fcs_error_count); + p += sprintf(p, "tx_frame_count = %u\n", ustats.tx_frame_count); + p += sprintf(p, "rsna_tkip_cm_invoked = %u\n", + ustats.rsna_tkip_cm_invoked); + p += sprintf(p, "rsna_4way_hshk_failures = %u\n", + ustats.rsna_4way_hshk_failures); + } +#endif /* UAP_SUPPORT */ + exit: + LEAVE(); + return (p - page); +} + +#define CMD52_STR_LEN 50 +/* + * @brief Parse cmd52 string + * + * @param buffer A pointer user buffer + * @param len Length user buffer + * @param func Parsed func number + * @param reg Parsed reg value + * @param val Parsed value to set + * @return BT_STATUS_SUCCESS + */ +static int +parse_cmd52_string(const char __user * buffer, size_t len, int *func, int *reg, + int *val) +{ + int ret = MLAN_STATUS_SUCCESS; + char *string = NULL; + char *pos = NULL; + + ENTER(); + + string = (char *) kmalloc(CMD52_STR_LEN, GFP_KERNEL); + memset(string, 0, CMD52_STR_LEN); + memcpy(string, buffer + strlen("sdcmd52rw="), len - strlen("sdcmd52rw=")); + string = strstrip(string); + + *func = -1; + *reg = -1; + *val = -1; + + /* Get func */ + pos = strsep(&string, " \t"); + if (pos) { + *func = woal_string_to_number(pos); + } + + /* Get reg */ + pos = strsep(&string, " \t"); + if (pos) { + *reg = woal_string_to_number(pos); + } + + /* Get val (optional) */ + pos = strsep(&string, " \t"); + if (pos) { + *val = woal_string_to_number(pos); + } + if (string) + kfree(string); + LEAVE(); + return ret; +} + +/** + * @brief config proc write function + * + * @param f file pointer + * @param buf pointer to data buffer + * @param cnt data number to write + * @param data data to write + * @return number of data + */ +static int +woal_config_write(struct file *f, const char *buf, unsigned long cnt, + void *data) +{ + char databuf[101]; + char *line; + t_u32 config_data = 0; + moal_handle *handle = (moal_handle *) data; + int func, reg, val; + + ENTER(); + if (!MODULE_GET) { + LEAVE(); + return 0; + } + + if (cnt >= sizeof(databuf)) { + MODULE_PUT; + LEAVE(); + return (int) cnt; + } + memset(databuf, 0, sizeof(databuf)); + if (copy_from_user(databuf, buf, cnt)) { + MODULE_PUT; + LEAVE(); + return 0; + } + line = databuf; + if (!strncmp(databuf, "soft_reset", strlen("soft_reset"))) { + line += strlen("soft_reset") + 1; + config_data = (t_u32) woal_string_to_number(line); + PRINTM(MINFO, "soft_reset: %d\n", (int) config_data); + if (woal_request_soft_reset(handle) == MLAN_STATUS_SUCCESS) { + handle->hardware_status = HardwareStatusReset; + } else { + PRINTM(MERROR, "Could not perform soft reset\n"); + } + } + if (!strncmp(databuf, "drv_mode", strlen("drv_mode"))) { + line += strlen("drv_mode") + 1; + config_data = (t_u32) woal_string_to_number(line); + PRINTM(MINFO, "drv_mode: %d\n", (int) config_data); + if (config_data != (t_u32) drv_mode) + if (woal_switch_drv_mode(handle, config_data) != + MLAN_STATUS_SUCCESS) { + PRINTM(MERROR, "Could not switch drv mode\n"); + } + } + if (!strncmp(databuf, "sdcmd52rw=", strlen("sdcmd52rw="))) { + parse_cmd52_string(databuf, (size_t) cnt, &func, ®, &val); + woal_sdio_read_write_cmd52(handle, func, reg, val); + } + MODULE_PUT; + LEAVE(); + return (int) cnt; +} + +/** + * @brief config proc read function + * + * @param page pointer to buffer + * @param s read data starting position + * @param off offset + * @param cnt counter + * @param eof end of file flag + * @param data data to output + * @return number of output data + */ +static int +woal_config_read(char *page, char **s, off_t off, int cnt, int *eof, void *data) +{ + char *p = page; + moal_handle *handle = (moal_handle *) data; + + ENTER(); + if (!MODULE_GET) { + LEAVE(); + return 0; + } + p += sprintf(p, "hardware_status=%d\n", (int) handle->hardware_status); + p += sprintf(p, "netlink_num=%d\n", (int) handle->netlink_num); + p += sprintf(p, "drv_mode=%d\n", (int) drv_mode); + p += sprintf(p, "sdcmd52rw=%d 0x%0x 0x%02X\n", handle->cmd52_func, + handle->cmd52_reg, handle->cmd52_val); + MODULE_PUT; + LEAVE(); + return p - page; +} + +/******************************************************** + Global Functions +********************************************************/ +/** + * @brief Convert string to number + * + * @param s Pointer to numbered string + * + * @return Converted number from string s + */ +int +woal_string_to_number(char *s) +{ + int r = 0; + int base = 0; + int pn = 1; + + if (!strncmp(s, "-", 1)) { + pn = -1; + s++; + } + if (!strncmp(s, "0x", 2) || !strncmp(s, "0X", 2)) { + base = 16; + s += 2; + } else + base = 10; + + for (s = s; *s; s++) { + if ((*s >= '0') && (*s <= '9')) + r = (r * base) + (*s - '0'); + else if ((*s >= 'A') && (*s <= 'F')) + r = (r * base) + (*s - 'A' + 10); + else if ((*s >= 'a') && (*s <= 'f')) + r = (r * base) + (*s - 'a' + 10); + else + break; + } + + return (r * pn); +} + +/** + * @brief Create the top level proc directory + * + * @param handle Pointer to woal_handle + * + * @return N/A + */ +void +woal_proc_init(moal_handle * handle) +{ + struct proc_dir_entry *r; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) + struct proc_dir_entry *pde = PROC_DIR; +#endif + char config_proc_dir[20]; + + ENTER(); + + PRINTM(MINFO, "Create Proc Interface\n"); + if (!handle->proc_mwlan) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) + /* Check if directory already exists */ + for (pde = pde->subdir; pde; pde = pde->next) { + if (pde->namelen && !strcmp("mwlan", pde->name)) { + /* Directory exists */ + PRINTM(MWARN, "proc interface already exists!\n"); + handle->proc_mwlan = pde; + break; + } + } + if (pde == NULL) { + handle->proc_mwlan = proc_mkdir("mwlan", PROC_DIR); + if (!handle->proc_mwlan) + PRINTM(MERROR, "Cannot create proc interface!\n"); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) + else + atomic_set(&handle->proc_mwlan->count, 1); +#endif + } +#else + if (!proc_mwlan) { + handle->proc_mwlan = proc_mkdir("mwlan", PROC_DIR); + if (!handle->proc_mwlan) { + PRINTM(MERROR, "Cannot create proc interface!\n"); + } + } else { + handle->proc_mwlan = proc_mwlan; + } +#endif + if (handle->proc_mwlan) { + if (handle->handle_idx) + sprintf(config_proc_dir, "config%d", handle->handle_idx); + else + strcpy(config_proc_dir, "config"); + + r = create_proc_entry(config_proc_dir, 0644, handle->proc_mwlan); + + if (r) { + r->data = handle; + r->read_proc = woal_config_read; + r->write_proc = woal_config_write; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) + r->owner = THIS_MODULE; +#endif + } else + PRINTM(MMSG, "Fail to create proc config\n"); + } +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26) + proc_mwlan = handle->proc_mwlan; +#endif + } + + LEAVE(); +} + +/** + * @brief Remove the top level proc directory + * + * @param handle pointer moal_handle + * + * @return N/A + */ +void +woal_proc_exit(moal_handle * handle) +{ + ENTER(); + + PRINTM(MINFO, "Remove Proc Interface\n"); + if (handle->proc_mwlan) { + char config_proc_dir[20]; + if (handle->handle_idx) + sprintf(config_proc_dir, "config%d", handle->handle_idx); + else + strcpy(config_proc_dir, "config"); + remove_proc_entry(config_proc_dir, handle->proc_mwlan); + + /* Remove only if we are the only instance using this */ + if (atomic_read(&(handle->proc_mwlan->count)) > 1) { + PRINTM(MWARN, "More than one interface using proc!\n"); + } else { +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) + atomic_dec(&(handle->proc_mwlan->count)); +#endif + remove_proc_entry("mwlan", PROC_DIR); + handle->proc_mwlan = NULL; +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,26) + proc_mwlan = NULL; +#endif + } + } + + LEAVE(); +} + +/** + * @brief Create proc file for interface + * + * @param priv pointer moal_private + * + * @return N/A + */ +void +woal_create_proc_entry(moal_private * priv) +{ + struct net_device *dev = priv->netdev; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) + char proc_dir_name[20]; +#endif + + ENTER(); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) + if (!priv->proc_entry) { + memset(proc_dir_name, 0, sizeof(proc_dir_name)); + strcpy(proc_dir_name, MWLAN_PROC_DIR); + strcat(proc_dir_name, dev->name); + /* Try to create mwlan/mlanX first */ + priv->proc_entry = proc_mkdir(proc_dir_name, PROC_DIR); + if (priv->proc_entry) { + /* Success. Continue normally */ + if (!priv->phandle->proc_mwlan) { + priv->phandle->proc_mwlan = priv->proc_entry->parent; + } + atomic_inc(&(priv->phandle->proc_mwlan->count)); + } else { + /* Failure. mwlan may not exist. Try to create that first */ + priv->phandle->proc_mwlan = proc_mkdir("mwlan", PROC_DIR); + if (!priv->phandle->proc_mwlan) { + /* Failure. Something broken */ + LEAVE(); + return; + } else { + /* Success. Now retry creating mlanX */ + priv->proc_entry = proc_mkdir(proc_dir_name, PROC_DIR); + atomic_inc(&(priv->phandle->proc_mwlan->count)); + } + } +#else + if (priv->phandle->proc_mwlan && !priv->proc_entry) { + priv->proc_entry = proc_mkdir(dev->name, priv->phandle->proc_mwlan); + atomic_inc(&(priv->phandle->proc_mwlan->count)); +#endif + strcpy(priv->proc_entry_name, dev->name); + if (priv->proc_entry) { + create_proc_read_entry("info", 0, priv->proc_entry, + woal_info_proc_read, dev); + } + } + + LEAVE(); +} + +/** + * @brief Remove proc file + * + * @param priv Pointer moal_private + * + * @return N/A + */ +void +woal_proc_remove(moal_private * priv) +{ + ENTER(); + if (priv->phandle->proc_mwlan && priv->proc_entry) { + remove_proc_entry("info", priv->proc_entry); + remove_proc_entry(priv->proc_entry_name, priv->phandle->proc_mwlan); + atomic_dec(&(priv->phandle->proc_mwlan->count)); + priv->proc_entry = NULL; + } + LEAVE(); +} +#endif diff --git a/drivers/net/wireless/sd8797/mlinux/moal_sdio.h b/drivers/net/wireless/sd8797/mlinux/moal_sdio.h new file mode 100644 index 000000000000..5a5bc2c3718c --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/moal_sdio.h @@ -0,0 +1,140 @@ +/** @file moal_sdio.h + * + * @brief This file contains definitions for SDIO interface. + * driver. + * + * Copyright (C) 2008-2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/**************************************************** +Change log: +****************************************************/ + +#ifndef _MOAL_SDIO_H +#define _MOAL_SDIO_H + +#include +#include +#include +#include +#include + +#include "moal_main.h" + +#ifndef BLOCK_MODE +/** Block mode */ +#define BLOCK_MODE 1 +#endif + +#ifndef BYTE_MODE +/** Byte Mode */ +#define BYTE_MODE 0 +#endif + +#ifndef FIXED_ADDRESS +/** Fixed address mode */ +#define FIXED_ADDRESS 0 +#endif + +/** SD8797 chip revision ID */ +#define SD8797_A0 0x00 +#define SD8797_B0 0x10 + +#define SD8797_A0_FW_NAME "mrvl/sd8797_uapsta_a0.bin" +#define SD8797_B0_FW_NAME "mrvl/sd8797_uapsta.bin" + +#ifdef STA_SUPPORT +/** Default firmware name */ + +#define DEFAULT_FW_NAME "mrvl/sd8797_uapsta.bin" + +#ifndef DEFAULT_FW_NAME +#define DEFAULT_FW_NAME "" +#endif +#endif /* STA_SUPPORT */ + +#ifdef UAP_SUPPORT +/** Default firmware name */ + +#define DEFAULT_AP_FW_NAME "mrvl/sd8797_uapsta.bin" + +#ifndef DEFAULT_AP_FW_NAME +#define DEFAULT_AP_FW_NAME "" +#endif +#endif /* UAP_SUPPORT */ + +/** Default firmaware name */ + +#define DEFAULT_AP_STA_FW_NAME "mrvl/sd8797_uapsta.bin" + +#ifndef DEFAULT_AP_STA_FW_NAME +#define DEFAULT_AP_STA_FW_NAME "" +#endif + +/******************************************************** + Global Functions +********************************************************/ + +/** Function to write register */ +mlan_status woal_write_reg(moal_handle * handle, t_u32 reg, t_u32 data); +/** Function to read register */ +mlan_status woal_read_reg(moal_handle * handle, t_u32 reg, t_u32 * data); +/** Function to write data to IO memory */ +mlan_status woal_write_data_sync(moal_handle * handle, mlan_buffer * pmbuf, + t_u32 port, t_u32 timeout); +/** Function to read data from IO memory */ +mlan_status woal_read_data_sync(moal_handle * handle, mlan_buffer * pmbuf, + t_u32 port, t_u32 timeout); + +/** Register to bus driver function */ +mlan_status woal_bus_register(void); +/** Unregister from bus driver function */ +void woal_bus_unregister(void); + +/** Register device function */ +mlan_status woal_register_dev(moal_handle * handle); +/** Unregister device function */ +void woal_unregister_dev(moal_handle * handle); + +int woal_sdio_set_bus_clock(moal_handle * handle, t_u8 option); + +#ifdef SDIO_SUSPEND_RESUME +#ifdef MMC_PM_FUNC_SUSPENDED +/** Notify SDIO bus driver that WLAN is suspended */ +void woal_wlan_is_suspended(moal_handle * handle); +#endif +/** SDIO Suspend */ +int woal_sdio_suspend(struct device *dev); +/** SDIO Resume */ +int woal_sdio_resume(struct device *dev); +#endif /* SDIO_SUSPEND_RESUME */ + +/** Structure: SDIO MMC card */ +struct sdio_mmc_card +{ + /** sdio_func structure pointer */ + struct sdio_func *func; + /** moal_handle structure pointer */ + moal_handle *handle; + /** saved host clock value */ + unsigned int host_clock; +}; + +/** cmd52 read write */ +int woal_sdio_read_write_cmd52(moal_handle * handle, int func, int reg, + int val); + +#endif /* _MOAL_SDIO_H */ diff --git a/drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c b/drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c new file mode 100644 index 000000000000..94d2a1eef004 --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c @@ -0,0 +1,728 @@ +/** @file moal_sdio_mmc.c + * + * @brief This file contains SDIO MMC IF (interface) module + * related functions. + * + * Copyright (C) 2008-2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/**************************************************** +Change log: + 02/25/09: Initial creation - + This file supports SDIO MMC only +****************************************************/ + +#include + +#include "moal_sdio.h" + +/** define marvell vendor id */ +#define MARVELL_VENDOR_ID 0x02df + +/******************************************************** + Local Variables +********************************************************/ + +/******************************************************** + Global Variables +********************************************************/ + +#ifdef SDIO_SUSPEND_RESUME +/** PM keep power */ +extern int pm_keep_power; +#endif + +/** Device ID for SD8797 */ +#define SD_DEVICE_ID_8797 (0x9129) + +/** WLAN IDs */ +static const struct sdio_device_id wlan_ids[] = { + {SDIO_DEVICE(MARVELL_VENDOR_ID, SD_DEVICE_ID_8797)}, + {}, +}; + +MODULE_DEVICE_TABLE(sdio, wlan_ids); + +int woal_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id); +void woal_sdio_remove(struct sdio_func *func); + +#ifdef SDIO_SUSPEND_RESUME +#ifdef MMC_PM_KEEP_POWER +int woal_sdio_suspend(struct device *dev); +int woal_sdio_resume(struct device *dev); + +static struct dev_pm_ops wlan_sdio_pm_ops = { + .suspend = woal_sdio_suspend, + .resume = woal_sdio_resume, +}; +#endif +#endif +static struct sdio_driver wlan_sdio = { + .name = "wlan_sdio", + .id_table = wlan_ids, + .probe = woal_sdio_probe, + .remove = woal_sdio_remove, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) + .drv = { + .owner = THIS_MODULE, +#ifdef SDIO_SUSPEND_RESUME +#ifdef MMC_PM_KEEP_POWER + .pm = &wlan_sdio_pm_ops, +#endif +#endif + } +#else +#ifdef SDIO_SUSPEND_RESUME +#ifdef MMC_PM_KEEP_POWER + .drv = { + .pm = &wlan_sdio_pm_ops, + } +#endif +#endif +#endif +}; + +/******************************************************** + Local Functions +********************************************************/ +/** @brief This function dump the sdio register + * + * @param handle A Pointer to the moal_handle structure + * @return N/A + */ +void +woal_dump_sdio_reg(moal_handle * handle) +{ + int ret = 0; + t_u8 data; + data = + sdio_f0_readb(((struct sdio_mmc_card *) handle->card)->func, 0x05, + &ret); + PRINTM(MMSG, "fun0: reg 0x05=0x%x ret=%d\n", data, ret); + data = + sdio_f0_readb(((struct sdio_mmc_card *) handle->card)->func, 0x04, + &ret); + PRINTM(MMSG, "fun0: reg 0x04=0x%x ret=%d\n", data, ret); + data = + sdio_readb(((struct sdio_mmc_card *) handle->card)->func, 0x03, &ret); + PRINTM(MMSG, "fun1: reg 0x03=0x%x ret=%d\n", data, ret); + data = + sdio_readb(((struct sdio_mmc_card *) handle->card)->func, 0x04, &ret); + PRINTM(MMSG, "fun1: reg 0x04=0x%x ret=%d\n", data, ret); + data = + sdio_readb(((struct sdio_mmc_card *) handle->card)->func, 0x05, &ret); + PRINTM(MMSG, "fun1: reg 0x05=0x%x ret=%d\n", data, ret); + data = + sdio_readb(((struct sdio_mmc_card *) handle->card)->func, 0x60, &ret); + PRINTM(MMSG, "fun1: reg 0x60=0x%x ret=%d\n", data, ret); + data = + sdio_readb(((struct sdio_mmc_card *) handle->card)->func, 0x61, &ret); + PRINTM(MMSG, "fun1: reg 0x61=0x%x ret=%d\n", data, ret); + return; +} + +/******************************************************** + Global Functions +********************************************************/ + +/** + * @brief This function handles the interrupt. + * + * @param func A pointer to the sdio_func structure + * @return N/A + */ +static void +woal_sdio_interrupt(struct sdio_func *func) +{ + moal_handle *handle; + struct sdio_mmc_card *card; + + ENTER(); + + card = sdio_get_drvdata(func); + if (!card || !card->handle) { + PRINTM(MINFO, + "sdio_mmc_interrupt(func = %p) card or handle is NULL, card=%p\n", + func, card); + LEAVE(); + return; + } + handle = card->handle; + + PRINTM(MINFO, "*** IN SDIO IRQ ***\n"); + woal_interrupt(handle); + + LEAVE(); +} + +/** @brief This function handles client driver probe. + * + * @param func A pointer to sdio_func structure. + * @param id A pointer to sdio_device_id structure. + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE/error code + */ +int +woal_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) +{ + int ret = MLAN_STATUS_SUCCESS; + struct sdio_mmc_card *card = NULL; + + ENTER(); + + PRINTM(MINFO, "vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n", + func->vendor, func->device, func->class, func->num); + + card = kzalloc(sizeof(struct sdio_mmc_card), GFP_KERNEL); + if (!card) { + PRINTM(MFATAL, "Failed to allocate memory in probe function!\n"); + LEAVE(); + return -ENOMEM; + } + + card->func = func; + +#ifdef MMC_QUIRK_BLKSZ_FOR_BYTE_MODE + /* The byte mode patch is available in kernel MMC driver which fixes one + issue in MP-A transfer. bit1: use func->cur_blksize for byte mode */ + func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; +#endif +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) + /* wait for chip fully wake up */ + if (!func->enable_timeout) + func->enable_timeout = 200; +#endif + sdio_claim_host(func); + ret = sdio_enable_func(func); + if (ret) { + sdio_disable_func(func); + sdio_release_host(func); + kfree(card); + PRINTM(MFATAL, "sdio_enable_func() failed: ret=%d\n", ret); + LEAVE(); + return -EIO; + } + sdio_release_host(func); + if (NULL == woal_add_card(card)) { + PRINTM(MERROR, "woal_add_card failed\n"); + kfree(card); + sdio_claim_host(func); + sdio_disable_func(func); + sdio_release_host(func); + ret = MLAN_STATUS_FAILURE; + } + + LEAVE(); + return ret; +} + +/** @brief This function handles client driver remove. + * + * @param func A pointer to sdio_func structure. + * @return N/A + */ +void +woal_sdio_remove(struct sdio_func *func) +{ + struct sdio_mmc_card *card; + + ENTER(); + + PRINTM(MINFO, "SDIO func=%d\n", func->num); + + if (func) { + card = sdio_get_drvdata(func); + if (card) { + woal_remove_card(card); + kfree(card); + } + } + + LEAVE(); +} + +#ifdef SDIO_SUSPEND_RESUME +#ifdef MMC_PM_KEEP_POWER +#ifdef MMC_PM_FUNC_SUSPENDED +/** @brief This function tells lower driver that WLAN is suspended + * + * @param handle A Pointer to the moal_handle structure + * @return N/A + */ +void +woal_wlan_is_suspended(moal_handle * handle) +{ + ENTER(); + if (handle->suspend_notify_req == MTRUE) { + handle->is_suspended = MTRUE; + sdio_func_suspended(((struct sdio_mmc_card *) handle->card)->func); + } + LEAVE(); +} +#endif + +/** @brief This function handles client driver suspend + * + * @param dev A pointer to device structure + * @return MLAN_STATUS_SUCCESS or error code + */ +int +woal_sdio_suspend(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + mmc_pm_flag_t pm_flags = 0; + moal_handle *handle = NULL; + struct sdio_mmc_card *cardp; + int i; + int ret = MLAN_STATUS_SUCCESS; + int hs_actived = 0; + mlan_ds_ps_info pm_info; + + ENTER(); + PRINTM(MCMND, "<--- Enter woal_sdio_suspend --->\n"); + if (func) { + pm_flags = sdio_get_host_pm_caps(func); + PRINTM(MCMND, "%s: suspend: PM flags = 0x%x\n", sdio_func_id(func), + pm_flags); + if (!(pm_flags & MMC_PM_KEEP_POWER)) { + PRINTM(MERROR, "%s: cannot remain alive while host is suspended\n", + sdio_func_id(func)); + LEAVE(); + return -ENOSYS; + } + cardp = sdio_get_drvdata(func); + if (!cardp || !cardp->handle) { + PRINTM(MERROR, "Card or moal_handle structure is not valid\n"); + LEAVE(); + return MLAN_STATUS_SUCCESS; + } + } else { + PRINTM(MERROR, "sdio_func is not specified\n"); + LEAVE(); + return MLAN_STATUS_SUCCESS; + } + + handle = cardp->handle; + handle->suspend_fail = MFALSE; + memset(&pm_info, 0, sizeof(pm_info)); + if (MLAN_STATUS_SUCCESS == + woal_get_pm_info(woal_get_priv(handle, MLAN_BSS_ROLE_ANY), &pm_info)) { + if (pm_info.is_suspend_allowed == MFALSE) { + PRINTM(MMSG, "suspend not allowed!"); + ret = -EBUSY; + goto done; + } + } + for (i = 0; i < handle->priv_num; i++) + netif_device_detach(handle->priv[i]->netdev); + + if (pm_keep_power) { + /* Enable the Host Sleep */ +#ifdef MMC_PM_FUNC_SUSPENDED + handle->suspend_notify_req = MTRUE; +#endif + hs_actived = woal_enable_hs(woal_get_priv(handle, MLAN_BSS_ROLE_ANY)); +#ifdef MMC_PM_FUNC_SUSPENDED + handle->suspend_notify_req = MFALSE; +#endif + if (hs_actived) { +#ifdef MMC_PM_SKIP_RESUME_PROBE + PRINTM(MCMND, "suspend with MMC_PM_KEEP_POWER and " + "MMC_PM_SKIP_RESUME_PROBE\n"); + ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER | + MMC_PM_SKIP_RESUME_PROBE); +#else + PRINTM(MCMND, "suspend with MMC_PM_KEEP_POWER\n"); + ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); +#endif + } else { + PRINTM(MMSG, "HS not actived, suspend fail!"); + ret = -EBUSY; + goto done; + } + } + + /* Indicate device suspended */ + handle->is_suspended = MTRUE; + done: + PRINTM(MCMND, "<--- Leave woal_sdio_suspend --->\n"); + LEAVE(); + return ret; +} + +/** @brief This function handles client driver resume + * + * @param dev A pointer to device structure + * @return MLAN_STATUS_SUCCESS + */ +int +woal_sdio_resume(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + mmc_pm_flag_t pm_flags = 0; + moal_handle *handle = NULL; + struct sdio_mmc_card *cardp; + int i; + + ENTER(); + PRINTM(MCMND, "<--- Enter woal_sdio_resume --->\n"); + if (func) { + pm_flags = sdio_get_host_pm_caps(func); + PRINTM(MCMND, "%s: resume: PM flags = 0x%x\n", sdio_func_id(func), + pm_flags); + cardp = sdio_get_drvdata(func); + if (!cardp || !cardp->handle) { + PRINTM(MERROR, "Card or moal_handle structure is not valid\n"); + LEAVE(); + return MLAN_STATUS_SUCCESS; + } + } else { + PRINTM(MERROR, "sdio_func is not specified\n"); + LEAVE(); + return MLAN_STATUS_SUCCESS; + } + handle = cardp->handle; + + if (handle->is_suspended == MFALSE) { + PRINTM(MWARN, "Device already resumed\n"); + LEAVE(); + return MLAN_STATUS_SUCCESS; + } + + handle->is_suspended = MFALSE; + for (i = 0; i < handle->priv_num; i++) + netif_device_attach(handle->priv[i]->netdev); + + /* Disable Host Sleep */ + woal_cancel_hs(woal_get_priv(handle, MLAN_BSS_ROLE_ANY), MOAL_NO_WAIT); + PRINTM(MCMND, "<--- Leave woal_sdio_resume --->\n"); + LEAVE(); + return MLAN_STATUS_SUCCESS; +} +#endif +#endif /* SDIO_SUSPEND_RESUME */ + +/** + * @brief This function writes data into card register + * + * @param handle A Pointer to the moal_handle structure + * @param reg Register offset + * @param data Value + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +woal_write_reg(moal_handle * handle, t_u32 reg, t_u32 data) +{ + mlan_status ret = MLAN_STATUS_FAILURE; + sdio_writeb(((struct sdio_mmc_card *) handle->card)->func, (t_u8) data, reg, + (int *) &ret); + return ret; +} + +/** + * @brief This function reads data from card register + * + * @param handle A Pointer to the moal_handle structure + * @param reg Register offset + * @param data Value + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +woal_read_reg(moal_handle * handle, t_u32 reg, t_u32 * data) +{ + mlan_status ret = MLAN_STATUS_FAILURE; + t_u8 val; + + val = + sdio_readb(((struct sdio_mmc_card *) handle->card)->func, reg, + (int *) &ret); + *data = val; + + return ret; +} + +/** + * @brief This function writes multiple bytes into card memory + * + * @param handle A Pointer to the moal_handle structure + * @param pmbuf Pointer to mlan_buffer structure + * @param port Port + * @param timeout Time out value + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +woal_write_data_sync(moal_handle * handle, mlan_buffer * pmbuf, t_u32 port, + t_u32 timeout) +{ + mlan_status ret = MLAN_STATUS_FAILURE; + t_u8 *buffer = (t_u8 *) (pmbuf->pbuf + pmbuf->data_offset); + t_u8 blkmode = (port & MLAN_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE; + t_u32 blksz = (blkmode == BLOCK_MODE) ? MLAN_SDIO_BLOCK_SIZE : 1; + t_u32 blkcnt = + (blkmode == + BLOCK_MODE) ? (pmbuf->data_len / + MLAN_SDIO_BLOCK_SIZE) : pmbuf->data_len; + t_u32 ioport = (port & MLAN_SDIO_IO_PORT_MASK); +#ifdef SDIO_MMC_DEBUG + handle->cmd53w = 1; +#endif + if (!sdio_writesb + (((struct sdio_mmc_card *) handle->card)->func, ioport, buffer, + blkcnt * blksz)) + ret = MLAN_STATUS_SUCCESS; +#ifdef SDIO_MMC_DEBUG + handle->cmd53w = 2; +#endif + return ret; +} + +/** + * @brief This function reads multiple bytes from card memory + * + * @param handle A Pointer to the moal_handle structure + * @param pmbuf Pointer to mlan_buffer structure + * @param port Port + * @param timeout Time out value + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +woal_read_data_sync(moal_handle * handle, mlan_buffer * pmbuf, t_u32 port, + t_u32 timeout) +{ + mlan_status ret = MLAN_STATUS_FAILURE; + t_u8 *buffer = (t_u8 *) (pmbuf->pbuf + pmbuf->data_offset); + t_u8 blkmode = (port & MLAN_SDIO_BYTE_MODE_MASK) ? BYTE_MODE : BLOCK_MODE; + t_u32 blksz = (blkmode == BLOCK_MODE) ? MLAN_SDIO_BLOCK_SIZE : 1; + t_u32 blkcnt = + (blkmode == + BLOCK_MODE) ? (pmbuf->data_len / + MLAN_SDIO_BLOCK_SIZE) : pmbuf->data_len; + t_u32 ioport = (port & MLAN_SDIO_IO_PORT_MASK); + +#ifdef SDIO_MMC_DEBUG + handle->cmd53r = 1; +#endif + if (!sdio_readsb + (((struct sdio_mmc_card *) handle->card)->func, buffer, ioport, + blkcnt * blksz)) + ret = MLAN_STATUS_SUCCESS; + else + woal_dump_sdio_reg(handle); +#ifdef SDIO_MMC_DEBUG + handle->cmd53r = 2; +#endif + return ret; +} + +/** + * @brief This function registers the IF module in bus driver + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +woal_bus_register(void) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + + ENTER(); + + /* SDIO Driver Registration */ + if (sdio_register_driver(&wlan_sdio)) { + PRINTM(MFATAL, "SDIO Driver Registration Failed \n"); + LEAVE(); + return MLAN_STATUS_FAILURE; + } + + LEAVE(); + return ret; +} + +/** + * @brief This function de-registers the IF module in bus driver + * + * @return N/A + */ +void +woal_bus_unregister(void) +{ + ENTER(); + + /* SDIO Driver Unregistration */ + sdio_unregister_driver(&wlan_sdio); + + LEAVE(); +} + +/** + * @brief This function de-registers the device + * + * @param handle A pointer to moal_handle structure + * @return N/A + */ +void +woal_unregister_dev(moal_handle * handle) +{ + ENTER(); + if (handle->card) { + /* Release the SDIO IRQ */ + sdio_claim_host(((struct sdio_mmc_card *) handle->card)->func); + sdio_release_irq(((struct sdio_mmc_card *) handle->card)->func); + sdio_disable_func(((struct sdio_mmc_card *) handle->card)->func); + sdio_release_host(((struct sdio_mmc_card *) handle->card)->func); + + sdio_set_drvdata(((struct sdio_mmc_card *) handle->card)->func, NULL); + + PRINTM(MWARN, "Making the sdio dev card as NULL\n"); + } + + LEAVE(); +} + +/** + * @brief This function registers the device + * + * @param handle A pointer to moal_handle structure + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +woal_register_dev(moal_handle * handle) +{ + int ret = MLAN_STATUS_SUCCESS; + struct sdio_mmc_card *card = handle->card; + struct sdio_func *func; + + ENTER(); + + func = card->func; + sdio_claim_host(func); + /* Request the SDIO IRQ */ + ret = sdio_claim_irq(func, woal_sdio_interrupt); + if (ret) { + PRINTM(MFATAL, "sdio_claim_irq failed: ret=%d\n", ret); + goto release_host; + } + + /* Set block size */ + ret = sdio_set_block_size(card->func, MLAN_SDIO_BLOCK_SIZE); + if (ret) { + PRINTM(MERROR, "sdio_set_block_seize(): cannot set SDIO block size\n"); + ret = MLAN_STATUS_FAILURE; + goto release_irq; + } + + sdio_release_host(func); + sdio_set_drvdata(func, card); + + handle->hotplug_device = &func->dev; + + LEAVE(); + return MLAN_STATUS_SUCCESS; + + release_irq: + sdio_release_irq(func); + release_host: + sdio_release_host(func); + handle->card = NULL; + + LEAVE(); + return MLAN_STATUS_FAILURE; +} + +/** + * @brief This function set bus clock on/off + * + * @param handle A pointer to moal_handle structure + * @param option TRUE--on , FALSE--off + * @return MLAN_STATUS_SUCCESS + */ +int +woal_sdio_set_bus_clock(moal_handle * handle, t_u8 option) +{ + struct sdio_mmc_card *cardp = (struct sdio_mmc_card *) handle->card; + struct mmc_host *host = cardp->func->card->host; + + ENTER(); + if (option == MTRUE) { + /* restore value if non-zero */ + if (cardp->host_clock) + host->ios.clock = cardp->host_clock; + } else { + /* backup value if non-zero, then clear */ + if (host->ios.clock) + cardp->host_clock = host->ios.clock; + host->ios.clock = 0; + } + + host->ops->set_ios(host, &host->ios); + LEAVE(); + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief This function updates card reg based on the Cmd52 value in dev structure + * + * @param handle A pointer to moal_handle structure + * @param func A pointer to store func variable + * @param reg A pointer to store reg variable + * @param val A pointer to store val variable + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +int +woal_sdio_read_write_cmd52(moal_handle * handle, int func, int reg, int val) +{ + int ret = MLAN_STATUS_SUCCESS; + struct sdio_mmc_card *card = (struct sdio_mmc_card *) handle->card; + + ENTER(); + /* Save current func and reg for read */ + handle->cmd52_func = func; + handle->cmd52_reg = reg; + sdio_claim_host(card->func); + if (val >= 0) { + /* Perform actual write only if val is provided */ + if (func) + sdio_writeb(card->func, val, reg, &ret); + else + sdio_f0_writeb(card->func, val, reg, &ret); + if (ret) { + PRINTM(MERROR, "Cannot write value (0x%x) to func %d reg 0x%x\n", + val, func, reg); + } else { + PRINTM(MMSG, "write value (0x%x) to func %d reg 0x%x\n", (u8) val, + func, reg); + handle->cmd52_val = val; + } + } else { + if (func) + val = sdio_readb(card->func, reg, &ret); + else + val = sdio_f0_readb(card->func, reg, &ret); + if (ret) { + PRINTM(MERROR, "Cannot read value from func %d reg 0x%x\n", func, + reg); + } else { + PRINTM(MMSG, "read value (0x%x) from func %d reg 0x%x\n", (u8) val, + func, reg); + handle->cmd52_val = val; + } + } + sdio_release_host(card->func); + LEAVE(); + return ret; +} diff --git a/drivers/net/wireless/sd8797/mlinux/moal_shim.c b/drivers/net/wireless/sd8797/mlinux/moal_shim.c new file mode 100644 index 000000000000..51f192a160f9 --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/moal_shim.c @@ -0,0 +1,1458 @@ +/** @file moal_shim.c + * + * @brief This file contains the callback functions registered to MLAN + * + * Copyright (C) 2008-2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +/******************************************************** +Change log: + 10/21/2008: initial version +********************************************************/ + +#include "moal_main.h" +#include "moal_sdio.h" +#ifdef UAP_SUPPORT +#include "moal_uap.h" +#endif +#ifdef STA_CFG80211 +#include "moal_cfg80211.h" +#endif + +/******************************************************** + Local Variables +********************************************************/ +/** moal_lock */ +typedef struct _moal_lock +{ + /** Lock */ + spinlock_t lock; + /** Flags */ + unsigned long flags; +} moal_lock; + +/******************************************************** + Global Variables +********************************************************/ +extern int cfg80211_wext; + +/******************************************************** + Local Functions +********************************************************/ + +/******************************************************** + Global Functions +********************************************************/ + +/** + * @brief Alloc a buffer + * + * @param pmoal_handle Pointer to the MOAL context + * @param size The size of the buffer to be allocated + * @param flag The type of the buffer to be allocated + * @param ppbuf Pointer to a buffer location to store buffer pointer allocated + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +moal_malloc(IN t_void * pmoal_handle, + IN t_u32 size, IN t_u32 flag, OUT t_u8 ** ppbuf) +{ + moal_handle *handle = (moal_handle *) pmoal_handle; + t_u32 mem_flag = GFP_ATOMIC; /* Default type: GFP_ATOMIC */ + + if (flag & MLAN_MEM_DMA) + mem_flag |= GFP_DMA; + + if (!(*ppbuf = kmalloc(size, mem_flag))) { + PRINTM(MERROR, "%s: allocate buffer %d failed!\n", __FUNCTION__, + (int) size); + return MLAN_STATUS_FAILURE; + } + handle->malloc_count++; + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Free a buffer + * + * @param pmoal_handle Pointer to the MOAL context + * @param pbuf Pointer to the buffer to be freed + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +moal_mfree(IN t_void * pmoal_handle, IN t_u8 * pbuf) +{ + moal_handle *handle = (moal_handle *) pmoal_handle; + + if (!pbuf) + return MLAN_STATUS_FAILURE; + kfree(pbuf); + handle->malloc_count--; + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Fill memory with constant byte + * + * @param pmoal_handle Pointer to the MOAL context + * @param pmem Pointer to the memory area + * @param byte A constant byte + * @param num Number of bytes to fill + * + * @return Pointer to the memory area + */ +t_void * +moal_memset(IN t_void * pmoal_handle, + IN t_void * pmem, IN t_u8 byte, IN t_u32 num) +{ + t_void *p = pmem; + + if (pmem && num) + p = memset(pmem, byte, num); + + return p; +} + +/** + * @brief Copy memory from one area to another + * + * @param pmoal_handle Pointer to the MOAL context + * @param pdest Pointer to the dest memory + * @param psrc Pointer to the src memory + * @param num Number of bytes to move + * + * @return Pointer to the dest memory + */ +t_void * +moal_memcpy(IN t_void * pmoal_handle, + IN t_void * pdest, IN const t_void * psrc, IN t_u32 num) +{ + t_void *p = pdest; + + if (pdest && psrc && num) + p = memcpy(pdest, psrc, num); + + return p; +} + +/** + * @brief Move memory from one area to another + * + * @param pmoal_handle Pointer to the MOAL context + * @param pdest Pointer to the dest memory + * @param psrc Pointer to the src memory + * @param num Number of bytes to move + * + * @return Pointer to the dest memory + */ +t_void * +moal_memmove(IN t_void * pmoal_handle, + IN t_void * pdest, IN const t_void * psrc, IN t_u32 num) +{ + t_void *p = pdest; + + if (pdest && psrc && num) + p = memmove(pdest, psrc, num); + + return p; +} + +/** + * @brief Compare two memory areas + * + * @param pmoal_handle Pointer to the MOAL context + * @param pmem1 Pointer to the first memory + * @param pmem2 Pointer to the second memory + * @param num Number of bytes to compare + * + * @return Compare result returns by memcmp + */ +t_s32 +moal_memcmp(IN t_void * pmoal_handle, + IN const t_void * pmem1, IN const t_void * pmem2, IN t_u32 num) +{ + t_s32 result; + + result = memcmp(pmem1, pmem2, num); + + return result; +} + +/** + * @brief Delay function + * + * @param pmoal_handle Pointer to the MOAL context + * @param delay delay in micro-second + * + * @return N/A + */ +t_void +moal_udelay(IN t_void * pmoal_handle, IN t_u32 delay) +{ + if (delay >= 1000) + mdelay(delay / 1000); + if (delay % 1000) + udelay(delay % 1000); +} + +/** + * @brief Retrieves the current system time + * + * @param pmoal_handle Pointer to the MOAL context + * @param psec Pointer to buf for the seconds of system time + * @param pusec Pointer to buf the micro seconds of system time + * + * @return MLAN_STATUS_SUCCESS + */ +mlan_status +moal_get_system_time(IN t_void * pmoal_handle, + OUT t_u32 * psec, OUT t_u32 * pusec) +{ + struct timeval t; + + do_gettimeofday(&t); + *psec = (t_u32) t.tv_sec; + *pusec = (t_u32) t.tv_usec; + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Initializes the timer + * + * @param pmoal_handle Pointer to the MOAL context + * @param pptimer Pointer to the timer + * @param callback Pointer to callback function + * @param pcontext Pointer to context + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +moal_init_timer(IN t_void * pmoal_handle, + OUT t_void ** pptimer, + IN t_void(*callback) (t_void * pcontext), IN t_void * pcontext) +{ + moal_drv_timer *timer = NULL; + + if (! + (timer = + (moal_drv_timer *) kmalloc(sizeof(moal_drv_timer), GFP_KERNEL))) + return MLAN_STATUS_FAILURE; + woal_initialize_timer(timer, callback, pcontext); + *pptimer = (t_void *) timer; + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Free the timer + * + * @param pmoal_handle Pointer to the MOAL context + * @param ptimer Pointer to the timer + * + * @return MLAN_STATUS_SUCCESS + */ +mlan_status +moal_free_timer(IN t_void * pmoal_handle, IN t_void * ptimer) +{ + moal_drv_timer *timer = (moal_drv_timer *) ptimer; + + if (timer) { + if ((timer->timer_is_canceled == MFALSE) && timer->time_period) { + PRINTM(MWARN, "mlan try to free timer without stop timer!\n"); + woal_cancel_timer(timer); + } + kfree(timer); + } + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Start the timer + * + * @param pmoal_handle Pointer to the MOAL context + * @param ptimer Pointer to the timer + * @param periodic Periodic timer + * @param msec Timer value in milliseconds + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +moal_start_timer(IN t_void * pmoal_handle, + IN t_void * ptimer, IN t_u8 periodic, IN t_u32 msec) +{ + if (!ptimer) + return MLAN_STATUS_FAILURE; + + ((moal_drv_timer *) ptimer)->timer_is_periodic = periodic; + woal_mod_timer((moal_drv_timer *) ptimer, msec); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Stop the timer + * + * @param pmoal_handle Pointer to the MOAL context + * @param ptimer Pointer to the timer + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +moal_stop_timer(IN t_void * pmoal_handle, IN t_void * ptimer) +{ + if (!ptimer) + return MLAN_STATUS_FAILURE; + woal_cancel_timer((moal_drv_timer *) ptimer); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Initializes the lock + * + * @param pmoal_handle Pointer to the MOAL context + * @param pplock Pointer to the lock + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +moal_init_lock(IN t_void * pmoal_handle, OUT t_void ** pplock) +{ + moal_handle *handle = (moal_handle *) pmoal_handle; + moal_lock *mlock = NULL; + + if (!(mlock = (moal_lock *) kmalloc(sizeof(moal_lock), GFP_ATOMIC))) + return MLAN_STATUS_FAILURE; + spin_lock_init(&mlock->lock); + *pplock = (t_void *) mlock; + + handle->lock_count++; + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Free the lock + * + * @param pmoal_handle Pointer to the MOAL context + * @param plock Lock + * + * @return MLAN_STATUS_SUCCESS + */ +mlan_status +moal_free_lock(IN t_void * pmoal_handle, IN t_void * plock) +{ + moal_handle *handle = (moal_handle *) pmoal_handle; + moal_lock *mlock = plock; + + if (mlock) { + kfree(mlock); + handle->lock_count--; + } + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Request a spin lock + * + * @param pmoal_handle Pointer to the MOAL context + * @param plock Pointer to the lock + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +moal_spin_lock(IN t_void * pmoal_handle, IN t_void * plock) +{ + moal_lock *mlock = plock; + unsigned long flags = 0; + + if (mlock) { + spin_lock_irqsave(&mlock->lock, flags); + mlock->flags = flags; + return MLAN_STATUS_SUCCESS; + } else { + return MLAN_STATUS_FAILURE; + } +} + +/** + * @brief Request a spin_unlock + * + * @param pmoal_handle Pointer to the MOAL context + * @param plock Pointer to the lock + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +moal_spin_unlock(IN t_void * pmoal_handle, IN t_void * plock) +{ + moal_lock *mlock = (moal_lock *) plock; + + if (mlock) { + spin_unlock_irqrestore(&mlock->lock, mlock->flags); + + return MLAN_STATUS_SUCCESS; + } else { + return MLAN_STATUS_FAILURE; + } +} + +/** + * @brief This function reads one block of firmware data from MOAL + * + * @param pmoal_handle Pointer to the MOAL context + * @param offset Offset from where the data will be copied + * @param len Length to be copied + * @param pbuf Buffer where the data will be copied + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +moal_get_fw_data(IN t_void * pmoal_handle, + IN t_u32 offset, IN t_u32 len, OUT t_u8 * pbuf) +{ + moal_handle *handle = (moal_handle *) pmoal_handle; + + if (!pbuf || !len) + return MLAN_STATUS_FAILURE; + + if (offset + len > handle->firmware->size) + return MLAN_STATUS_FAILURE; + + memcpy(pbuf, handle->firmware->data + offset, len); + + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief This function is called when MLAN completes the initialization firmware. + * + * @param pmoal_handle Pointer to the MOAL context + * @param status The status code for mlan_init_fw request + * + * @return MLAN_STATUS_SUCCESS + */ +mlan_status +moal_init_fw_complete(IN t_void * pmoal_handle, IN mlan_status status) +{ + moal_handle *handle = (moal_handle *) pmoal_handle; + ENTER(); + if (status == MLAN_STATUS_SUCCESS) + handle->hardware_status = HardwareStatusReady; + handle->init_wait_q_woken = MTRUE; + wake_up_interruptible(&handle->init_wait_q); + LEAVE(); + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief This function is called when MLAN shutdown firmware is completed. + * + * @param pmoal_handle Pointer to the MOAL context + * @param status The status code for mlan_shutdown request + * + * @return MLAN_STATUS_SUCCESS + */ +mlan_status +moal_shutdown_fw_complete(IN t_void * pmoal_handle, IN mlan_status status) +{ + moal_handle *handle = (moal_handle *) pmoal_handle; + ENTER(); + handle->hardware_status = HardwareStatusNotReady; + handle->init_wait_q_woken = MTRUE; + wake_up_interruptible(&handle->init_wait_q); + LEAVE(); + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief This function is called when an MLAN IOCTL is completed. + * + * @param pmoal_handle Pointer to the MOAL context + * @param pioctl_req pointer to structure mlan_ioctl_req + * @param status The status code for mlan_ioctl request + * + * @return MLAN_STATUS_SUCCESS + */ +mlan_status +moal_ioctl_complete(IN t_void * pmoal_handle, + IN pmlan_ioctl_req pioctl_req, IN mlan_status status) +{ + moal_handle *handle = (moal_handle *) pmoal_handle; + moal_private *priv = NULL; + wait_queue *wait; + ENTER(); + + if (!atomic_read(&handle->ioctl_pending)) + PRINTM(MERROR, "ERR: Unexpected IOCTL completed: %p\n", pioctl_req); + else + atomic_dec(&handle->ioctl_pending); + priv = woal_bss_index_to_priv(handle, pioctl_req->bss_index); + + wait = (wait_queue *) pioctl_req->reserved_1; + PRINTM(MIOCTL, + "IOCTL completed: %p id=0x%x sub_id=0x%x, action=%d, status=%d, status_code=0x%x\n", + pioctl_req, pioctl_req->req_id, (*(t_u32 *) pioctl_req->pbuf), + (int) pioctl_req->action, status, pioctl_req->status_code); + if (wait) { + wait->condition = MTRUE; + wait->status = status; + if ((status != MLAN_STATUS_SUCCESS) && + (pioctl_req->status_code == MLAN_ERROR_CMD_TIMEOUT)) { + PRINTM(MERROR, "IOCTL: command timeout\n"); + } else { + wake_up_interruptible(wait->wait); + } + } else { + if (priv && (status == MLAN_STATUS_SUCCESS) && + (pioctl_req->action == MLAN_ACT_GET)) + woal_process_ioctl_resp(priv, pioctl_req); + if (status != MLAN_STATUS_SUCCESS) + PRINTM(MERROR, + "IOCTL failed: id=0x%x, action=%d, status_code=0x%x\n", + pioctl_req->req_id, (int) pioctl_req->action, + pioctl_req->status_code); + kfree(pioctl_req); + } + LEAVE(); + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief This function allocates mlan_buffer. + * + * @param pmoal_handle Pointer to the MOAL context + * @param size allocation size requested + * @param pmbuf pointer to pointer to the allocated buffer + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +moal_alloc_mlan_buffer(IN t_void * pmoal_handle, + IN t_u32 size, OUT pmlan_buffer * pmbuf) +{ + if (NULL == + (*pmbuf = woal_alloc_mlan_buffer((moal_handle *) pmoal_handle, size))) + return MLAN_STATUS_FAILURE; + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief This function frees mlan_buffer. + * + * @param pmoal_handle Pointer to the MOAL context + * @param pmbuf pointer to buffer to be freed + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +moal_free_mlan_buffer(IN t_void * pmoal_handle, IN pmlan_buffer pmbuf) +{ + if (!pmbuf) + return MLAN_STATUS_FAILURE; + woal_free_mlan_buffer((moal_handle *) pmoal_handle, pmbuf); + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief This function is called when MLAN complete send data packet. + * + * @param pmoal_handle Pointer to the MOAL context + * @param pmbuf Pointer to the mlan buffer structure + * @param status The status code for mlan_send_packet request + * + * @return MLAN_STATUS_SUCCESS + */ +mlan_status +moal_send_packet_complete(IN t_void * pmoal_handle, + IN pmlan_buffer pmbuf, IN mlan_status status) +{ + moal_private *priv = NULL; + moal_handle *handle = (moal_handle *) pmoal_handle; + struct sk_buff *skb = NULL; + int i; + ENTER(); + if (pmbuf && pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA) { + woal_free_mlan_buffer(handle, pmbuf); + atomic_dec(&handle->tx_pending); + LEAVE(); + return MLAN_STATUS_SUCCESS; + } + if (pmbuf) { + priv = woal_bss_index_to_priv(pmoal_handle, pmbuf->bss_index); + skb = (struct sk_buff *) pmbuf->pdesc; + if (priv) { + woal_set_trans_start(priv->netdev); + if (skb) { + if (status == MLAN_STATUS_SUCCESS) { + priv->stats.tx_packets++; + priv->stats.tx_bytes += skb->len; + } else { + priv->stats.tx_errors++; + } + if (atomic_dec_return(&handle->tx_pending) < LOW_TX_PENDING) { + for (i = 0; i < handle->priv_num; i++) { +#ifdef STA_SUPPORT + if ((GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA) + && (handle->priv[i]->media_connected || + priv->is_adhoc_link_sensed)) { + woal_wake_queue(handle->priv[i]->netdev); + } +#endif +#ifdef UAP_SUPPORT + if ((GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_UAP) + && (handle->priv[i]->media_connected)) { + woal_wake_queue(handle->priv[i]->netdev); + } +#endif + } + } + } + } + if (skb) + dev_kfree_skb_any(skb); + } + LEAVE(); + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief This function write a command/data packet to card. + * This function blocks the call until it finishes + * + * @param pmoal_handle Pointer to the MOAL context + * @param pmbuf Pointer to the mlan buffer structure + * @param port Port number for sent + * @param timeout Timeout value in milliseconds (if 0 the wait is forever) + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +moal_write_data_sync(IN t_void * pmoal_handle, + IN pmlan_buffer pmbuf, IN t_u32 port, IN t_u32 timeout) +{ + return woal_write_data_sync((moal_handle *) pmoal_handle, pmbuf, port, + timeout); +} + +/** + * @brief This function read data packet/event/command from card. + * This function blocks the call until it finish + * + * @param pmoal_handle Pointer to the MOAL context + * @param pmbuf Pointer to the mlan buffer structure + * @param port Port number for read + * @param timeout Timeout value in milliseconds (if 0 the wait is forever) + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +moal_read_data_sync(IN t_void * pmoal_handle, + IN OUT pmlan_buffer pmbuf, IN t_u32 port, IN t_u32 timeout) +{ + return woal_read_data_sync((moal_handle *) pmoal_handle, pmbuf, port, + timeout); +} + +/** + * @brief This function writes data into card register. + * + * @param pmoal_handle Pointer to the MOAL context + * @param reg register offset + * @param data value + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +moal_write_reg(IN t_void * pmoal_handle, IN t_u32 reg, IN t_u32 data) +{ + return woal_write_reg((moal_handle *) pmoal_handle, reg, data); +} + +/** + * @brief This function reads data from card register. + * + * @param pmoal_handle Pointer to the MOAL context + * @param reg register offset + * @param data value + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +moal_read_reg(IN t_void * pmoal_handle, IN t_u32 reg, OUT t_u32 * data) +{ + return woal_read_reg((moal_handle *) pmoal_handle, reg, data); +} + +/** + * @brief This function uploads the packet to the network stack + * + * @param pmoal_handle Pointer to the MOAL context + * @param pmbuf Pointer to the mlan buffer structure + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +moal_recv_packet(IN t_void * pmoal_handle, IN pmlan_buffer pmbuf) +{ + mlan_status status = MLAN_STATUS_SUCCESS; + moal_private *priv = NULL; + struct sk_buff *skb = NULL; + ENTER(); + if (pmbuf) { + priv = woal_bss_index_to_priv(pmoal_handle, pmbuf->bss_index); + skb = (struct sk_buff *) pmbuf->pdesc; + if (priv) { + if (skb) { + skb_reserve(skb, pmbuf->data_offset); + skb_put(skb, pmbuf->data_len); + pmbuf->pdesc = NULL; + pmbuf->pbuf = NULL; + pmbuf->data_offset = pmbuf->data_len = 0; + } else { + PRINTM(MERROR, "%s without skb attach!!!\n", __FUNCTION__); + if (!(skb = dev_alloc_skb(pmbuf->data_len + MLAN_NET_IP_ALIGN))) { + PRINTM(MERROR, "%s fail to alloc skb\n", __FUNCTION__); + status = MLAN_STATUS_FAILURE; + priv->stats.rx_dropped++; + goto done; + } + skb_reserve(skb, MLAN_NET_IP_ALIGN); + memcpy(skb->data, (t_u8 *) (pmbuf->pbuf + pmbuf->data_offset), + pmbuf->data_len); + skb_put(skb, pmbuf->data_len); + } + skb->dev = priv->netdev; + skb->protocol = eth_type_trans(skb, priv->netdev); + skb->ip_summed = CHECKSUM_NONE; + priv->stats.rx_bytes += skb->len; + priv->stats.rx_packets++; + if (in_interrupt()) + netif_rx(skb); + else + netif_rx_ni(skb); + } + } + done: + LEAVE(); + return status; +} + +/** + * @brief This function handles event receive + * + * @param pmoal_handle Pointer to the MOAL context + * @param pmevent Pointer to the mlan event structure + * + * @return MLAN_STATUS_SUCCESS + */ +mlan_status +moal_recv_event(IN t_void * pmoal_handle, IN pmlan_event pmevent) +{ + moal_private *priv = NULL; +#if defined(STA_WEXT) || defined(UAP_SUPPORT) + moal_private *pmpriv = NULL; +#endif +#if defined(STA_WEXT) || defined(UAP_WEXT) +#if defined(STA_SUPPORT) || defined(UAP_WEXT) +#if defined(UAP_SUPPORT) || defined(STA_WEXT) + union iwreq_data wrqu; +#endif +#endif +#endif +#if defined(SDIO_SUSPEND_RESUME) + mlan_ds_ps_info pm_info; +#endif + ENTER(); + + PRINTM(MEVENT, "event id:0x%x\n", pmevent->event_id); + priv = woal_bss_index_to_priv(pmoal_handle, pmevent->bss_index); + if (priv == NULL) { + PRINTM(MERROR, "%s: priv is null\n", __FUNCTION__); + goto done; + } + switch (pmevent->event_id) { +#ifdef STA_SUPPORT + case MLAN_EVENT_ID_FW_ADHOC_LINK_SENSED: + priv->is_adhoc_link_sensed = MTRUE; + if (!netif_carrier_ok(priv->netdev)) + netif_carrier_on(priv->netdev); + woal_wake_queue(priv->netdev); +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) + woal_send_iwevcustom_event(priv, CUS_EVT_ADHOC_LINK_SENSED); +#endif + break; + + case MLAN_EVENT_ID_FW_ADHOC_LINK_LOST: + woal_stop_queue(priv->netdev); + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); + priv->is_adhoc_link_sensed = MFALSE; +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) + woal_send_iwevcustom_event(priv, CUS_EVT_ADHOC_LINK_LOST); +#endif + break; + + case MLAN_EVENT_ID_DRV_CONNECTED: +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext) && pmevent->event_len == ETH_ALEN) { + memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN); + memcpy(wrqu.ap_addr.sa_data, pmevent->event_buf, ETH_ALEN); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(priv->netdev, SIOCGIWAP, &wrqu, NULL); + } +#endif +#ifdef STA_CFG80211 + if (IS_STA_CFG80211(cfg80211_wext)) + memcpy(priv->cfg_bssid, pmevent->event_buf, ETH_ALEN); +#endif + priv->media_connected = MTRUE; + if (!netif_carrier_ok(priv->netdev)) + netif_carrier_on(priv->netdev); + woal_wake_queue(priv->netdev); + break; + + case MLAN_EVENT_ID_DRV_SCAN_REPORT: + PRINTM(MINFO, "Scan report\n"); + if (priv->phandle->scan_pending_on_block == MTRUE) { + priv->phandle->scan_pending_on_block = MFALSE; + MOAL_REL_SEMAPHORE(&priv->phandle->async_sem); + } + + if (priv->report_scan_result) { +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) { + memset(&wrqu, 0, sizeof(union iwreq_data)); + wireless_send_event(priv->netdev, SIOCGIWSCAN, &wrqu, NULL); + } +#endif +#ifdef STA_CFG80211 + if (IS_STA_CFG80211(cfg80211_wext)) { + woal_inform_bss_from_scan_result(priv, NULL); + PRINTM(MINFO, "Reporting scan results\n"); + if (priv->scan_request) { + cfg80211_scan_done(priv->scan_request, MFALSE); + priv->scan_request = NULL; + } + } +#endif /* STA_CFG80211 */ + + priv->report_scan_result = MFALSE; + } + break; + + case MLAN_EVENT_ID_DRV_OBSS_SCAN_PARAM: +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) { + memset(&wrqu, 0, sizeof(union iwreq_data)); + memmove((pmevent->event_buf + strlen(CUS_EVT_OBSS_SCAN_PARAM) + 1), + pmevent->event_buf, pmevent->event_len); + memcpy(pmevent->event_buf, (t_u8 *) CUS_EVT_OBSS_SCAN_PARAM, + strlen(CUS_EVT_OBSS_SCAN_PARAM)); + pmevent->event_buf[strlen(CUS_EVT_OBSS_SCAN_PARAM)] = 0; + + wrqu.data.pointer = pmevent->event_buf; + wrqu.data.length = + pmevent->event_len + strlen(CUS_EVT_OBSS_SCAN_PARAM) + 1; + wireless_send_event(priv->netdev, IWEVCUSTOM, &wrqu, + pmevent->event_buf); + } +#endif + break; + case MLAN_EVENT_ID_FW_BW_CHANGED: +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) { + memset(&wrqu, 0, sizeof(union iwreq_data)); + memmove((pmevent->event_buf + strlen(CUS_EVT_BW_CHANGED) + 1), + pmevent->event_buf, pmevent->event_len); + memcpy(pmevent->event_buf, (t_u8 *) CUS_EVT_BW_CHANGED, + strlen(CUS_EVT_BW_CHANGED)); + pmevent->event_buf[strlen(CUS_EVT_BW_CHANGED)] = 0; + + wrqu.data.pointer = pmevent->event_buf; + wrqu.data.length = + pmevent->event_len + strlen(CUS_EVT_BW_CHANGED) + 1; + wireless_send_event(priv->netdev, IWEVCUSTOM, &wrqu, + pmevent->event_buf); + } +#endif + break; + + case MLAN_EVENT_ID_FW_DISCONNECTED: + woal_send_disconnect_to_system(priv); +#ifdef STA_CFG80211 + if (IS_STA_CFG80211(cfg80211_wext)) { + if (!priv->cfg_disconnect && + priv->wdev->iftype != NL80211_IFTYPE_ADHOC) { + PRINTM(MINFO, "Successfully disconnected from %pM:" + " Reason code %d\n", priv->cfg_bssid, + WLAN_REASON_DEAUTH_LEAVING); + /* This function must be called only when disconnect issued by + the FW, i.e. disconnected by AP. For IBSS mode this call is + not valid */ + cfg80211_disconnected(priv->netdev, + WLAN_REASON_DEAUTH_LEAVING, NULL, 0, + GFP_KERNEL); + } + priv->cfg_disconnect = 0; + } +#endif /* STA_CFG80211 */ + /* Reset wireless stats signal info */ +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) { + priv->w_stats.qual.level = 0; + priv->w_stats.qual.noise = 0; + } +#endif + +#ifdef REASSOCIATION + if (priv->reassoc_on == MTRUE) { + PRINTM(MINFO, "Reassoc: trigger the timer\n"); + priv->reassoc_required = MTRUE; + priv->phandle->is_reassoc_timer_set = MTRUE; + woal_mod_timer(&priv->phandle->reassoc_timer, + REASSOC_TIMER_DEFAULT); + } else { + priv->rate_index = AUTO_RATE; + } +#endif /* REASSOCIATION */ + break; + + case MLAN_EVENT_ID_FW_MIC_ERR_UNI: +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) { +#if WIRELESS_EXT >= 18 + woal_send_mic_error_event(priv, MLAN_EVENT_ID_FW_MIC_ERR_UNI); +#else + woal_send_iwevcustom_event(priv, CUS_EVT_MLME_MIC_ERR_UNI); +#endif + } +#endif /* STA_WEXT */ + break; + case MLAN_EVENT_ID_FW_MIC_ERR_MUL: +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) { +#if WIRELESS_EXT >= 18 + woal_send_mic_error_event(priv, MLAN_EVENT_ID_FW_MIC_ERR_MUL); +#else + woal_send_iwevcustom_event(priv, CUS_EVT_MLME_MIC_ERR_MUL); +#endif + } +#endif /* STA_WEXT */ + break; + case MLAN_EVENT_ID_FW_BCN_RSSI_LOW: +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) + woal_send_iwevcustom_event(priv, CUS_EVT_BEACON_RSSI_LOW); +#endif + break; + case MLAN_EVENT_ID_FW_BCN_RSSI_HIGH: +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) + woal_send_iwevcustom_event(priv, CUS_EVT_BEACON_RSSI_HIGH); +#endif + break; + case MLAN_EVENT_ID_FW_BCN_SNR_LOW: +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) + woal_send_iwevcustom_event(priv, CUS_EVT_BEACON_SNR_LOW); +#endif + break; + case MLAN_EVENT_ID_FW_BCN_SNR_HIGH: +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) + woal_send_iwevcustom_event(priv, CUS_EVT_BEACON_SNR_HIGH); +#endif + break; + case MLAN_EVENT_ID_FW_MAX_FAIL: +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) + woal_send_iwevcustom_event(priv, CUS_EVT_MAX_FAIL); +#endif + break; + case MLAN_EVENT_ID_FW_DATA_RSSI_LOW: +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) + woal_send_iwevcustom_event(priv, CUS_EVT_DATA_RSSI_LOW); +#endif + break; + case MLAN_EVENT_ID_FW_DATA_SNR_LOW: +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) + woal_send_iwevcustom_event(priv, CUS_EVT_DATA_SNR_LOW); +#endif + break; + case MLAN_EVENT_ID_FW_DATA_RSSI_HIGH: +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) + woal_send_iwevcustom_event(priv, CUS_EVT_DATA_RSSI_HIGH); +#endif + break; + case MLAN_EVENT_ID_FW_DATA_SNR_HIGH: +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) + woal_send_iwevcustom_event(priv, CUS_EVT_DATA_SNR_HIGH); +#endif + break; + case MLAN_EVENT_ID_FW_LINK_QUALITY: +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) + woal_send_iwevcustom_event(priv, CUS_EVT_LINK_QUALITY); +#endif + break; + case MLAN_EVENT_ID_FW_PORT_RELEASE: +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) + woal_send_iwevcustom_event(priv, CUS_EVT_PORT_RELEASE); +#endif + break; + case MLAN_EVENT_ID_FW_PRE_BCN_LOST: +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) + woal_send_iwevcustom_event(priv, CUS_EVT_PRE_BEACON_LOST); +#endif + break; + case MLAN_EVENT_ID_FW_WMM_CONFIG_CHANGE: +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) + woal_send_iwevcustom_event(priv, WMM_CONFIG_CHANGE_INDICATION); +#endif + break; + + case MLAN_EVENT_ID_DRV_REPORT_STRING: + PRINTM(MINFO, "Report string %s\n", pmevent->event_buf); +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) + woal_send_iwevcustom_event(priv, pmevent->event_buf); +#endif + break; + case MLAN_EVENT_ID_FW_WEP_ICV_ERR: + DBG_HEXDUMP(MCMD_D, "WEP ICV error", pmevent->event_buf, + pmevent->event_len); +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) + woal_send_iwevcustom_event(priv, CUS_EVT_WEP_ICV_ERR); +#endif + break; + + case MLAN_EVENT_ID_DRV_DEFER_HANDLING: + queue_work(priv->phandle->workqueue, &priv->phandle->main_work); + break; + case MLAN_EVENT_ID_DRV_DBG_DUMP: + woal_moal_debug_info(priv, NULL, MFALSE); + break; + case MLAN_EVENT_ID_FW_BG_SCAN: + if (priv->media_connected == MTRUE) + priv->bg_scan_start = MFALSE; + priv->bg_scan_reported = MTRUE; +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) { + woal_send_iwevcustom_event(priv, CUS_EVT_BG_SCAN); + memset(&wrqu, 0, sizeof(union iwreq_data)); + wireless_send_event(priv->netdev, SIOCGIWSCAN, &wrqu, NULL); + } +#endif + break; + case MLAN_EVENT_ID_FW_CHANNEL_SWITCH_ANN: +#ifdef STA_WEXT + if (IS_STA_WEXT(cfg80211_wext)) + woal_send_iwevcustom_event(priv, CUS_EVT_CHANNEL_SWITCH_ANN); +#endif + break; +#endif /* STA_SUPPORT */ + case MLAN_EVENT_ID_FW_STOP_TX: + woal_stop_queue(priv->netdev); + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); + break; + case MLAN_EVENT_ID_FW_START_TX: + if (!netif_carrier_ok(priv->netdev)) + netif_carrier_on(priv->netdev); + woal_wake_queue(priv->netdev); + break; + case MLAN_EVENT_ID_FW_HS_WAKEUP: + /* simulate HSCFG_CANCEL command */ + woal_cancel_hs(priv, MOAL_NO_WAIT); +#ifdef STA_WEXT +#ifdef STA_SUPPORT + if (IS_STA_WEXT(cfg80211_wext) && (pmpriv = woal_get_priv((moal_handle + *) + pmoal_handle, + MLAN_BSS_ROLE_STA))) + woal_send_iwevcustom_event(pmpriv, CUS_EVT_HS_WAKEUP); +#endif /* STA_SUPPORT */ +#endif /* STA_WEXT */ +#ifdef UAP_SUPPORT + if ((pmpriv = + woal_get_priv((moal_handle *) pmoal_handle, MLAN_BSS_ROLE_UAP))) { + pmevent->event_id = UAP_EVENT_ID_HS_WAKEUP; + woal_broadcast_event(pmpriv, (t_u8 *) & pmevent->event_id, + sizeof(t_u32)); + } +#endif /* UAP_SUPPORT */ + break; + case MLAN_EVENT_ID_DRV_HS_ACTIVATED: +#ifdef STA_WEXT +#ifdef STA_SUPPORT + if (IS_STA_WEXT(cfg80211_wext) && (pmpriv = woal_get_priv((moal_handle + *) + pmoal_handle, + MLAN_BSS_ROLE_STA))) + { + woal_send_iwevcustom_event(pmpriv, CUS_EVT_HS_ACTIVATED); + } +#endif /* STA_SUPPORT */ +#endif /* STA_WEXT */ +#if defined(UAP_SUPPORT) + if ((pmpriv = + woal_get_priv((moal_handle *) pmoal_handle, MLAN_BSS_ROLE_UAP))) { + pmevent->event_id = UAP_EVENT_ID_DRV_HS_ACTIVATED; + woal_broadcast_event(pmpriv, (t_u8 *) & pmevent->event_id, + sizeof(t_u32)); + } +#endif +#if defined(SDIO_SUSPEND_RESUME) + if (priv->phandle->suspend_fail == MFALSE) { + woal_get_pm_info(priv, &pm_info); + if (pm_info.is_suspend_allowed == MTRUE) { + priv->phandle->hs_activated = MTRUE; +#ifdef MMC_PM_FUNC_SUSPENDED + woal_wlan_is_suspended(priv->phandle); +#endif + } + priv->phandle->hs_activate_wait_q_woken = MTRUE; + wake_up_interruptible(&priv->phandle->hs_activate_wait_q); + } +#endif + break; + case MLAN_EVENT_ID_DRV_HS_DEACTIVATED: +#ifdef STA_WEXT +#ifdef STA_SUPPORT + if (IS_STA_WEXT(cfg80211_wext) && (pmpriv = woal_get_priv((moal_handle + *) + pmoal_handle, + MLAN_BSS_ROLE_STA))) + { + woal_send_iwevcustom_event(pmpriv, CUS_EVT_HS_DEACTIVATED); + } +#endif +#endif +#if defined(UAP_SUPPORT) + if ((pmpriv = + woal_get_priv((moal_handle *) pmoal_handle, MLAN_BSS_ROLE_UAP))) { + pmevent->event_id = UAP_EVENT_ID_DRV_HS_DEACTIVATED; + woal_broadcast_event(pmpriv, (t_u8 *) & pmevent->event_id, + sizeof(t_u32)); + } +#endif +#if defined(SDIO_SUSPEND_RESUME) + priv->phandle->hs_activated = MFALSE; +#endif + break; +#ifdef UAP_SUPPORT + case MLAN_EVENT_ID_UAP_FW_BSS_START: + priv->bss_started = MTRUE; + memcpy(priv->current_addr, pmevent->event_buf + 6, ETH_ALEN); + memcpy(priv->netdev->dev_addr, priv->current_addr, ETH_ALEN); + woal_broadcast_event(priv, pmevent->event_buf, pmevent->event_len); + break; + case MLAN_EVENT_ID_UAP_FW_BSS_ACTIVE: + priv->media_connected = MTRUE; + if (!netif_carrier_ok(priv->netdev)) + netif_carrier_on(priv->netdev); + woal_wake_queue(priv->netdev); + woal_broadcast_event(priv, pmevent->event_buf, pmevent->event_len); + break; + case MLAN_EVENT_ID_UAP_FW_BSS_IDLE: + priv->media_connected = MFALSE; + woal_stop_queue(priv->netdev); + if (netif_carrier_ok(priv->netdev)) + netif_carrier_off(priv->netdev); + woal_broadcast_event(priv, pmevent->event_buf, pmevent->event_len); + break; +#ifdef WIFI_DIRECT_SUPPORT +#if defined(STA_CFG80211) || defined(UAP_CFG80211) + case MLAN_EVENT_ID_FW_REMAIN_ON_CHAN_EXPIRED: + if (IS_STA_OR_UAP_CFG80211(cfg80211_wext)) { + PRINTM(MEVENT, "FW_REMAIN_ON_CH0ANNEL_EXPIRED cookie = %#llx\n", + priv->phandle->cookie); + priv->phandle->remain_on_channel = MFALSE; + if (priv->phandle->cookie) { + cfg80211_remain_on_channel_expired(priv->netdev, + priv->phandle->cookie, + &priv->phandle->chan, + priv->phandle->channel_type, + GFP_ATOMIC); + priv->phandle->cookie = 0; + } + } + break; +#endif +#endif + case MLAN_EVENT_ID_UAP_FW_STA_CONNECT: +#if defined(STA_CFG80211) || defined(UAP_CFG80211) + if (IS_STA_OR_UAP_CFG80211(cfg80211_wext)) { + struct station_info sinfo; + t_u8 addr[ETH_ALEN]; + + sinfo.filled = 0; + sinfo.generation = 0; + /* copy the station mac address */ + memset(addr, 0xFF, ETH_ALEN); + memcpy(addr, pmevent->event_buf, ETH_ALEN); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0) || defined(COMPAT_WIRELESS) + if (pmevent->event_len > ETH_ALEN) { + /* set station info filled flag */ + sinfo.filled |= STATION_INFO_ASSOC_REQ_IES; + /* get the assoc request ies and length */ + sinfo.assoc_req_ies = + (const t_u8 *) (pmevent->event_buf + ETH_ALEN); + sinfo.assoc_req_ies_len = pmevent->event_len - ETH_ALEN; + + } +#endif /* KERNEL_VERSION */ + if (priv->netdev) + cfg80211_new_sta(priv->netdev, + (t_u8 *) addr, &sinfo, GFP_KERNEL); + } +#endif /* UAP_CFG80211 */ +#ifdef UAP_WEXT + if (IS_UAP_WEXT(cfg80211_wext)) { + memset(&wrqu, 0, sizeof(union iwreq_data)); + memmove((pmevent->event_buf + strlen(CUS_EVT_STA_CONNECTED) + 1), + pmevent->event_buf, pmevent->event_len); + memcpy(pmevent->event_buf, (t_u8 *) CUS_EVT_STA_CONNECTED, + strlen(CUS_EVT_STA_CONNECTED)); + pmevent->event_buf[strlen(CUS_EVT_STA_CONNECTED)] = 0; + wrqu.data.pointer = pmevent->event_buf; + if ((pmevent->event_len + strlen(CUS_EVT_STA_CONNECTED) + 1) > + IW_CUSTOM_MAX) + wrqu.data.length = ETH_ALEN + strlen(CUS_EVT_STA_CONNECTED) + 1; + else + wrqu.data.length = + pmevent->event_len + strlen(CUS_EVT_STA_CONNECTED) + 1; + wireless_send_event(priv->netdev, IWEVCUSTOM, &wrqu, + pmevent->event_buf); + } +#endif /* UAP_WEXT */ + break; + case MLAN_EVENT_ID_UAP_FW_STA_DISCONNECT: +#ifdef UAP_CFG80211 + if (IS_UAP_CFG80211(cfg80211_wext)) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) || defined(COMPAT_WIRELESS) + /* skip 2 bytes extra header will get the mac address */ + cfg80211_del_sta(priv->netdev, pmevent->event_buf + 2, GFP_KERNEL); +#endif /* KERNEL_VERSION */ + } +#endif /* UAP_CFG80211 */ +#ifdef UAP_WEXT + if (IS_UAP_WEXT(cfg80211_wext)) { + memset(&wrqu, 0, sizeof(union iwreq_data)); + memmove((pmevent->event_buf + strlen(CUS_EVT_STA_DISCONNECTED) + 1), + pmevent->event_buf, pmevent->event_len); + memcpy(pmevent->event_buf, (t_u8 *) CUS_EVT_STA_DISCONNECTED, + strlen(CUS_EVT_STA_DISCONNECTED)); + pmevent->event_buf[strlen(CUS_EVT_STA_DISCONNECTED)] = 0; + + wrqu.data.pointer = pmevent->event_buf; + wrqu.data.length = + pmevent->event_len + strlen(CUS_EVT_STA_DISCONNECTED) + 1; + wireless_send_event(priv->netdev, IWEVCUSTOM, &wrqu, + pmevent->event_buf); + } +#endif /* UAP_WEXT */ + break; + case MLAN_EVENT_ID_DRV_MGMT_FRAME: +#ifdef WIFI_DIRECT_SUPPORT +#if defined(STA_CFG80211) || defined(UAP_CFG80211) + if (IS_STA_OR_UAP_CFG80211(cfg80211_wext)) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) || defined(COMPAT_WIRELESS) + if (priv->netdev && priv->netdev->ieee80211_ptr->wiphy->mgmt_stypes) { + /* frmctl + durationid + addr1 + addr2 + addr3 + seqctl */ +#define PACKET_ADDR4_POS (2 + 2 + 6 + 6 + 6 + 2) + t_u8 *pkt; + pkt = ((t_u8 *) pmevent->event_buf + sizeof(pmevent->event_id)); + + /* move addr4 */ + memmove(pkt + PACKET_ADDR4_POS, + pkt + PACKET_ADDR4_POS + ETH_ALEN, + pmevent->event_len - sizeof(pmevent->event_id) + - PACKET_ADDR4_POS - ETH_ALEN); + cfg80211_rx_mgmt(priv->netdev, priv->phandle->chan.center_freq, + ((const t_u8 *) pmevent->event_buf) + + sizeof(pmevent->event_id), + pmevent->event_len - sizeof(pmevent->event_id) + - MLAN_MAC_ADDR_LENGTH, GFP_ATOMIC); + } +#endif /* KERNEL_VERSION */ + } +#endif /* STA_CFG80211 || UAP_CFG80211 */ +#endif /* WIFI_DIRECT_SUPPORT */ +#ifdef UAP_WEXT + if (IS_UAP_WEXT(cfg80211_wext)) { + woal_broadcast_event(priv, pmevent->event_buf, pmevent->event_len); + } +#endif /* UAP_WEXT */ + break; +#endif /* UAP_SUPPORT */ + case MLAN_EVENT_ID_DRV_PASSTHRU: + woal_broadcast_event(priv, pmevent->event_buf, pmevent->event_len); + break; + case MLAN_EVENT_ID_DRV_MEAS_REPORT: + /* We have received measurement report, wakeup measurement wait queue */ + PRINTM(MINFO, "Measurement Report\n"); + /* Going out of CAC checking period */ + if (priv->phandle->cac_period == MTRUE) { + priv->phandle->cac_period = MFALSE; + if (priv->phandle->meas_wait_q_woken == MFALSE) { + priv->phandle->meas_wait_q_woken = MTRUE; + wake_up_interruptible(&priv->phandle->meas_wait_q); + } + + /* Execute delayed BSS START command */ + if (priv->phandle->delay_bss_start == MTRUE) { + mlan_ioctl_req *req = NULL; + mlan_ds_bss *bss = NULL; + + /* Clear flag */ + priv->phandle->delay_bss_start = MFALSE; + + PRINTM(MMSG, "Now CAC measure period end. " + "Execute delayed BSS Start command.\n"); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + bss = (mlan_ds_bss *) req->pbuf; + req->req_id = MLAN_IOCTL_BSS; + req->action = MLAN_ACT_SET; + bss->sub_command = MLAN_OID_BSS_START; + memcpy(&bss->param.ssid_bssid, + &priv->phandle->delay_ssid_bssid, + sizeof(mlan_ssid_bssid)); + + if (woal_request_ioctl(priv, req, MOAL_NO_WAIT) + != MLAN_STATUS_PENDING) { + PRINTM(MMSG, "Delayed BSS Start operation failed!\n"); + kfree(req); + } + + PRINTM(MMSG, "BSS START Complete!\n"); + } + } + default: + break; + } + done: + LEAVE(); + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief This function prints the debug message in mlan + * + * @param pmoal_handle Pointer to the MOAL context + * @param level debug level + * @param pformat point to string format buf + * + * @return N/A + */ +t_void +moal_print(IN t_void * pmoal_handle, IN t_u32 level, IN t_s8 * pformat, IN ...) +{ +#ifdef DEBUG_LEVEL1 + va_list args; + + if (level & MHEX_DUMP) { + t_u8 *buf = NULL; + int len = 0; + + va_start(args, pformat); + buf = (t_u8 *) va_arg(args, t_u8 *); + len = (int) va_arg(args, int); + va_end(args); + +#ifdef DEBUG_LEVEL2 + if (level & MINFO) + HEXDUMP((char *) pformat, buf, len); + else +#endif /* DEBUG_LEVEL2 */ + { + if (level & MERROR) + DBG_HEXDUMP(MERROR, (char *) pformat, buf, len); + if (level & MCMD_D) + DBG_HEXDUMP(MCMD_D, (char *) pformat, buf, len); + if (level & MDAT_D) + DBG_HEXDUMP(MDAT_D, (char *) pformat, buf, len); + if (level & MIF_D) + DBG_HEXDUMP(MIF_D, (char *) pformat, buf, len); + if (level & MFW_D) + DBG_HEXDUMP(MFW_D, (char *) pformat, buf, len); + if (level & MEVT_D) + DBG_HEXDUMP(MEVT_D, (char *) pformat, buf, len); + } + } else { + va_start(args, pformat); + vprintk(pformat, args); + va_end(args); + } +#endif /* DEBUG_LEVEL1 */ +} + +/** + * @brief This function prints the network interface name + * + * @param pmoal_handle Pointer to the MOAL context + * @param bss_index BSS index + * @param level debug level + * + * @return N/A + */ +t_void +moal_print_netintf(IN t_void * pmoal_handle, IN t_u32 bss_index, IN t_u32 level) +{ +#ifdef DEBUG_LEVEL1 + moal_handle *phandle = (moal_handle *) pmoal_handle; + + if (phandle && (drvdbg & level)) { + if ((bss_index < MLAN_MAX_BSS_NUM) && phandle->priv[bss_index] && + phandle->priv[bss_index]->netdev) + printk("%s: ", phandle->priv[bss_index]->netdev->name); + } +#endif /* DEBUG_LEVEL1 */ +} + +/** + * @brief This function asserts the existence of the passed argument + * + * @param pmoal_handle A pointer to moal_private structure + * @param cond Condition to check + * + * @return N/A + */ +t_void +moal_assert(IN t_void * pmoal_handle, IN t_u32 cond) +{ + if (!cond) + panic("Assert failed: Panic!"); +} diff --git a/drivers/net/wireless/sd8797/mlinux/moal_shim.h b/drivers/net/wireless/sd8797/mlinux/moal_shim.h new file mode 100644 index 000000000000..ee50a2105f0f --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/moal_shim.h @@ -0,0 +1,95 @@ +/** @file moal_shim.h + * + * @brief This file contains declaration referring to + * functions defined in moal module + * + * Copyright (C) 2008-2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ +/************************************************************* +Change Log: + 10/21/2008: initial version +************************************************************/ + +#ifndef _MOAL_H +#define _MOAL_H + +mlan_status moal_get_fw_data(IN t_void * pmoal_handle, + IN t_u32 offset, IN t_u32 len, OUT t_u8 * pbuf); +mlan_status moal_init_fw_complete(IN t_void * pmoal_handle, + IN mlan_status status); +mlan_status moal_shutdown_fw_complete(IN t_void * pmoal_handle, + IN mlan_status status); +mlan_status moal_ioctl_complete(IN t_void * pmoal_handle, + IN pmlan_ioctl_req pioctl_req, + IN mlan_status status); +mlan_status moal_alloc_mlan_buffer(IN t_void * pmoal_handle, IN t_u32 size, + OUT pmlan_buffer * pmbuf); +mlan_status moal_free_mlan_buffer(IN t_void * pmoal_handle, + IN pmlan_buffer pmbuf); +mlan_status moal_send_packet_complete(IN t_void * pmoal_handle, + IN pmlan_buffer pmbuf, + IN mlan_status status); +/** moal_write_reg */ +mlan_status moal_write_reg(IN t_void * pmoal_handle, + IN t_u32 reg, IN t_u32 data); +/** moal_read_reg */ +mlan_status moal_read_reg(IN t_void * pmoal_handle, + IN t_u32 reg, OUT t_u32 * data); +mlan_status moal_write_data_sync(IN t_void * pmoal_handle, + IN pmlan_buffer pmbuf, + IN t_u32 port, IN t_u32 timeout); +mlan_status moal_read_data_sync(IN t_void * pmoal_handle, + IN OUT pmlan_buffer pmbuf, + IN t_u32 port, IN t_u32 timeout); +mlan_status moal_recv_packet(IN t_void * pmoal_handle, IN pmlan_buffer pmbuf); +mlan_status moal_recv_event(IN t_void * pmoal_handle, IN pmlan_event pmevent); +mlan_status moal_malloc(IN t_void * pmoal_handle, + IN t_u32 size, IN t_u32 flag, OUT t_u8 ** ppbuf); +mlan_status moal_mfree(IN t_void * pmoal_handle, IN t_u8 * pbuf); +t_void *moal_memset(IN t_void * pmoal_handle, + IN t_void * pmem, IN t_u8 byte, IN t_u32 num); +t_void *moal_memcpy(IN t_void * pmoal_handle, + IN t_void * pdest, IN const t_void * psrc, IN t_u32 num); +t_void *moal_memmove(IN t_void * pmoal_handle, + IN t_void * pdest, IN const t_void * psrc, IN t_u32 num); +t_s32 moal_memcmp(IN t_void * pmoal_handle, + IN const t_void * pmem1, + IN const t_void * pmem2, IN t_u32 num); +/** moal_udelay */ +t_void moal_udelay(IN t_void * pmoal_handle, IN t_u32 udelay); +mlan_status moal_get_system_time(IN t_void * pmoal_handle, OUT t_u32 * psec, + OUT t_u32 * pusec); +mlan_status moal_init_lock(IN t_void * pmoal_handle, OUT t_void ** pplock); +mlan_status moal_free_lock(IN t_void * pmoal_handle, IN t_void * plock); +mlan_status moal_spin_lock(IN t_void * pmoal_handle, IN t_void * plock); +mlan_status moal_spin_unlock(IN t_void * pmoal_handle, IN t_void * plock); +t_void moal_print(IN t_void * pmoal_handle, IN t_u32 level, IN t_s8 * pformat, + IN ...); +t_void moal_print_netintf(IN t_void * pmoal_handle, IN t_u32 bss_index, + IN t_u32 level); +t_void moal_assert(IN t_void * pmoal_handle, IN t_u32 cond); +mlan_status moal_init_timer(IN t_void * pmoal_handle, + OUT t_void ** pptimer, + IN t_void(*callback) (t_void * pcontext), + IN t_void * pcontext); +mlan_status moal_free_timer(IN t_void * pmoal_handle, IN t_void * ptimer); +mlan_status moal_start_timer(IN t_void * pmoal_handle, + IN t_void * ptimer, + IN t_u8 periodic, IN t_u32 msec); +mlan_status moal_stop_timer(IN t_void * pmoal_handle, IN t_void * ptimer); + +#endif /*_MOAL_H */ diff --git a/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c b/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c new file mode 100644 index 000000000000..dfb4aefcbb33 --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c @@ -0,0 +1,2476 @@ +/** @file moal_sta_cfg80211.c + * + * @brief This file contains the functions for STA CFG80211. + * + * Copyright (C) 2011-2012, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +#include "moal_cfg80211.h" +#include "moal_sta_cfg80211.h" +static int woal_cfg80211_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request); + +static int woal_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_scan_request *request); + +static int woal_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme); + +static int woal_cfg80211_disconnect(struct wiphy *wiphy, + struct net_device *dev, t_u16 reason_code); + +static int woal_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *dev, + t_u8 * mac, struct station_info *sinfo); + +static int woal_cfg80211_dump_station(struct wiphy *wiphy, + struct net_device *dev, int idx, + t_u8 * mac, struct station_info *sinfo); + +static int woal_cfg80211_set_power_mgmt(struct wiphy *wiphy, + struct net_device *dev, bool enabled, + int timeout); + +static int woal_cfg80211_set_tx_power(struct wiphy *wiphy, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) && !defined(COMPAT_WIRELESS) + enum tx_power_setting type, +#else + enum nl80211_tx_power_setting type, +#endif + int dbm); + +static int woal_cfg80211_join_ibss(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ibss_params *params); + +static int woal_cfg80211_leave_ibss(struct wiphy *wiphy, + struct net_device *dev); + +#if defined(WIFI_DIRECT_SUPPORT) +#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION +static int woal_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, + struct net_device *dev, + u64 cookie); + +void woal_cfg80211_remain_on_channel_done(void *context); + +static int woal_cfg80211_remain_on_channel(struct wiphy *wiphy, + struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_channel_type + channel_type, unsigned int duration, + u64 * cookie); + +static int woal_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, + struct net_device *dev, + u64 cookie); +#endif /* KERNEL_VERSION */ +#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */ + +/** cfg80211 STA operations */ +static struct cfg80211_ops woal_cfg80211_sta_ops = { + .change_virtual_intf = woal_cfg80211_change_virtual_intf, + .scan = woal_cfg80211_scan, + .connect = woal_cfg80211_connect, + .disconnect = woal_cfg80211_disconnect, + .get_station = woal_cfg80211_get_station, + .dump_station = woal_cfg80211_dump_station, + .set_wiphy_params = woal_cfg80211_set_wiphy_params, + .set_channel = woal_cfg80211_set_channel, + .join_ibss = woal_cfg80211_join_ibss, + .leave_ibss = woal_cfg80211_leave_ibss, + .add_key = woal_cfg80211_add_key, + .del_key = woal_cfg80211_del_key, + .set_default_key = woal_cfg80211_set_default_key, + .set_power_mgmt = woal_cfg80211_set_power_mgmt, + .set_tx_power = woal_cfg80211_set_tx_power, +}; + +#if defined(WIFI_DIRECT_SUPPORT) +#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION +/** cfg80211 Wifi Direct operations */ +static struct cfg80211_ops woal_cfg80211_wifi_direct_ops = { + .add_virtual_intf = woal_cfg80211_add_virtual_intf, + .del_virtual_intf = woal_cfg80211_del_virtual_intf, + .change_virtual_intf = woal_cfg80211_change_virtual_intf, + .scan = woal_cfg80211_scan, + .connect = woal_cfg80211_connect, + .disconnect = woal_cfg80211_disconnect, + .get_station = woal_cfg80211_get_station, + .dump_station = woal_cfg80211_dump_station, + .set_wiphy_params = woal_cfg80211_set_wiphy_params, + .set_channel = woal_cfg80211_set_channel, + .add_key = woal_cfg80211_add_key, + .del_key = woal_cfg80211_del_key, + .add_beacon = woal_cfg80211_add_beacon, + .set_beacon = woal_cfg80211_set_beacon, + .del_beacon = woal_cfg80211_del_beacon, + .mgmt_frame_register = woal_cfg80211_mgmt_frame_register, + .mgmt_tx = woal_cfg80211_mgmt_tx, + .mgmt_tx_cancel_wait = woal_cfg80211_mgmt_tx_cancel_wait, + .remain_on_channel = woal_cfg80211_remain_on_channel, + .cancel_remain_on_channel = woal_cfg80211_cancel_remain_on_channel, + .set_default_key = woal_cfg80211_set_default_key, + .set_power_mgmt = woal_cfg80211_set_power_mgmt, + .set_tx_power = woal_cfg80211_set_tx_power, +}; +#endif /* KERNEL_VERSION */ +#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */ + +/******************************************************** + Local Variables +********************************************************/ +#if defined(WIFI_DIRECT_SUPPORT) +#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION +static const struct ieee80211_txrx_stypes + ieee80211_mgmt_stypes[NUM_NL80211_IFTYPES] = { + [NL80211_IFTYPE_ADHOC] = { + .tx = 0x0000, + .rx = 0x0000, + }, + [NL80211_IFTYPE_STATION] = { + .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_RESP >> 4), + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4), + }, + [NL80211_IFTYPE_AP] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4), + }, + [NL80211_IFTYPE_AP_VLAN] = { + .tx = 0x0000, + .rx = 0x0000, + }, + [NL80211_IFTYPE_P2P_CLIENT] = { + .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_RESP >> 4), + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4), + }, + [NL80211_IFTYPE_P2P_GO] = { + .tx = BIT(IEEE80211_STYPE_ACTION >> 4) | + // BIT(IEEE80211_STYPE_PROBE_RESP >> 4) | + 0, + .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4), + }, + [NL80211_IFTYPE_MESH_POINT] = { + .tx = 0x0000, + .rx = 0x0000, + }, + +}; +#endif +#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */ + +/******************************************************** + Global Variables +********************************************************/ + +/******************************************************** + Local Functions +********************************************************/ +/** + * @brief Get the encryption mode from cipher + * + * @param cipher Cipher cuite + * @param wpa_enabled WPA enable or disable + * + * @return MLAN_ENCRYPTION_MODE_* + */ +static int +woal_cfg80211_get_encryption_mode(t_u32 cipher, int *wpa_enabled) +{ + int encrypt_mode; + + ENTER(); + + *wpa_enabled = 0; + switch (cipher) { + case IW_AUTH_CIPHER_NONE: + encrypt_mode = MLAN_ENCRYPTION_MODE_NONE; + break; + case WLAN_CIPHER_SUITE_WEP40: + encrypt_mode = MLAN_ENCRYPTION_MODE_WEP40; + break; + case WLAN_CIPHER_SUITE_WEP104: + encrypt_mode = MLAN_ENCRYPTION_MODE_WEP104; + break; + case WLAN_CIPHER_SUITE_TKIP: + encrypt_mode = MLAN_ENCRYPTION_MODE_TKIP; + *wpa_enabled = 1; + break; + case WLAN_CIPHER_SUITE_CCMP: + encrypt_mode = MLAN_ENCRYPTION_MODE_CCMP; + *wpa_enabled = 1; + break; + default: + encrypt_mode = -1; + } + + LEAVE(); + return encrypt_mode; +} + +/** + * @brief Check the pairwise or group cipher for + * WEP enabled or not + * + * @param cipher MLAN Cipher cuite + * + * @return 1 -- enable or 0 -- disable + */ +static int +woal_cfg80211_is_alg_wep(t_u32 cipher) +{ + int alg = 0; + ENTER(); + + if (cipher == MLAN_ENCRYPTION_MODE_WEP40 || + cipher == MLAN_ENCRYPTION_MODE_WEP104) + alg = 1; + + LEAVE(); + return alg; +} + +/** + * @brief Convert NL802.11 channel type into driver channel type + * + * The mapping is as follows - + * NL80211_CHAN_NO_HT -> NO_SEC_CHANNEL + * NL80211_CHAN_HT20 -> NO_SEC_CHANNEL + * NL80211_CHAN_HT40PLUS -> SEC_CHANNEL_ABOVE + * NL80211_CHAN_HT40MINUS -> SEC_CHANNEL_BELOW + * Others -> NO_SEC_CHANNEL + * + * @param channel_type Channel type + * + * @return Driver channel type + */ +static int +woal_cfg80211_channel_type_to_channel(enum nl80211_channel_type channel_type) +{ + int channel; + + ENTER(); + + switch (channel_type) { + case NL80211_CHAN_NO_HT: + case NL80211_CHAN_HT20: + channel = NO_SEC_CHANNEL; + break; + case NL80211_CHAN_HT40PLUS: + channel = SEC_CHANNEL_ABOVE; + break; + case NL80211_CHAN_HT40MINUS: + channel = SEC_CHANNEL_BELOW; + break; + default: + channel = NO_SEC_CHANNEL; + } + LEAVE(); + return channel; +} + +/** + * @brief Convert secondary channel type to NL80211 channel type + * + * The mapping is as follows - + * NO_SEC_CHANNEL -> NL80211_CHAN_HT20 + * SEC_CHANNEL_ABOVE -> NL80211_CHAN_HT40PLUS + * SEC_CHANNEL_BELOW -> NL80211_CHAN_HT40MINUS + * Others -> NL80211_CHAN_HT20 + * + * @param channel_type Driver channel type + * + * @return nl80211_channel_type type + */ +static enum nl80211_channel_type +woal_channel_to_nl80211_channel_type(int channel_type) +{ + enum nl80211_channel_type channel; + + ENTER(); + + switch (channel_type) { + case NO_SEC_CHANNEL: + channel = NL80211_CHAN_HT20; + break; + case SEC_CHANNEL_ABOVE: + channel = NL80211_CHAN_HT40PLUS; + break; + case SEC_CHANNEL_BELOW: + channel = NL80211_CHAN_HT40MINUS; + break; + default: + channel = NL80211_CHAN_HT20; + } + LEAVE(); + return channel; +} + +/** + * @brief Convert driver band configuration to IEEE band type + * + * @param band Driver band configuration + * + * @return IEEE band type + */ +t_u8 +woal_band_cfg_to_ieee_band(t_u32 band) +{ + t_u8 ret_radio_type; + + ENTER(); + + switch (band) { + case BAND_A: + case BAND_AN: + case BAND_A | BAND_AN: + ret_radio_type = IEEE80211_BAND_5GHZ; + break; + case BAND_B: + case BAND_G: + case BAND_B | BAND_G: + case BAND_GN: + case BAND_B | BAND_GN: + default: + ret_radio_type = IEEE80211_BAND_2GHZ; + break; + } + + LEAVE(); + return ret_radio_type; +} + +/** + * @brief Convert NL80211 interface type to MLAN_BSS_MODE_* + * + * @param iftype Interface type of NL80211 + * + * @return Driver bss mode + */ +static t_u32 +woal_nl80211_iftype_to_mode(enum nl80211_iftype iftype) +{ + switch (iftype) { + case NL80211_IFTYPE_ADHOC: + return MLAN_BSS_MODE_IBSS; + case NL80211_IFTYPE_STATION: + return MLAN_BSS_MODE_INFRA; + case NL80211_IFTYPE_UNSPECIFIED: + default: + return MLAN_BSS_MODE_AUTO; + } +} + +/** + * @brief Control WPS Session Enable/Disable + * + * @param priv Pointer to the moal_private driver data struct + * @param enable enable/disable flag + * + * @return 0 --success, otherwise fail + */ +static int +woal_wps_cfg(moal_private * priv, int enable) +{ + int ret = 0; + mlan_ds_wps_cfg *pwps = NULL; + mlan_ioctl_req *req = NULL; + + ENTER(); + + PRINTM(MINFO, "WOAL_WPS_SESSION\n"); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wps_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + pwps = (mlan_ds_wps_cfg *) req->pbuf; + req->req_id = MLAN_IOCTL_WPS_CFG; + req->action = MLAN_ACT_SET; + pwps->sub_command = MLAN_OID_WPS_CFG_SESSION; + if (enable) + pwps->param.wps_session = MLAN_WPS_CFG_SESSION_START; + else + pwps->param.wps_session = MLAN_WPS_CFG_SESSION_END; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief configure ASSOC IE + * + * @param priv A pointer to moal private structure + * @param ie A pointer to ie data + * @param ie_len The length of ie data + * + * @return 0 -- success, otherwise fail + */ +static int +woal_cfg80211_assoc_ies_cfg(moal_private * priv, t_u8 * ie, int ie_len) +{ + int bytes_left = ie_len; + t_u8 *pcurrent_ptr = ie; + int total_ie_len; + t_u8 element_len; + int ret = MLAN_STATUS_SUCCESS; + IEEEtypes_ElementId_e element_id; + IEEEtypes_VendorSpecific_t *pvendor_ie; + t_u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 }; + + while (bytes_left >= 2) { + element_id = (IEEEtypes_ElementId_e) (*((t_u8 *) pcurrent_ptr)); + element_len = *((t_u8 *) pcurrent_ptr + 1); + total_ie_len = element_len + sizeof(IEEEtypes_Header_t); + if (bytes_left < total_ie_len) { + PRINTM(MERROR, "InterpretIE: Error in processing IE, " + "bytes left < IE length\n"); + bytes_left = 0; + continue; + } + switch (element_id) { + case RSN_IE: + if (MLAN_STATUS_SUCCESS != + woal_set_get_gen_ie(priv, MLAN_ACT_SET, pcurrent_ptr, + &total_ie_len)) { + PRINTM(MERROR, "Fail to set RSN IE\n"); + ret = -EFAULT; + goto done; + } + PRINTM(MIOCTL, "Set RSN IE\n"); + break; + case VENDOR_SPECIFIC_221: + pvendor_ie = (IEEEtypes_VendorSpecific_t *) pcurrent_ptr; + if (!memcmp(pvendor_ie->vend_hdr.oui, wps_oui, sizeof(wps_oui))) { + PRINTM(MIOCTL, "Enable WPS session\n"); + woal_wps_cfg(priv, MTRUE); + } + if (MLAN_STATUS_SUCCESS != + woal_set_get_gen_ie(priv, MLAN_ACT_SET, pcurrent_ptr, + &total_ie_len)) { + PRINTM(MERROR, "Fail to Set VENDOR SPECIFIC IE\n"); + ret = -EFAULT; + goto done; + } + PRINTM(MIOCTL, "Set VENDOR SPECIFIC IE, OUI: %02x:%02x:%02x:%02x\n", + pvendor_ie->vend_hdr.oui[0], pvendor_ie->vend_hdr.oui[1], + pvendor_ie->vend_hdr.oui[2], pvendor_ie->vend_hdr.oui_type); + break; + default: + if (MLAN_STATUS_SUCCESS != + woal_set_get_gen_ie(priv, MLAN_ACT_SET, pcurrent_ptr, + &total_ie_len)) { + PRINTM(MERROR, "Fail to set GEN IE\n"); + ret = -EFAULT; + goto done; + } + PRINTM(MIOCTL, "Set GEN IE\n"); + break; + } + pcurrent_ptr += element_len + 2; + /* Need to account for IE ID and IE Len */ + bytes_left -= (element_len + 2); + } + done: + return ret; +} + +/** + * @brief Send domain info command to FW + * + * @param wiphy A pointer to wiphy structure + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +static mlan_status +woal_send_domain_info_cmd_fw(struct wiphy *wiphy) +{ + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + mlan_status ret = MLAN_STATUS_SUCCESS; + enum ieee80211_band band; + struct ieee80211_supported_band *sband = NULL; + struct ieee80211_channel *channel = NULL; + t_u8 no_of_sub_band = 0; + t_u8 no_of_parsed_chan = 0; + t_u8 first_chan = 0, next_chan = 0, max_pwr = 0; + t_u8 i, flag = 0; + mlan_ds_11d_cfg *cfg_11d = NULL; + mlan_ds_radio_cfg *radio_cfg = NULL; + mlan_ioctl_req *req = NULL; + + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg)); + if (req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + radio_cfg = (mlan_ds_radio_cfg *) req->pbuf; + radio_cfg->sub_command = MLAN_OID_BAND_CFG; + req->req_id = MLAN_IOCTL_RADIO_CFG; + req->action = MLAN_ACT_GET; + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + band = woal_band_cfg_to_ieee_band(radio_cfg->param.band_cfg.config_bands); + if (!wiphy->bands[band]) { + PRINTM(MERROR, "11D: setting domain info in FW failed"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + kfree(req); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg)); + if (req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + cfg_11d = (mlan_ds_11d_cfg *) req->pbuf; + cfg_11d->sub_command = MLAN_OID_11D_DOMAIN_INFO; + req->req_id = MLAN_IOCTL_11D_CFG; + req->action = MLAN_ACT_SET; + + /* Set country code */ + cfg_11d->param.domain_info.country_code[0] = priv->country_code[0]; + cfg_11d->param.domain_info.country_code[1] = priv->country_code[1]; + cfg_11d->param.domain_info.country_code[2] = ' '; + cfg_11d->param.domain_info.band = band; + + sband = wiphy->bands[band]; + for (i = 0; (i < sband->n_channels) && + (no_of_sub_band < MRVDRV_MAX_SUBBAND_802_11D); i++) { + channel = &sband->channels[i]; + if (channel->flags & IEEE80211_CHAN_DISABLED) + continue; + + if (!flag) { + flag = 1; + next_chan = first_chan = (t_u32) channel->hw_value; + max_pwr = channel->max_power; + no_of_parsed_chan = 1; + continue; + } + + if (channel->hw_value == next_chan + 1 && channel->max_power == max_pwr) { + next_chan++; + no_of_parsed_chan++; + } else { + cfg_11d->param.domain_info.sub_band[no_of_sub_band] + .first_chan = first_chan; + cfg_11d->param.domain_info.sub_band[no_of_sub_band] + .no_of_chan = no_of_parsed_chan; + cfg_11d->param.domain_info.sub_band[no_of_sub_band] + .max_tx_pwr = max_pwr; + no_of_sub_band++; + next_chan = first_chan = (t_u32) channel->hw_value; + max_pwr = channel->max_power; + no_of_parsed_chan = 1; + } + } + + if (flag) { + cfg_11d->param.domain_info.sub_band[no_of_sub_band] + .first_chan = first_chan; + cfg_11d->param.domain_info.sub_band[no_of_sub_band] + .no_of_chan = no_of_parsed_chan; + cfg_11d->param.domain_info.sub_band[no_of_sub_band] + .max_tx_pwr = max_pwr; + no_of_sub_band++; + } + cfg_11d->param.domain_info.no_of_sub_band = no_of_sub_band; + + /* Send domain info command to FW */ + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = MLAN_STATUS_FAILURE; + PRINTM(MERROR, "11D: Error setting domain info in FW\n"); + goto done; + } + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Request the driver to change the channel and + * change domain info according to that channel + * + * @param wiphy A pointer to wiphy structure + * @param chan A pointer to ieee80211_channel structure + * @param channel_type Channel type of nl80211_channel_type + * + * @return 0 -- success, otherwise fail + */ +int +woal_set_rf_channel(struct wiphy *wiphy, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) +{ + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + int ret = 0; + t_u32 mode, config_bands = 0; + mlan_ioctl_req *req1 = NULL, *req2 = NULL; + mlan_ds_radio_cfg *radio_cfg = NULL; + mlan_ds_bss *bss = NULL; + + ENTER(); + + mode = woal_nl80211_iftype_to_mode(priv->wdev->iftype); + + req1 = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg)); + if (req1 == NULL) { + ret = -ENOMEM; + goto done; + } + + radio_cfg = (mlan_ds_radio_cfg *) req1->pbuf; + radio_cfg->sub_command = MLAN_OID_BAND_CFG; + req1->req_id = MLAN_IOCTL_RADIO_CFG; + + if (chan) { + req1->action = MLAN_ACT_SET; + /* Set appropriate bands */ + if (chan->band == IEEE80211_BAND_2GHZ) + config_bands = BAND_B | BAND_G | BAND_GN; + else + config_bands = BAND_AN | BAND_A; + if (mode == MLAN_BSS_MODE_IBSS) + radio_cfg->param.band_cfg.adhoc_start_band = config_bands; + radio_cfg->param.band_cfg.config_bands = config_bands; + /* Set channel offset */ + radio_cfg->param.band_cfg.sec_chan_offset = + woal_cfg80211_channel_type_to_channel(channel_type); + + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, req1, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + woal_send_domain_info_cmd_fw(wiphy); + } + + PRINTM(MINFO, "Setting band %d, channel bandwidth %d and mode = %d\n", + config_bands, radio_cfg->param.band_cfg.sec_chan_offset, mode); + + if (!chan) + goto done; + + req2 = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + if (req2 == NULL) { + ret = -ENOMEM; + goto done; + } + + bss = (mlan_ds_bss *) req2->pbuf; + + bss->param.bss_chan.freq = chan->center_freq; + /* Convert frequency to channel */ + bss->param.bss_chan.channel = + ieee80211_frequency_to_channel(chan->center_freq); + + bss->sub_command = MLAN_OID_BSS_CHANNEL; + req2->req_id = MLAN_IOCTL_BSS; + req2->action = MLAN_ACT_SET; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req2, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + if (MLAN_STATUS_SUCCESS != + woal_change_adhoc_chan(priv, bss->param.bss_chan.channel)) { + ret = -EFAULT; + goto done; + } + + done: + if (req1) + kfree(req1); + if (req2) + kfree(req2); + + LEAVE(); + return ret; +} + +/** + * @brief Set ewpa mode + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * @param ssid_bssid A pointer to mlan_ssid_bssid structure + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_set_ewpa_mode(moal_private * priv, t_u8 wait_option, + mlan_ssid_bssid * ssid_bssid) +{ + int ret = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_sec_cfg *sec = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto error; + } + /* Fill request buffer */ + sec = (mlan_ds_sec_cfg *) req->pbuf; + sec->sub_command = MLAN_OID_SEC_CFG_PASSPHRASE; + req->req_id = MLAN_IOCTL_SEC_CFG; + req->action = MLAN_ACT_GET; + + /* Try Get All */ + memset(&sec->param.passphrase, 0, sizeof(mlan_ds_passphrase)); + memcpy(&sec->param.passphrase.ssid, &ssid_bssid->ssid, + sizeof(sec->param.passphrase.ssid)); + memcpy(&sec->param.passphrase.bssid, &ssid_bssid->bssid, + MLAN_MAC_ADDR_LENGTH); + sec->param.passphrase.psk_type = MLAN_PSK_QUERY; + + /* Send IOCTL request to MLAN */ + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, wait_option)) + goto error; + sec->param.ewpa_enabled = MFALSE; + if (sec->param.passphrase.psk_type == MLAN_PSK_PASSPHRASE) { + if (sec->param.passphrase.psk.passphrase.passphrase_len > 0) { + sec->param.ewpa_enabled = MTRUE; + } + } else if (sec->param.passphrase.psk_type == MLAN_PSK_PMK) + sec->param.ewpa_enabled = MTRUE; + + sec->sub_command = MLAN_OID_SEC_CFG_EWPA_ENABLED; + req->action = MLAN_ACT_SET; + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, wait_option); + + error: + if (req && (status != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return status; +} + +/** + * @brief Set encryption mode and enable WPA + * + * @param priv A pointer to moal_private structure + * @param encrypt_mode Encryption mode + * @param wpa_enabled WPA enable or not + * + * @return 0 -- success, otherwise fail + */ +static int +woal_cfg80211_set_auth(moal_private * priv, int encrypt_mode, int wpa_enabled) +{ + int ret = 0; + + ENTER(); + + if (MLAN_STATUS_SUCCESS != + woal_set_encrypt_mode(priv, MOAL_IOCTL_WAIT, encrypt_mode)) + ret = -EFAULT; + + if (wpa_enabled) { + if (MLAN_STATUS_SUCCESS != + woal_set_wpa_enable(priv, MOAL_IOCTL_WAIT, 1)) + ret = -EFAULT; + } + + LEAVE(); + return ret; +} + +/** + * @brief Informs the CFG802.11 subsystem of a new BSS connection. + * + * The following information are sent to the CFG802.11 subsystem + * to register the new BSS connection. If we do not register the new BSS, + * a kernel panic will result. + * - MAC address + * - Capabilities + * - Beacon period + * - RSSI value + * - Channel + * - Supported rates IE + * - Extended capabilities IE + * - DS parameter set IE + * - HT Capability IE + * - Vendor Specific IE (221) + * - WPA IE + * - RSN IE + * + * @param priv A pointer to moal_private structure + * @param ssid A pointer to mlan_802_11_ssid structure + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +woal_inform_bss_from_scan_result(moal_private * priv, mlan_802_11_ssid * ssid) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + struct ieee80211_channel *chan; + mlan_scan_resp scan_resp; + BSSDescriptor_t *scan_table; + t_u8 *ie, *tmp, *ie_buf; + __le32 ie_len; + t_u64 ts = 0; + t_u8 *cap; + t_u8 *beacon; + int beacon_size, i, j; + IEEEtypes_ElementId_e element_id; + t_u8 element_len; + struct cfg80211_bss *pub = NULL; + + ENTER(); + + memset(&scan_resp, 0, sizeof(scan_resp)); + if (MLAN_STATUS_SUCCESS != woal_get_scan_table(priv, + MOAL_IOCTL_WAIT, + &scan_resp)) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + if (scan_resp.num_in_scan_table) { +#define MAX_IE_BUF 2048 + ie_buf = kzalloc(MAX_IE_BUF, GFP_KERNEL); + if (ie_buf == NULL) { + PRINTM(MERROR, "%s: failed to allocate ie_buf\n", __func__); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + scan_table = (BSSDescriptor_t *) scan_resp.pscan_table; + for (i = 0; i < scan_resp.num_in_scan_table; i++) { + if (ssid) { + /* Inform specific BSS only */ + if (memcmp(ssid->ssid, scan_table[i].ssid.ssid, ssid->ssid_len)) + continue; + } + if (!scan_table[i].freq) { + PRINTM(MERROR, "Invalid channel number %d\n", + (int) scan_table[i].channel); + continue; + } + memset(ie_buf, 0, MAX_IE_BUF); + ie_buf[0] = WLAN_EID_SSID; + ie_buf[1] = scan_table[i].ssid.ssid_len; + memcpy(&ie_buf[sizeof(IEEEtypes_Header_t)], + scan_table[i].ssid.ssid, ie_buf[1]); + + ie = ie_buf + ie_buf[1] + sizeof(IEEEtypes_Header_t); + ie_len = ie_buf[1] + sizeof(IEEEtypes_Header_t); + + ie[0] = WLAN_EID_SUPP_RATES; + + for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) { + if (!scan_table[i].supported_rates[j]) + break; + else { + ie[j + sizeof(IEEEtypes_Header_t)] = + scan_table[i].supported_rates[j]; + } + } + + ie[1] = j; + ie_len += ie[1] + sizeof(IEEEtypes_Header_t); + + beacon = scan_table[i].pbeacon_buf; + beacon_size = scan_table[i].beacon_buf_size; + + /* Skip time stamp, beacon interval and capability */ + + if (beacon) { + beacon += sizeof(scan_table[i].beacon_period) + + sizeof(scan_table[i].time_stamp) + + +sizeof(scan_table[i].cap_info); + + beacon_size -= sizeof(scan_table[i].beacon_period) + + sizeof(scan_table[i].time_stamp) + + sizeof(scan_table[i].cap_info); + } + + while (beacon_size >= sizeof(IEEEtypes_Header_t)) { + ie = ie_buf + ie_len; + element_id = *beacon; + element_len = *(beacon + 1); + if (beacon_size < (int) element_len + + sizeof(IEEEtypes_Header_t)) { + PRINTM(MERROR, + "Get scan: Error in processing IE, " + "bytes left < IE length\n"); + break; + } + switch (element_id) { + case WLAN_EID_FH_PARAMS: + case WLAN_EID_DS_PARAMS: + case WLAN_EID_CF_PARAMS: + case WLAN_EID_IBSS_PARAMS: + case WLAN_EID_COUNTRY: + case WLAN_EID_PWR_CONSTRAINT: + case WLAN_EID_PWR_CAPABILITY: + case WLAN_EID_TPC_REQUEST: + case WLAN_EID_TPC_REPORT: + case WLAN_EID_CHANNEL_SWITCH: + case WLAN_EID_QUIET: + case WLAN_EID_IBSS_DFS: + case WLAN_EID_SUPPORTED_CHANNELS: + case WLAN_EID_ERP_INFO: + case WLAN_EID_EXT_SUPP_RATES: + case WLAN_EID_HT_CAPABILITY: + case WLAN_EID_HT_INFORMATION: + case EXT_CAPABILITY: // TODO: Replace when kernel macro + // available + case WLAN_EID_RSN: + case WAPI_IE: // TODO: Replace when kernel macro available + case WLAN_EID_VENDOR_SPECIFIC: + ie[0] = element_id; + ie[1] = element_len; + tmp = (t_u8 *) beacon; + memcpy(&ie[sizeof(IEEEtypes_Header_t)], + tmp + sizeof(IEEEtypes_Header_t), element_len); + ie_len += ie[1] + sizeof(IEEEtypes_Header_t); + break; + default: + break; + } + beacon += element_len + sizeof(IEEEtypes_Header_t); + beacon_size -= (element_len + sizeof(IEEEtypes_Header_t)); + } + chan = ieee80211_get_channel(priv->wdev->wiphy, scan_table[i].freq); + cap = (t_u8 *) & scan_table[i].cap_info; + pub = cfg80211_inform_bss(priv->wdev->wiphy, chan, + scan_table[i].mac_address, + ts, (__le16) (*cap), + scan_table[i].beacon_period, ie_buf, + ie_len, + -RSSI_DBM_TO_MDM(scan_table[i].rssi), + GFP_KERNEL); + pub->len_information_elements = pub->len_beacon_ies; + } + kfree(ie_buf); + } + + done: + LEAVE(); + return ret; +} + +/** + * @brief Informs the CFG802.11 subsystem of a new IBSS connection. + * + * The following information are sent to the CFG802.11 subsystem + * to register the new IBSS connection. If we do not register the + * new IBSS, a kernel panic will result. + * - MAC address + * - Capabilities + * - Beacon period + * - RSSI value + * - Channel + * - Supported rates IE + * - Extended capabilities IE + * - DS parameter set IE + * - HT Capability IE + * - Vendor Specific IE (221) + * - WPA IE + * - RSN IE + * + * @param priv A pointer to moal_private structure + * @param cahn A pointer to ieee80211_channel structure + * @param beacon_interval Beacon interval + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +static mlan_status +woal_cfg80211_inform_ibss_bss(moal_private * priv, + struct ieee80211_channel *chan, + t_u16 beacon_interval) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_bss_info bss_info; + mlan_ds_get_signal signal; + t_u8 ie_buf[MLAN_MAX_SSID_LENGTH + sizeof(IEEEtypes_Header_t)]; + int ie_len = 0; + + ENTER(); + + ret = woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info); + if (ret) + goto done; + + memset(ie_buf, 0, sizeof(ie_buf)); + ie_buf[0] = WLAN_EID_SSID; + ie_buf[1] = bss_info.ssid.ssid_len; + + memcpy(&ie_buf[sizeof(IEEEtypes_Header_t)], + &bss_info.ssid.ssid, bss_info.ssid.ssid_len); + ie_len = ie_buf[1] + sizeof(IEEEtypes_Header_t); + + /* Get signal information from the firmware */ + memset(&signal, 0, sizeof(mlan_ds_get_signal)); + if (MLAN_STATUS_SUCCESS != + woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) { + PRINTM(MERROR, "Error getting signal information\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + cfg80211_inform_bss(priv->wdev->wiphy, chan, + bss_info.bssid, 0, WLAN_CAPABILITY_IBSS, + beacon_interval, ie_buf, ie_len, signal.bcn_rssi_avg, + GFP_KERNEL); + + done: + LEAVE(); + return ret; +} + +/** + * @brief Request the driver for (re)association + * + * @param wiphy A pointer to wiphy structure + * @param sme A pointer to connect parameters + * + * @return 0 -- success, otherwise fail + */ +static int +woal_cfg80211_assoc(struct wiphy *wiphy, void *sme) +{ + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + struct cfg80211_ibss_params *ibss_param = NULL; + struct cfg80211_connect_params *conn_param = NULL; + mlan_802_11_ssid req_ssid; + mlan_ssid_bssid ssid_bssid; + mlan_ds_radio_cfg *radio_cfg = NULL; + mlan_ioctl_req *req = NULL; + int ret = 0; + t_u32 auth_type = 0, mode; + int wpa_enabled = 0; + int group_enc_mode = 0, pairwise_enc_mode = 0; + int alg_is_wep = 0; + + t_u8 *ssid, ssid_len = 0, *bssid; + t_u8 *ie = NULL; + int ie_len = 0; + struct ieee80211_channel *channel = NULL; + t_u16 beacon_interval = 0; + bool privacy; + + ENTER(); + + mode = woal_nl80211_iftype_to_mode(priv->wdev->iftype); + + if (mode == MLAN_BSS_MODE_IBSS) { + ibss_param = (struct cfg80211_ibss_params *) sme; + ssid = ibss_param->ssid; + ssid_len = ibss_param->ssid_len; + bssid = ibss_param->bssid; + channel = ibss_param->channel; + if (ibss_param->ie_len) + ie = ibss_param->ie; + ie_len = ibss_param->ie_len; + beacon_interval = ibss_param->beacon_interval; + privacy = ibss_param->privacy; + } else { + conn_param = (struct cfg80211_connect_params *) sme; + ssid = conn_param->ssid; + ssid_len = conn_param->ssid_len; + bssid = conn_param->bssid; + channel = conn_param->channel; + if (conn_param->ie_len) + ie = conn_param->ie; + ie_len = conn_param->ie_len; + privacy = conn_param->privacy; + } + + memset(&req_ssid, 0, sizeof(mlan_802_11_ssid)); + memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid)); + + req_ssid.ssid_len = ssid_len; + if (ssid_len > IW_ESSID_MAX_SIZE) { + PRINTM(MERROR, "Invalid SSID - aborting\n"); + ret = -EINVAL; + goto done; + } + + memcpy(req_ssid.ssid, ssid, ssid_len); + if (!req_ssid.ssid_len || req_ssid.ssid[0] < 0x20) { + PRINTM(MERROR, "Invalid SSID - aborting\n"); + ret = -EINVAL; + goto done; + } + + if (channel) { + /* Get the secondary channel offset */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + radio_cfg = (mlan_ds_radio_cfg *) req->pbuf; + radio_cfg->sub_command = MLAN_OID_BAND_CFG; + req->req_id = MLAN_IOCTL_RADIO_CFG; + req->action = MLAN_ACT_GET; + + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + if (MLAN_STATUS_SUCCESS != woal_set_rf_channel(wiphy, + channel, + woal_channel_to_nl80211_channel_type + (radio_cfg->param. + band_cfg. + sec_chan_offset))) { + ret = -EFAULT; + goto done; + } + } + + if (MLAN_STATUS_SUCCESS != + woal_set_ewpa_mode(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) { + ret = -EFAULT; + goto done; + } + + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_set_key(priv, 0, 0, NULL, 0, NULL, 0, 0, NULL, 1)) { + /* Disable keys */ + ret = -EFAULT; + goto done; + } + + if (ie && ie_len) { /* Set the IE */ + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_assoc_ies_cfg(priv, ie, ie_len)) { + ret = -EFAULT; + goto done; + } + } + + if (conn_param && mode != MLAN_BSS_MODE_IBSS) { + /* These parameters are only for managed mode */ + if (conn_param->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) + auth_type = MLAN_AUTH_MODE_OPEN; + else if (conn_param->auth_type == NL80211_AUTHTYPE_SHARED_KEY) + auth_type = MLAN_AUTH_MODE_SHARED; + else if (conn_param->auth_type == NL80211_AUTHTYPE_NETWORK_EAP) + auth_type = MLAN_AUTH_MODE_NETWORKEAP; + else + auth_type = MLAN_AUTH_MODE_AUTO; + + if (MLAN_STATUS_SUCCESS != + woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_type)) { + ret = -EFAULT; + goto done; + } + + if (conn_param->crypto.n_ciphers_pairwise) { + pairwise_enc_mode = + woal_cfg80211_get_encryption_mode(conn_param-> + crypto.ciphers_pairwise[0], + &wpa_enabled); + ret = woal_cfg80211_set_auth(priv, pairwise_enc_mode, wpa_enabled); + if (ret) + goto done; + } + + if (conn_param->crypto.cipher_group) { + group_enc_mode = + woal_cfg80211_get_encryption_mode(conn_param-> + crypto.cipher_group, + &wpa_enabled); + ret = woal_cfg80211_set_auth(priv, group_enc_mode, wpa_enabled); + if (ret) + goto done; + } + + if (conn_param->key) { + alg_is_wep = + woal_cfg80211_is_alg_wep(pairwise_enc_mode) | + woal_cfg80211_is_alg_wep(group_enc_mode); + if (alg_is_wep) { + PRINTM(MINFO, "Setting wep encryption with " + "key len %d\n", conn_param->key_len); + /* Set the WEP key */ + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_set_wep_keys(priv, conn_param->key, + conn_param->key_len, + conn_param->key_idx)) { + ret = -EFAULT; + goto done; + } + /* Enable the WEP key by key index */ + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_set_wep_keys(priv, NULL, 0, + conn_param->key_idx)) { + ret = -EFAULT; + goto done; + } + } + } + } + + if (mode == MLAN_BSS_MODE_IBSS) { + mlan_ds_bss *bss = NULL; + /* Change beacon interval */ + if ((beacon_interval < MLAN_MIN_BEACON_INTERVAL) || + (beacon_interval > MLAN_MAX_BEACON_INTERVAL)) { + ret = -EINVAL; + goto done; + } + if (req) + kfree(req); + req = NULL; + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + bss = (mlan_ds_bss *) req->pbuf; + req->req_id = MLAN_IOCTL_BSS; + req->action = MLAN_ACT_SET; + bss->sub_command = MLAN_OID_IBSS_BCN_INTERVAL; + bss->param.bcn_interval = beacon_interval; + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + /* "privacy" is set only for ad-hoc mode */ + if (privacy) { + /* + * Keep MLAN_ENCRYPTION_MODE_WEP40 for now so that + * the firmware can find a matching network from the + * scan. cfg80211 does not give us the encryption + * mode at this stage so just setting it to wep here + */ + if (MLAN_STATUS_SUCCESS != + woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, + MLAN_AUTH_MODE_OPEN)) { + ret = -EFAULT; + goto done; + } + + wpa_enabled = 0; + ret = woal_cfg80211_set_auth(priv, + MLAN_ENCRYPTION_MODE_WEP104, + wpa_enabled); + if (ret) + goto done; + } + } + memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(mlan_802_11_ssid)); + if (bssid) + memcpy(&ssid_bssid.bssid, bssid, ETH_ALEN); + if (MLAN_STATUS_SUCCESS != woal_find_essid(priv, &ssid_bssid)) { + /* Do specific SSID scanning */ + if (MLAN_STATUS_SUCCESS != + woal_request_scan(priv, MOAL_IOCTL_WAIT, &req_ssid)) { + ret = -EFAULT; + goto done; + } + } + + /* Disconnect before try to associate */ + woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL); + + if (mode != MLAN_BSS_MODE_IBSS) { + if (MLAN_STATUS_SUCCESS != + woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) { + ret = -EFAULT; + goto done; + } + /* Inform the BSS information to kernel, otherwise kernel will give a + panic after successful assoc */ + if (MLAN_STATUS_SUCCESS != + woal_inform_bss_from_scan_result(priv, &req_ssid)) { + ret = -EFAULT; + goto done; + } + } else if (MLAN_STATUS_SUCCESS != + woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) + /* Adhoc start, Check the channel command */ + woal_11h_channel_check_ioctl(priv); + + PRINTM(MINFO, "Trying to associate to %s and bssid %pM\n", + (char *) req_ssid.ssid, ssid_bssid.bssid); + + /* Zero SSID implies use BSSID to connect */ + if (bssid) + memset(&ssid_bssid.ssid, 0, sizeof(mlan_802_11_ssid)); + else /* Connect to BSS by ESSID */ + memset(&ssid_bssid.bssid, 0, MLAN_MAC_ADDR_LENGTH); + + if (MLAN_STATUS_SUCCESS != + woal_bss_start(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) { + ret = -EFAULT; + goto done; + } + + /* Inform the IBSS information to kernel, otherwise kernel will give a + panic after successful assoc */ + if (mode == MLAN_BSS_MODE_IBSS) { + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_inform_ibss_bss(priv, channel, beacon_interval)) { + ret = -EFAULT; + goto done; + } + } + + done: + if (ret) { + /* clear IE */ + ie_len = 0; + woal_set_get_gen_ie(priv, MLAN_ACT_SET, NULL, &ie_len); + } + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Request the driver to dump the station information + * + * @param priv A pointer to moal_private structure + * @param sinfo A pointer to station_info structure + * + * @return 0 -- success, otherwise fail + */ +static mlan_status +woal_cfg80211_dump_station_info(moal_private * priv, struct station_info *sinfo) +{ + mlan_ds_get_signal signal; + mlan_ioctl_req *req = NULL; + mlan_ds_rate *rate = NULL; + mlan_status ret = MLAN_STATUS_SUCCESS; + + ENTER(); + sinfo->filled = STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES | + STATION_INFO_RX_PACKETS | STATION_INFO_TX_PACKETS | + STATION_INFO_SIGNAL | STATION_INFO_TX_BITRATE; + + /* Get signal information from the firmware */ + memset(&signal, 0, sizeof(mlan_ds_get_signal)); + if (MLAN_STATUS_SUCCESS != + woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) { + PRINTM(MERROR, "Error getting signal information\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate)); + if (req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + rate = (mlan_ds_rate *) req->pbuf; + rate->sub_command = MLAN_OID_GET_DATA_RATE; + req->req_id = MLAN_IOCTL_RATE; + req->action = MLAN_ACT_GET; + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + sinfo->txrate.flags = RATE_INFO_FLAGS_MCS; + if (rate->param.data_rate.tx_ht_bw == MLAN_HT_BW40) { + sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; + } + if (rate->param.data_rate.tx_ht_gi == MLAN_HT_SGI) { + sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; + } + sinfo->txrate.mcs = rate->param.data_rate.tx_data_rate; + sinfo->rx_bytes = priv->stats.rx_bytes; + sinfo->tx_bytes = priv->stats.tx_bytes; + sinfo->rx_packets = priv->stats.rx_packets; + sinfo->tx_packets = priv->stats.tx_packets; + sinfo->signal = signal.bcn_rssi_avg; + + done: + if (req) + kfree(req); + + LEAVE(); + return ret; +} + +/******************************************************** + Global Functions +********************************************************/ + +/** + * @brief Request the driver to change regulatory domain + * + * @param wiphy A pointer to wiphy structure + * @param request A pointer to regulatory_request structure + * + * @return 0 + */ +static int +woal_cfg80211_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + int ret = 0; + + ENTER(); + + PRINTM(MINFO, "cfg80211 regulatory domain callback " + "%c%c\n", request->alpha2[0], request->alpha2[1]); + + if (MLAN_STATUS_SUCCESS != woal_set_region_code(priv, request->alpha2)) + PRINTM(MERROR, "Set country code failed!\n"); + memcpy(priv->country_code, request->alpha2, COUNTRY_CODE_LEN); + + switch (request->initiator) { + case NL80211_REGDOM_SET_BY_DRIVER: + PRINTM(MINFO, "Regulatory domain BY_DRIVER\n"); + break; + case NL80211_REGDOM_SET_BY_CORE: + PRINTM(MINFO, "Regulatory domain BY_CORE\n"); + break; + case NL80211_REGDOM_SET_BY_USER: + PRINTM(MINFO, "Regulatory domain BY_USER\n"); + break; + /* TODO: apply driver specific changes in channel flags based on the + request initiator if necessory. * */ + case NL80211_REGDOM_SET_BY_COUNTRY_IE: + PRINTM(MINFO, "Regulatory domain BY_COUNTRY_IE\n"); + break; + } + + if (MLAN_STATUS_SUCCESS != woal_send_domain_info_cmd_fw(wiphy)) + ret = -EFAULT; + + LEAVE(); + return ret; +} + +/** + * @brief Request the driver to do a scan. Always returning + * zero meaning that the scan request is given to driver, + * and will be valid until passed to cfg80211_scan_done(). + * To inform scan results, call cfg80211_inform_bss(). + * + * @param wiphy A pointer to wiphy structure + * @param dev A pointer to net_device structure + * @param request A pointer to cfg80211_scan_request structure + * + * @return 0 -- success, otherwise fail + */ +static int +woal_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_scan_request *request) +{ + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + wlan_user_scan_cfg scan_req; + struct ieee80211_channel *chan; + int ret = 0, i; + + ENTER(); + + PRINTM(MINFO, "Received scan request on %s\n", dev->name); + + if (priv->scan_request && priv->scan_request != request) { + LEAVE(); + return -EBUSY; + } + priv->scan_request = request; + + memset(&scan_req, 0x00, sizeof(scan_req)); + for (i = 0; i < priv->scan_request->n_ssids; i++) { + memcpy(scan_req.ssid_list[i].ssid, + priv->scan_request->ssids[i].ssid, + priv->scan_request->ssids[i].ssid_len); + if (priv->scan_request->ssids[i].ssid_len) + scan_req.ssid_list[i].max_len = 0; + else + scan_req.ssid_list[i].max_len = 0xff; + PRINTM(MIOCTL, "scan: ssid=%s\n", scan_req.ssid_list[i].ssid); + } +#if defined(WIFI_DIRECT_SUPPORT) +#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION + if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT && + priv->scan_request->n_ssids) { + if (!memcmp(scan_req.ssid_list[i - 1].ssid, "DIRECT-", 7)) { + /* Enable wildcard ssid scan */ + memcpy(scan_req.ssid_list[i].ssid, "DIRECT-*", 8); + scan_req.ssid_list[i].max_len = 0xff; + } + } +#endif +#endif + for (i = 0; i < priv->scan_request->n_channels; i++) { + chan = priv->scan_request->channels[i]; + scan_req.chan_list[i].chan_number = chan->hw_value; + scan_req.chan_list[i].radio_type = chan->band; + if (chan->flags & IEEE80211_CHAN_DISABLED) + scan_req.chan_list[i].scan_type = MLAN_SCAN_TYPE_PASSIVE; + else + scan_req.chan_list[i].scan_type = MLAN_SCAN_TYPE_ACTIVE; + scan_req.chan_list[i].scan_time = 0; + } + if (priv->scan_request->ie && priv->scan_request->ie_len) { + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, + NULL, 0, NULL, 0, + (t_u8 *) priv->scan_request->ie, + priv->scan_request->ie_len, + MGMT_MASK_PROBE_REQ)) { + ret = -EFAULT; + goto done; + } + } else { + /** Clear SCAN IE in Firmware */ + woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, NULL, 0, NULL, 0, NULL, 0, + MGMT_MASK_PROBE_REQ); + } + if (MLAN_STATUS_SUCCESS != woal_do_scan(priv, &scan_req)) { + ret = -EAGAIN; + } + done: + LEAVE(); + return 0; +} + +/** + * @brief Request the driver to connect to the ESS with + * the specified parameters from kernel + * + * @param wiphy A pointer to wiphy structure + * @param dev A pointer to net_device structure + * @param sme A pointer to cfg80211_connect_params structure + * + * @return 0 -- success, otherwise fail + */ +static int +woal_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme) +{ + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + int ret = 0; + + ENTER(); + PRINTM(MINFO, "Received association request on %s\n", dev->name); + + if (priv->wdev->iftype != NL80211_IFTYPE_STATION +#if defined(WIFI_DIRECT_SUPPORT) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS) + && priv->wdev->iftype != NL80211_IFTYPE_P2P_CLIENT +#endif /* KERNEL_VERSION */ +#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */ + ) { + PRINTM(MERROR, "Received infra assoc request " + "when station not in infra mode\n"); + LEAVE(); + return -EINVAL; + } +#if defined(WIFI_DIRECT_SUPPORT) +#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION + if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT + && (priv->wdev->iftype == NL80211_IFTYPE_STATION + || priv->wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) { + /* if bsstype == wifi direct, and iftype == station or p2p client, that + means wpa_supplicant wants to enable wifi direct functionality, so + we should init p2p client. Note that due to kernel iftype check, + ICS wpa_supplicant could not updaet iftype to init p2p client, so + we have to done it here. */ + if (MLAN_STATUS_SUCCESS != woal_cfg80211_init_p2p_client(priv)) { + PRINTM(MERROR, "Init p2p client for wpa_supplicant failed.\n"); + ret = -EFAULT; + + LEAVE(); + return ret; + } + } +#endif +#endif + + if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE) + woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE); + ret = woal_cfg80211_assoc(wiphy, (void *) sme); + + if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE) + woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE); + + if (!ret) { + cfg80211_connect_result(priv->netdev, priv->cfg_bssid, NULL, 0, + NULL, 0, WLAN_STATUS_SUCCESS, GFP_KERNEL); + PRINTM(MINFO, "Associated to bssid %pM successfully\n", + priv->cfg_bssid); + } else { + PRINTM(MINFO, "Association to bssid %pM failed\n", priv->cfg_bssid); + cfg80211_connect_result(priv->netdev, priv->cfg_bssid, NULL, 0, + NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE, + GFP_KERNEL); + memset(priv->cfg_bssid, 0, ETH_ALEN); + } + + LEAVE(); + return ret; +} + +/** + * @brief Request the driver to disconnect + * + * @param wiphy A pointer to wiphy structure + * @param dev A pointer to net_device structure + * @param reason_code Reason code + * + * @return 0 -- success, otherwise fail + */ +static int +woal_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, + t_u16 reason_code) +{ + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + + ENTER(); + PRINTM(MINFO, "Received disassociation request on %s\n", dev->name); + + if (priv->cfg_disconnect) { + PRINTM(MERROR, "Disassociation already in progress\n"); + LEAVE(); + return -EBUSY; + } + + if (priv->media_connected == MFALSE) { + LEAVE(); + return -EINVAL; + } + + priv->cfg_disconnect = 1; + + if (woal_disconnect(priv, MOAL_IOCTL_WAIT, priv->cfg_bssid) != + MLAN_STATUS_SUCCESS) { + LEAVE(); + return -EFAULT; + } + + PRINTM(MINFO, "Successfully disconnected from %pM: Reason code %d\n", + priv->cfg_bssid, reason_code); + + memset(priv->cfg_bssid, 0, ETH_ALEN); + + LEAVE(); + return 0; +} + +/** + * @brief Request the driver to get the station information + * + * @param wiphy A pointer to wiphy structure + * @param dev A pointer to net_device structure + * @param mac MAC address of the station + * @param sinfo A pointer to station_info structure + * + * @return 0 -- success, otherwise fail + */ +static int +woal_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *dev, + t_u8 * mac, struct station_info *sinfo) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + + ENTER(); + +#if defined(WIFI_DIRECT_SUPPORT) +#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION + if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) { + LEAVE(); + return woal_uap_cfg80211_get_station(wiphy, dev, mac, sinfo); + } +#endif +#endif + if (priv->media_connected == MFALSE) { + PRINTM(MINFO, "cfg80211: Media not connected!\n"); + LEAVE(); + return -ENOENT; + } + if (memcmp(mac, priv->cfg_bssid, ETH_ALEN)) { + PRINTM(MINFO, "cfg80211: Request not for this station!\n"); + LEAVE(); + return -ENOENT; + } + + if (MLAN_STATUS_SUCCESS != woal_cfg80211_dump_station_info(priv, sinfo)) { + PRINTM(MERROR, "cfg80211: Failed to get station info\n"); + ret = -EFAULT; + } + + LEAVE(); + return ret; +} + +/** + * @brief Request the driver to dump the station information + * + * @param wiphy A pointer to wiphy structure + * @param dev A pointer to net_device structure + * @param idx Station index + * @param mac MAC address of the station + * @param sinfo A pointer to station_info structure + * + * @return 0 -- success, otherwise fail + */ +static int +woal_cfg80211_dump_station(struct wiphy *wiphy, + struct net_device *dev, int idx, + t_u8 * mac, struct station_info *sinfo) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + + ENTER(); + + if (!priv->media_connected || idx != 0) { + PRINTM(MINFO, "cfg80211: Media not connected or" + " not for this station!\n"); + LEAVE(); + return -ENOENT; + } + + memcpy(mac, priv->cfg_bssid, ETH_ALEN); + + if (MLAN_STATUS_SUCCESS != woal_cfg80211_dump_station_info(priv, sinfo)) { + PRINTM(MERROR, "cfg80211: Failed to get station info\n"); + ret = -EFAULT; + } + + LEAVE(); + return ret; +} + +/** + * @brief Request the driver to Join the specified + * IBSS (or create if necessary) + * + * @param wiphy A pointer to wiphy structure + * @param dev A pointer to net_device structure + * @param params A pointer to cfg80211_ibss_params structure + * + * @return 0 -- success, otherwise fail + */ +static int +woal_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_ibss_params *params) +{ + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + int ret = 0; + + ENTER(); + + if (priv->wdev->iftype != NL80211_IFTYPE_ADHOC) { + PRINTM(MERROR, "Request IBSS join received " + "when station not in ibss mode\n"); + LEAVE(); + return -EINVAL; + } + + ret = woal_cfg80211_assoc(wiphy, (void *) params); + + if (!ret) { + cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, GFP_KERNEL); + PRINTM(MINFO, "Joined/created adhoc network with bssid" + " %pM successfully\n", priv->cfg_bssid); + } else { + PRINTM(MINFO, "Failed creating/joining adhoc network\n"); + memset(priv->cfg_bssid, 0, ETH_ALEN); + } + + LEAVE(); + return ret; +} + +/** + * @brief Request the driver to leave the IBSS + * + * @param wiphy A pointer to wiphy structure + * @param dev A pointer to net_device structure + * + * @return 0 -- success, otherwise fail + */ +static int +woal_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) +{ + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + + ENTER(); + + if (priv->cfg_disconnect) { + PRINTM(MERROR, "IBSS leave already in progress\n"); + LEAVE(); + return -EBUSY; + } + + if (priv->media_connected == MFALSE) { + LEAVE(); + return -EINVAL; + } + + priv->cfg_disconnect = 1; + + PRINTM(MINFO, "Leaving from IBSS %pM\n", priv->cfg_bssid); + if (woal_disconnect(priv, MOAL_IOCTL_WAIT, priv->cfg_bssid) != + MLAN_STATUS_SUCCESS) { + LEAVE(); + return -EFAULT; + } + + memset(priv->cfg_bssid, 0, ETH_ALEN); + + LEAVE(); + return 0; +} + +/** + * @brief Request the driver to change the IEEE power save + * mdoe + * + * @param wiphy A pointer to wiphy structure + * @param dev A pointer to net_device structure + * @param enabled Enable or disable + * @param timeout Timeout value + * + * @return 0 -- success, otherwise fail + */ +static int +woal_cfg80211_set_power_mgmt(struct wiphy *wiphy, + struct net_device *dev, bool enabled, int timeout) +{ + int ret = 0, disabled; + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + + ENTER(); + + if (enabled) + disabled = 0; + else + disabled = 1; + + if (MLAN_STATUS_SUCCESS != + woal_set_get_power_mgmt(priv, MLAN_ACT_SET, &disabled, timeout)) { + ret = -EOPNOTSUPP; + } + + LEAVE(); + return ret; +} + +/** + * @brief Request the driver to change the transmit power + * + * @param wiphy A pointer to wiphy structure + * @param type TX power adjustment type + * @param dbm TX power in dbm + * + * @return 0 -- success, otherwise fail + */ +static int +woal_cfg80211_set_tx_power(struct wiphy *wiphy, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) && !defined(COMPAT_WIRELESS) + enum tx_power_setting type, +#else + enum nl80211_tx_power_setting type, +#endif + int dbm) +{ + int ret = 0; + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + mlan_power_cfg_t power_cfg; + + ENTER(); + + if (type) { + power_cfg.is_power_auto = 0; + power_cfg.power_level = dbm; + } else + power_cfg.is_power_auto = 1; + + if (MLAN_STATUS_SUCCESS != + woal_set_get_tx_power(priv, MLAN_ACT_SET, &power_cfg)) + ret = -EFAULT; + + LEAVE(); + return ret; +} + +/** + * @brief Sets up the CFG802.11 specific HT capability fields + * with default values + * + * @param ht_info A pointer to ieee80211_sta_ht_cap structure + * @param dev_cap Device capability informations + * @param mcs_set Device MCS sets + * + * @return N/A + */ +static void +woal_cfg80211_setup_sta_ht_cap(struct ieee80211_sta_ht_cap *ht_info, + t_u32 dev_cap, t_u8 * mcs_set) +{ + ENTER(); + + ht_info->ht_supported = true; + ht_info->ampdu_factor = 0x3; + ht_info->ampdu_density = 0x6; + + memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); + ht_info->cap = 0; + if (mcs_set) + memcpy(ht_info->mcs.rx_mask, mcs_set, sizeof(ht_info->mcs.rx_mask)); + if (dev_cap & MBIT(8)) /* 40Mhz intolarance enabled */ + ht_info->cap |= IEEE80211_HT_CAP_40MHZ_INTOLERANT; + if (dev_cap & MBIT(17)) /* Channel width 20/40Mhz support */ + ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; + if ((dev_cap >> 20) & 0x03) /* Delayed ACK supported */ + ht_info->cap |= IEEE80211_HT_CAP_DELAY_BA; + if (dev_cap & MBIT(22)) /* Rx LDPC supported */ + ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; + if (dev_cap & MBIT(23)) /* Short GI @ 20Mhz supported */ + ht_info->cap |= IEEE80211_HT_CAP_SGI_20; + if (dev_cap & MBIT(24)) /* Short GI @ 40Mhz supported */ + ht_info->cap |= IEEE80211_HT_CAP_SGI_40; + if (dev_cap & MBIT(25)) /* Tx STBC supported */ + ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; + if (dev_cap & MBIT(26)) /* Rx STBC supported */ + ht_info->cap |= IEEE80211_HT_CAP_RX_STBC; + if (dev_cap & MBIT(27)) /* MIMO PS supported */ + ht_info->cap |= IEEE80211_HT_CAP_SM_PS; + if (dev_cap & MBIT(29)) /* Green field supported */ + ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; + if (dev_cap & MBIT(31)) /* MAX AMSDU supported */ + ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; + ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; + + LEAVE(); +} + +#if defined(WIFI_DIRECT_SUPPORT) +#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION +/** + * @brief remain on channel config + * + * @param wiphy A pointer to wiphy structure + * @param wait_option Wait option + * @param cancel cancel remain on channel flag + * @param status A pointer to status, success, in process or reject + * @param chan A pointer to ieee80211_channel structure + * @param channel_type channel_type, + * @param duration Duration wait to receive frame + * + * @return 0 -- success, otherwise fail + */ +int +woal_cfg80211_remain_on_channel_cfg(struct wiphy *wiphy, + t_u8 wait_option, t_u8 remove, + t_u8 * status, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + t_u32 duration) +{ + mlan_ds_remain_chan chan_cfg; + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + + int ret = 0; + + ENTER(); + memset(&chan_cfg, 0, sizeof(mlan_ds_remain_chan)); + if (remove) { + chan_cfg.remove = MTRUE; + } else { + if (chan->band == IEEE80211_BAND_2GHZ) + chan_cfg.bandcfg = 0; + else if (chan->band == IEEE80211_BAND_5GHZ) + chan_cfg.bandcfg = 1; +/** secondary channel is below */ +#define SEC_CHAN_BELOW 0x30 +/** secondary channel is above */ +#define SEC_CHAN_ABOVE 0x10 + switch (channel_type) { + case NL80211_CHAN_HT40MINUS: + chan_cfg.bandcfg |= SEC_CHANNEL_BELOW; + break; + case NL80211_CHAN_HT40PLUS: + chan_cfg.bandcfg |= SEC_CHANNEL_ABOVE; + break; + + case NL80211_CHAN_NO_HT: + case NL80211_CHAN_HT20: + default: + break; + } + chan_cfg.channel = ieee80211_frequency_to_channel(chan->center_freq); + chan_cfg.remain_period = duration; + } + if (MLAN_STATUS_SUCCESS == + woal_set_remain_channel_ioctl(priv, wait_option, &chan_cfg)) + *status = chan_cfg.status; + else + ret = -EFAULT; + LEAVE(); + return ret; +} + +/** + * @brief tx mgmt frame + * + * @param wiphy A pointer to wiphy structure + * @param dev A pointer to net_device structure + * @param cookie A pointer to frame cookie + * + * @return 0 -- success, otherwise fail + */ +static int +woal_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, + struct net_device *dev, u64 cookie) +{ + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + int ret = 0; + t_u8 status = 1; + + ENTER(); + + if (priv->phandle->remain_on_channel) { + if (woal_cfg80211_remain_on_channel_cfg(priv->wdev->wiphy, + MOAL_IOCTL_WAIT, MTRUE, &status, + NULL, 0, 0)) { + PRINTM(MERROR, "Fail to cancel remain on channel\n"); + ret = -EFAULT; + goto done; + } + if (priv->phandle->cookie) { + cfg80211_remain_on_channel_expired(priv->netdev, + priv->phandle->cookie, + &priv->phandle->chan, + priv->phandle->channel_type, + GFP_ATOMIC); + priv->phandle->cookie = 0; + } + priv->phandle->remain_on_channel = MFALSE; + } + + done: + LEAVE(); + return ret; +} + +/** + * @brief Make chip remain on channel + * + * @param wiphy A pointer to wiphy structure + * @param dev A pointer to net_device structure + * @param chan A pointer to ieee80211_channel structure + * @param channel_type Channel type + * @param duration Duration for timer + * @param cookie A pointer to timer cookie + * + * @return 0 -- success, otherwise fail + */ +static int +woal_cfg80211_remain_on_channel(struct wiphy *wiphy, + struct net_device *dev, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, + unsigned int duration, u64 * cookie) +{ + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + int ret = 0; + t_u8 status = 1; + + ENTER(); + + if (!chan || !cookie) { + PRINTM(MERROR, "Invalid parameter for remain on channel\n"); + ret = -EFAULT; + goto done; + } + /** cancel previous remain on channel */ + if (priv->phandle->remain_on_channel) { + if (woal_cfg80211_remain_on_channel_cfg + (wiphy, MOAL_IOCTL_WAIT, MTRUE, &status, NULL, 0, 0)) { + PRINTM(MERROR, "Fail to cancel remain on channel\n"); + ret = -EFAULT; + goto done; + } + priv->phandle->cookie = 0; + priv->phandle->remain_on_channel = MFALSE; + } + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_remain_on_channel_cfg(wiphy, MOAL_IOCTL_WAIT, + MFALSE, &status, chan, channel_type, + (t_u32) duration)) { + ret = -EFAULT; + goto done; + } + if (status == 0) { + /* remain on channel operation success */ + /* we need update the value cookie */ + *cookie = (u64) random32() | 1; + priv->phandle->remain_on_channel = MTRUE; + priv->phandle->cookie = *cookie; + priv->phandle->channel_type = channel_type; + memcpy(&priv->phandle->chan, chan, sizeof(struct ieee80211_channel)); + cfg80211_ready_on_channel(dev, *cookie, chan, + channel_type, duration, GFP_KERNEL); + PRINTM(MIOCTL, "Set remain on Channel: channel=%d cookie = %#llx\n", + ieee80211_frequency_to_channel(chan->center_freq), + priv->phandle->cookie); + } + + done: + LEAVE(); + return ret; +} + +/** + * @brief Cancel remain on channel + * + * @param wiphy A pointer to wiphy structure + * @param dev A pointer to net_device structure + * @param cookie A pointer to timer cookie + * + * @return 0 -- success, otherwise fail + */ +static int +woal_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, + struct net_device *dev, u64 cookie) +{ + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + int ret = 0; + t_u8 status = 1; + + ENTER(); + PRINTM(MIOCTL, "Cancel remain on Channel: cookie = %#llx\n", cookie); + if (woal_cfg80211_remain_on_channel_cfg + (wiphy, MOAL_IOCTL_WAIT, MTRUE, &status, NULL, 0, 0)) { + PRINTM(MERROR, "Fail to cancel remain on channel\n"); + ret = -EFAULT; + goto done; + } + + priv->phandle->remain_on_channel = MFALSE; + if (priv->phandle->cookie) + priv->phandle->cookie = 0; + done: + LEAVE(); + return ret; +} +#endif /* KERNEL_VERSION */ +#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */ + +/** + * @brief Initialize the wiphy + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +woal_cfg80211_sta_init_wiphy(moal_private * priv, t_u8 wait_option) +{ + int retry_count, rts_thr, frag_thr, disabled; + struct wiphy *wiphy = NULL; + mlan_ioctl_req *req = NULL; + mlan_ds_11n_cfg *cfg_11n = NULL; + t_u32 hw_dev_cap; + + ENTER(); + + if (priv->wdev) + wiphy = priv->wdev->wiphy; + else { + PRINTM(MERROR, "Invalid parameter when init wiphy.\n"); + goto done; + } + + /* Get 11n tx parameters from MLAN */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); + if (req == NULL) { + LEAVE(); + return MLAN_STATUS_FAILURE; + } + cfg_11n = (mlan_ds_11n_cfg *) req->pbuf; + cfg_11n->sub_command = MLAN_OID_11N_HTCAP_CFG; + req->req_id = MLAN_IOCTL_11N_CFG; + req->action = MLAN_ACT_GET; + cfg_11n->param.htcap_cfg.hw_cap_req = MTRUE; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, wait_option)) { + kfree(req); + LEAVE(); + return MLAN_STATUS_FAILURE; + } + hw_dev_cap = cfg_11n->param.htcap_cfg.htcap; + + /* Get supported MCS sets */ + memset(req->pbuf, 0, sizeof(mlan_ds_11n_cfg)); + cfg_11n->sub_command = MLAN_OID_11N_CFG_SUPPORTED_MCS_SET; + req->req_id = MLAN_IOCTL_11N_CFG; + req->action = MLAN_ACT_GET; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, wait_option)) { + kfree(req); + LEAVE(); + return MLAN_STATUS_FAILURE; + } + + /* Initialize parameters for 2GHz and 5GHz bands */ + woal_cfg80211_setup_sta_ht_cap(&wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap, + hw_dev_cap, + cfg_11n->param.supported_mcs_set); + /* For 2.4G band only card, this shouldn't be set + woal_cfg80211_setup_sta_ht_cap(&wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap, + hw_dev_cap, cfg_11n->param.supported_mcs_set); */ + if (req) + kfree(req); + + /* Set retry limit count to wiphy */ + if (MLAN_STATUS_SUCCESS != + woal_set_get_retry(priv, MLAN_ACT_GET, wait_option, &retry_count)) { + LEAVE(); + return MLAN_STATUS_FAILURE; + } + wiphy->retry_long = (t_u8) retry_count; + wiphy->retry_short = (t_u8) retry_count; + wiphy->max_scan_ie_len = MAX_IE_SIZE; + +#if defined(WIFI_DIRECT_SUPPORT) +#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION + /* we should add mgmt_stypes for both STA & Wifi Direct, while only + initialize duration_timer for Wifi Direct */ + wiphy->mgmt_stypes = ieee80211_mgmt_stypes; + wiphy->max_remain_on_channel_duration = MAX_REMAIN_ON_CHANNEL_DURATION; +#endif /* KERNEL_VERSION */ +#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */ + + /* Set RTS threshold to wiphy */ + if (MLAN_STATUS_SUCCESS != + woal_set_get_rts(priv, MLAN_ACT_GET, wait_option, &rts_thr)) { + LEAVE(); + return MLAN_STATUS_FAILURE; + } + if (rts_thr < MLAN_RTS_MIN_VALUE || rts_thr > MLAN_RTS_MAX_VALUE) + rts_thr = MLAN_FRAG_RTS_DISABLED; + wiphy->rts_threshold = (t_u32) rts_thr; + + /* Set fragment threshold to wiphy */ + if (MLAN_STATUS_SUCCESS != + woal_set_get_frag(priv, MLAN_ACT_GET, wait_option, &frag_thr)) { + LEAVE(); + return MLAN_STATUS_FAILURE; + } + if (frag_thr < MLAN_RTS_MIN_VALUE || frag_thr > MLAN_RTS_MAX_VALUE) + frag_thr = MLAN_FRAG_RTS_DISABLED; + wiphy->frag_threshold = (t_u32) frag_thr; + + /* Get IEEE power save mode */ + if (MLAN_STATUS_SUCCESS != woal_set_get_power_mgmt(priv, + MLAN_ACT_GET, &disabled, + 0)) { + LEAVE(); + return MLAN_STATUS_FAILURE; + } + /* Save the IEEE power save mode to wiphy, because after warmreset wiphy + power save should be updated instead of using the last saved + configuration */ + if (disabled) + priv->wdev->ps = MFALSE; + else + priv->wdev->ps = MTRUE; + + done: + LEAVE(); + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Register the device with cfg80211 + * + * @param dev A pointer to net_device structure + * @param bss_type BSS type + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +woal_register_sta_cfg80211(struct net_device * dev, t_u8 bss_type) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + moal_private *priv = (moal_private *) netdev_priv(dev); + void *wdev_priv = NULL; + struct wireless_dev *wdev = NULL; + mlan_fw_info fw_info; + + ENTER(); + + /* Allocate wireless device */ + wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); + if (!wdev) { + PRINTM(MERROR, "Could not allocate wireless device\n"); + ret = MLAN_STATUS_FAILURE; + goto err_wdev; + } + + if (bss_type == MLAN_BSS_TYPE_STA) + /* Allocate wiphy */ + wdev->wiphy = wiphy_new(&woal_cfg80211_sta_ops, sizeof(moal_private *)); +#if defined(WIFI_DIRECT_SUPPORT) +#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION + else if (bss_type == MLAN_BSS_TYPE_WIFIDIRECT) + /* Allocate wiphy */ + wdev->wiphy = + wiphy_new(&woal_cfg80211_wifi_direct_ops, sizeof(moal_private *)); +#endif +#endif + else { + PRINTM(MERROR, "Unexpected bss_type when register cfg80211\n"); + ret = MLAN_STATUS_FAILURE; + goto err_wdev; + } + + if (!wdev->wiphy) { + PRINTM(MERROR, "Could not allocate wiphy device\n"); + ret = MLAN_STATUS_FAILURE; + goto err_wdev; + } + if (bss_type == MLAN_BSS_TYPE_STA) { + wdev->iftype = NL80211_IFTYPE_STATION; + wdev->wiphy->interface_modes = + MBIT(NL80211_IFTYPE_STATION) | MBIT(NL80211_IFTYPE_ADHOC); + wdev->wiphy->max_scan_ssids = 10; + } +#if defined(WIFI_DIRECT_SUPPORT) +#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION + if (bss_type == MLAN_BSS_TYPE_WIFIDIRECT) { + wdev->iftype = NL80211_IFTYPE_STATION; + wdev->wiphy->interface_modes = MBIT(NL80211_IFTYPE_STATION) | + MBIT(NL80211_IFTYPE_P2P_GO) | + MBIT(NL80211_IFTYPE_P2P_CLIENT) | + MBIT(NL80211_IFTYPE_ADHOC) | MBIT(NL80211_IFTYPE_AP) | + MBIT(NL80211_IFTYPE_MONITOR); + wdev->wiphy->max_scan_ssids = 10; + } +#endif +#endif + + /* Set phy name like net device name */ + dev_set_name(&wdev->wiphy->dev, dev->name); + + /* Make this wiphy known to this driver only */ + wdev->wiphy->privid = mrvl_wiphy_privid; + + /* Supported bands */ + wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &cfg80211_band_2ghz; + if (MLAN_STATUS_SUCCESS == + woal_request_get_fw_info(priv, MOAL_CMD_WAIT, &fw_info)) { + if (fw_info.fw_bands & BAND_A) + wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &cfg80211_band_5ghz; + } + /* Initialize cipher suits */ + wdev->wiphy->cipher_suites = cfg80211_cipher_suites; + wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cfg80211_cipher_suites); + + wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + + /* We are using custom domains */ + wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + + wdev->wiphy->reg_notifier = woal_cfg80211_reg_notifier; + + /* Set moal_private pointer in wiphy_priv */ + wdev_priv = wiphy_priv(wdev->wiphy); + + *(unsigned long *) wdev_priv = (unsigned long) priv; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) || defined(COMPAT_WIRELESS) + set_wiphy_dev(wdev->wiphy, (struct device *) priv->phandle->hotplug_device); +#endif + + if (wiphy_register(wdev->wiphy) < 0) { + PRINTM(MERROR, "Wiphy device registration failed!\n"); + ret = MLAN_STATUS_FAILURE; + goto err_wdev; + } + + dev_net_set(dev, wiphy_net(wdev->wiphy)); + dev->ieee80211_ptr = wdev; + SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy)); + priv->wdev = wdev; + + if (ret != MLAN_STATUS_SUCCESS) { + PRINTM(MERROR, "Wiphy device registration failed!\n"); + } else { + PRINTM(MINFO, "Successfully registered wiphy device\n"); + LEAVE(); + return ret; + } + + wiphy_unregister(wdev->wiphy); + err_wdev: + dev->ieee80211_ptr = NULL; + if (wdev && wdev->wiphy) + wiphy_free(wdev->wiphy); + kfree(wdev); + LEAVE(); + return ret; +} diff --git a/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.h b/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.h new file mode 100644 index 000000000000..a83957c5c031 --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.h @@ -0,0 +1,41 @@ +/** @file moal_sta_cfg80211.h + * + * @brief This file contains the STA CFG80211 specific defines. + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +#ifndef _MOAL_STA_CFG80211_H_ +#define _MOAL_STA_CFG80211_H_ + +/** Convert RSSI signal strength from dBm to mBm (100*dBm) */ +#define RSSI_DBM_TO_MDM(x) ((x) * 100) + +mlan_status woal_register_sta_cfg80211(struct net_device *dev, t_u8 bss_type); +mlan_status woal_cfg80211_sta_init_wiphy(moal_private * priv, t_u8 wait_option); + +mlan_status +woal_cfg80211_set_key(moal_private * priv, t_u8 is_enable_wep, + t_u32 cipher, const t_u8 * key, int key_len, + const t_u8 * seq, int seq_len, t_u8 key_index, + const t_u8 * addr, int disable); + +mlan_status +woal_cfg80211_set_wep_keys(moal_private * priv, const t_u8 * key, int key_len, + t_u8 index); + +#endif /* _MOAL_STA_CFG80211_H_ */ diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap.c b/drivers/net/wireless/sd8797/mlinux/moal_uap.c new file mode 100644 index 000000000000..7dac877abe00 --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/moal_uap.c @@ -0,0 +1,2692 @@ +/** @file moal_uap.c + * + * @brief This file contains the major functions in UAP + * driver. + * + * Copyright (C) 2008-2012, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +/******************************************************** +Change log: + 10/21/2008: initial version +********************************************************/ + +#include "moal_main.h" +#include "moal_uap.h" +#include "moal_sdio.h" +#include "moal_eth_ioctl.h" +#if defined(STA_CFG80211) && defined(UAP_CFG80211) +#include "moal_cfg80211.h" +#endif + +/******************************************************** + Local Variables +********************************************************/ + +/******************************************************** + Global Variables +********************************************************/ + +/******************************************************** + Local Functions +********************************************************/ +/** + * @brief uap addba parameter handler + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int +woal_uap_addba_param(struct net_device *dev, struct ifreq *req) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_ioctl_req *ioctl_req = NULL; + mlan_ds_11n_cfg *cfg_11n = NULL; + addba_param param; + int ret = 0; + + ENTER(); + memset(¶m, 0, sizeof(param)); + + /* Sanity check */ + if (req->ifr_data == NULL) { + PRINTM(MERROR, "uap_addba_param() corrupt data\n"); + ret = -EFAULT; + goto done; + } + if (copy_from_user(¶m, req->ifr_data, sizeof(param))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + PRINTM(MIOCTL, + "addba param: action=%d, timeout=%d, txwinsize=%d, rxwinsize=%d txamsdu=%d rxamsdu=%d\n", + (int) param.action, (int) param.timeout, (int) param.txwinsize, + (int) param.rxwinsize, (int) param.txamsdu, (int) param.rxamsdu); + ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); + if (ioctl_req == NULL) { + LEAVE(); + return -ENOMEM; + } + cfg_11n = (mlan_ds_11n_cfg *) ioctl_req->pbuf; + cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_PARAM; + ioctl_req->req_id = MLAN_IOCTL_11N_CFG; + + if (!param.action) { + /* Get addba param from MLAN */ + ioctl_req->action = MLAN_ACT_GET; + } else { + /* Set addba param in MLAN */ + ioctl_req->action = MLAN_ACT_SET; + cfg_11n->param.addba_param.timeout = param.timeout; + cfg_11n->param.addba_param.txwinsize = param.txwinsize; + cfg_11n->param.addba_param.rxwinsize = param.rxwinsize; + cfg_11n->param.addba_param.txamsdu = param.txamsdu; + cfg_11n->param.addba_param.rxamsdu = param.rxamsdu; + } + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + param.timeout = cfg_11n->param.addba_param.timeout; + param.txwinsize = cfg_11n->param.addba_param.txwinsize; + param.rxwinsize = cfg_11n->param.addba_param.rxwinsize; + param.txamsdu = cfg_11n->param.addba_param.txamsdu; + param.rxamsdu = cfg_11n->param.addba_param.rxamsdu; + + /* Copy to user */ + if (copy_to_user(req->ifr_data, ¶m, sizeof(param))) { + PRINTM(MERROR, "Copy to user failed!\n"); + ret = -EFAULT; + goto done; + } + done: + if (ioctl_req) + kfree(ioctl_req); + LEAVE(); + return ret; +} + +/** + * @brief uap aggr priority tbl + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int +woal_uap_aggr_priotbl(struct net_device *dev, struct ifreq *req) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_ioctl_req *ioctl_req = NULL; + mlan_ds_11n_cfg *cfg_11n = NULL; + aggr_prio_tbl param; + int ret = 0; + int i = 0; + + ENTER(); + memset(¶m, 0, sizeof(param)); + + /* Sanity check */ + if (req->ifr_data == NULL) { + PRINTM(MERROR, "woal_uap_aggr_priotbl() corrupt data\n"); + ret = -EFAULT; + goto done; + } + if (copy_from_user(¶m, req->ifr_data, sizeof(param))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + DBG_HEXDUMP(MCMD_D, "aggr_prio_tbl", (t_u8 *) & param, sizeof(param)); + + ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); + if (ioctl_req == NULL) { + LEAVE(); + return -ENOMEM; + } + cfg_11n = (mlan_ds_11n_cfg *) ioctl_req->pbuf; + cfg_11n->sub_command = MLAN_OID_11N_CFG_AGGR_PRIO_TBL; + ioctl_req->req_id = MLAN_IOCTL_11N_CFG; + + if (!param.action) { + /* Get aggr_prio_tbl from MLAN */ + ioctl_req->action = MLAN_ACT_GET; + } else { + /* Set aggr_prio_tbl in MLAN */ + ioctl_req->action = MLAN_ACT_SET; + for (i = 0; i < MAX_NUM_TID; i++) { + cfg_11n->param.aggr_prio_tbl.ampdu[i] = param.ampdu[i]; + cfg_11n->param.aggr_prio_tbl.amsdu[i] = param.amsdu[i]; + } + } + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + for (i = 0; i < MAX_NUM_TID; i++) { + param.ampdu[i] = cfg_11n->param.aggr_prio_tbl.ampdu[i]; + param.amsdu[i] = cfg_11n->param.aggr_prio_tbl.amsdu[i]; + } + /* Copy to user */ + if (copy_to_user(req->ifr_data, ¶m, sizeof(param))) { + PRINTM(MERROR, "Copy to user failed!\n"); + ret = -EFAULT; + goto done; + } + done: + if (ioctl_req) + kfree(ioctl_req); + LEAVE(); + return ret; +} + +/** + * @brief uap addba reject tbl + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int +woal_uap_addba_reject(struct net_device *dev, struct ifreq *req) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_ioctl_req *ioctl_req = NULL; + mlan_ds_11n_cfg *cfg_11n = NULL; + addba_reject_para param; + int ret = 0; + int i = 0; + + ENTER(); + memset(¶m, 0, sizeof(param)); + + /* Sanity check */ + if (req->ifr_data == NULL) { + PRINTM(MERROR, "woal_uap_addba_reject() corrupt data\n"); + ret = -EFAULT; + goto done; + } + if (copy_from_user(¶m, req->ifr_data, sizeof(param))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + DBG_HEXDUMP(MCMD_D, "addba_reject tbl", (t_u8 *) & param, sizeof(param)); + + ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); + if (ioctl_req == NULL) { + LEAVE(); + return -ENOMEM; + } + cfg_11n = (mlan_ds_11n_cfg *) ioctl_req->pbuf; + cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_REJECT; + ioctl_req->req_id = MLAN_IOCTL_11N_CFG; + + if (!param.action) { + /* Get addba_reject tbl from MLAN */ + ioctl_req->action = MLAN_ACT_GET; + } else { + /* Set addba_reject tbl in MLAN */ + ioctl_req->action = MLAN_ACT_SET; + for (i = 0; i < MAX_NUM_TID; i++) { + cfg_11n->param.addba_reject[i] = param.addba_reject[i]; + } + } + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + for (i = 0; i < MAX_NUM_TID; i++) { + param.addba_reject[i] = cfg_11n->param.addba_reject[i]; + } + /* Copy to user */ + if (copy_to_user(req->ifr_data, ¶m, sizeof(param))) { + PRINTM(MERROR, "Copy to user failed!\n"); + ret = -EFAULT; + goto done; + } + done: + if (ioctl_req) + kfree(ioctl_req); + LEAVE(); + return ret; +} + +/** + * @brief uap get_fw_info handler + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int +woal_uap_get_fw_info(struct net_device *dev, struct ifreq *req) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + fw_info fw; + mlan_fw_info fw_info; + int ret = 0; + + ENTER(); + memset(&fw, 0, sizeof(fw)); + memset(&fw_info, 0, sizeof(fw_info)); + + /* Sanity check */ + if (req->ifr_data == NULL) { + PRINTM(MERROR, "woal_uap_get_fw_info() corrupt data\n"); + ret = -EFAULT; + goto done; + } + if (copy_from_user(&fw, req->ifr_data, sizeof(fw))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + if (MLAN_STATUS_SUCCESS != + woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info)) { + ret = -EFAULT; + goto done; + } + fw.fw_release_number = fw_info.fw_ver; + fw.hw_dev_mcs_support = fw_info.hw_dev_mcs_support; + /* Copy to user */ + if (copy_to_user(req->ifr_data, &fw, sizeof(fw))) { + PRINTM(MERROR, "Copy to user failed!\n"); + ret = -EFAULT; + goto done; + } + done: + LEAVE(); + return ret; +} + +/** + * @brief configure deep sleep + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int +woal_uap_deep_sleep(struct net_device *dev, struct ifreq *req) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_ioctl_req *ioctl_req = NULL; + mlan_ds_pm_cfg *pm = NULL; + deep_sleep_para param; + int ret = 0; + + ENTER(); + memset(¶m, 0, sizeof(param)); + + /* Sanity check */ + if (req->ifr_data == NULL) { + PRINTM(MERROR, "woal_uap_deep_sleep() corrupt data\n"); + ret = -EFAULT; + goto done; + } + if (copy_from_user(¶m, req->ifr_data, sizeof(param))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + DBG_HEXDUMP(MCMD_D, "deep_sleep_para", (t_u8 *) & param, sizeof(param)); + + ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg)); + if (ioctl_req == NULL) { + LEAVE(); + return -ENOMEM; + } + pm = (mlan_ds_pm_cfg *) ioctl_req->pbuf; + pm->sub_command = MLAN_OID_PM_CFG_DEEP_SLEEP; + ioctl_req->req_id = MLAN_IOCTL_PM_CFG; + + if (!param.action) { + /* Get deep_sleep status from MLAN */ + ioctl_req->action = MLAN_ACT_GET; + } else { + /* Set deep_sleep in MLAN */ + ioctl_req->action = MLAN_ACT_SET; + if (param.deep_sleep == MTRUE) { + pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_ON; + pm->param.auto_deep_sleep.idletime = param.idle_time; + } else { + pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_OFF; + } + } + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + if (pm->param.auto_deep_sleep.auto_ds == DEEP_SLEEP_ON) + param.deep_sleep = MTRUE; + else + param.deep_sleep = MFALSE; + param.idle_time = pm->param.auto_deep_sleep.idletime; + /* Copy to user */ + if (copy_to_user(req->ifr_data, ¶m, sizeof(param))) { + PRINTM(MERROR, "Copy to user failed!\n"); + ret = -EFAULT; + goto done; + } + done: + if (ioctl_req) + kfree(ioctl_req); + LEAVE(); + return ret; +} + +/** + * @brief configure tx_pause settings + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int +woal_uap_txdatapause(struct net_device *dev, struct ifreq *req) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_ioctl_req *ioctl_req = NULL; + mlan_ds_misc_cfg *misc = NULL; + tx_data_pause_para param; + int ret = 0; + + ENTER(); + memset(¶m, 0, sizeof(param)); + + /* Sanity check */ + if (req->ifr_data == NULL) { + PRINTM(MERROR, "woal_uap_txdatapause corrupt data\n"); + ret = -EFAULT; + goto done; + } + if (copy_from_user(¶m, req->ifr_data, sizeof(param))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + DBG_HEXDUMP(MCMD_D, "tx_data_pause_para", (t_u8 *) & param, sizeof(param)); + + ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (ioctl_req == NULL) { + LEAVE(); + return -ENOMEM; + } + misc = (mlan_ds_misc_cfg *) ioctl_req->pbuf; + misc->sub_command = MLAN_OID_MISC_TX_DATAPAUSE; + ioctl_req->req_id = MLAN_IOCTL_MISC_CFG; + + if (!param.action) { + /* Get Tx data pause status from MLAN */ + ioctl_req->action = MLAN_ACT_GET; + } else { + /* Set Tx data pause in MLAN */ + ioctl_req->action = MLAN_ACT_SET; + misc->param.tx_datapause.tx_pause = param.txpause; + misc->param.tx_datapause.tx_buf_cnt = param.txbufcnt; + } + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + param.txpause = misc->param.tx_datapause.tx_pause; + param.txbufcnt = misc->param.tx_datapause.tx_buf_cnt; + + /* Copy to user */ + if (copy_to_user(req->ifr_data, ¶m, sizeof(param))) { + PRINTM(MERROR, "Copy to user failed!\n"); + ret = -EFAULT; + goto done; + } + done: + if (ioctl_req) + kfree(ioctl_req); + LEAVE(); + return ret; +} + +/** + * @brief uap sdcmd52rw ioctl handler + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int +woal_uap_sdcmd52_rw(struct net_device *dev, struct ifreq *req) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + sdcmd52_para param; + t_u8 func, data = 0; + int ret = 0, reg; + + ENTER(); + memset(¶m, 0, sizeof(param)); + + /* Sanity check */ + if (req->ifr_data == NULL) { + PRINTM(MERROR, "woal_uap_sdcmd52_rw() corrupt data\n"); + ret = -EFAULT; + goto done; + } + if (copy_from_user(¶m, req->ifr_data, sizeof(param))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + func = (t_u8) param.cmd52_params[0]; + reg = (t_u32) param.cmd52_params[1]; + + if (!param.action) { + PRINTM(MINFO, "Cmd52 read, func=%d, reg=0x%08X\n", func, reg); + sdio_claim_host(((struct sdio_mmc_card *) priv->phandle->card)->func); + if (func) + data = + sdio_readb(((struct sdio_mmc_card *) priv->phandle->card)->func, + reg, &ret); + else + data = + sdio_f0_readb(((struct sdio_mmc_card *) priv->phandle->card)-> + func, reg, &ret); + sdio_release_host(((struct sdio_mmc_card *) priv->phandle->card)->func); + if (ret) { + PRINTM(MERROR, "sdio_readb: reading register 0x%X failed\n", reg); + goto done; + } + param.cmd52_params[2] = data; + } else { + data = (t_u8) param.cmd52_params[2]; + PRINTM(MINFO, "Cmd52 write, func=%d, reg=0x%08X, data=0x%02X\n", func, + reg, data); + sdio_claim_host(((struct sdio_mmc_card *) priv->phandle->card)->func); + if (func) + sdio_writeb(((struct sdio_mmc_card *) priv->phandle->card)->func, + data, reg, &ret); + else + sdio_f0_writeb(((struct sdio_mmc_card *) priv->phandle->card)->func, + data, reg, &ret); + sdio_release_host(((struct sdio_mmc_card *) priv->phandle->card)->func); + if (ret) { + PRINTM(MERROR, "sdio_writeb: writing register 0x%X failed\n", reg); + goto done; + } + } + /* Copy to user */ + if (copy_to_user(req->ifr_data, ¶m, sizeof(param))) { + PRINTM(MERROR, "Copy to user failed!\n"); + ret = -EFAULT; + } + done: + LEAVE(); + return ret; +} + +/** + * @brief configure snmp mib + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int +woal_uap_snmp_mib(struct net_device *dev, struct ifreq *req) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_ioctl_req *ioctl_req = NULL; + mlan_ds_snmp_mib *snmp = NULL; + snmp_mib_para param; + t_u8 value[MAX_SNMP_VALUE_SIZE]; + int ret = 0; + + ENTER(); + memset(¶m, 0, sizeof(param)); + memset(value, 0, MAX_SNMP_VALUE_SIZE); + + /* Sanity check */ + if (req->ifr_data == NULL) { + PRINTM(MERROR, "woal_uap_snmp_mib() corrupt data\n"); + ret = -EFAULT; + goto done; + } + + /* Copy from user */ + if (copy_from_user(¶m, req->ifr_data, sizeof(param))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + DBG_HEXDUMP(MCMD_D, "snmp_mib_para", (t_u8 *) & param, sizeof(param)); + if (param.action) { + if (copy_from_user(value, req->ifr_data + sizeof(param), + MIN(param.oid_val_len, MAX_SNMP_VALUE_SIZE))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + DBG_HEXDUMP(MCMD_D, "snmp_mib_para value", value, + MIN(param.oid_val_len, sizeof(t_u32))); + } + + ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib)); + if (ioctl_req == NULL) { + LEAVE(); + return -ENOMEM; + } + snmp = (mlan_ds_snmp_mib *) ioctl_req->pbuf; + ioctl_req->req_id = MLAN_IOCTL_SNMP_MIB; + switch (param.oid) { + case OID_80211D_ENABLE: + snmp->sub_command = MLAN_OID_SNMP_MIB_DOT11D; + break; + case OID_80211H_ENABLE: + snmp->sub_command = MLAN_OID_SNMP_MIB_DOT11H; + break; + default: + PRINTM(MERROR, "%s: Unsupported SNMP_MIB OID (%d).\n", __FUNCTION__, + param.oid); + goto done; + } + + if (!param.action) { + /* Get mib value from MLAN */ + ioctl_req->action = MLAN_ACT_GET; + } else { + /* Set mib value to MLAN */ + ioctl_req->action = MLAN_ACT_SET; + snmp->param.oid_value = *(t_u32 *) value; + } + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + /* Copy to user */ + if (copy_to_user(req->ifr_data, ¶m, sizeof(param))) { + PRINTM(MERROR, "Copy to user failed!\n"); + ret = -EFAULT; + goto done; + } + if (!param.action) { /* GET */ + if (copy_to_user(req->ifr_data + sizeof(param), &snmp->param.oid_value, + MIN(param.oid_val_len, sizeof(t_u32)))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + } + + done: + if (ioctl_req) + kfree(ioctl_req); + LEAVE(); + return ret; +} + +/** + * @brief configure domain info + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int +woal_uap_domain_info(struct net_device *dev, struct ifreq *req) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_ioctl_req *ioctl_req = NULL; + mlan_ds_11d_cfg *cfg11d = NULL; + domain_info_para param; + t_u8 tlv[MAX_DOMAIN_TLV_LEN]; + t_u16 tlv_data_len = 0; + int ret = 0; + + ENTER(); + memset(¶m, 0, sizeof(param)); + memset(tlv, 0, MAX_DOMAIN_TLV_LEN); + + /* Sanity check */ + if (req->ifr_data == NULL) { + PRINTM(MERROR, "woal_uap_domain_info() corrupt data\n"); + ret = -EFAULT; + goto done; + } + + /* Copy from user */ + if (copy_from_user(¶m, req->ifr_data, sizeof(param))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + DBG_HEXDUMP(MCMD_D, "domain_info_para", (t_u8 *) & param, sizeof(param)); + if (param.action) { + /* get tlv header */ + if (copy_from_user(tlv, req->ifr_data + sizeof(param), TLV_HEADER_LEN)) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + tlv_data_len = ((t_u16 *) (tlv))[1]; + if ((TLV_HEADER_LEN + tlv_data_len) > sizeof(tlv)) { + PRINTM(MERROR, "TLV buffer is overflowed"); + ret = -EINVAL; + goto done; + } + /* get full tlv */ + if (copy_from_user(tlv, req->ifr_data + sizeof(param), + TLV_HEADER_LEN + tlv_data_len)) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + DBG_HEXDUMP(MCMD_D, "domain_info_para tlv", tlv, + TLV_HEADER_LEN + tlv_data_len); + } + + ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg)); + if (ioctl_req == NULL) { + LEAVE(); + return -ENOMEM; + } + cfg11d = (mlan_ds_11d_cfg *) ioctl_req->pbuf; + ioctl_req->req_id = MLAN_IOCTL_11D_CFG; + cfg11d->sub_command = MLAN_OID_11D_DOMAIN_INFO; + + if (!param.action) { + /* Get mib value from MLAN */ + ioctl_req->action = MLAN_ACT_GET; + } else { + /* Set mib value to MLAN */ + ioctl_req->action = MLAN_ACT_SET; + memcpy(cfg11d->param.domain_tlv, tlv, + MIN(MAX_IE_SIZE, (TLV_HEADER_LEN + tlv_data_len))); + } + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + /* Copy to user */ + if (copy_to_user(req->ifr_data, ¶m, sizeof(param))) { + PRINTM(MERROR, "Copy to user failed!\n"); + ret = -EFAULT; + goto done; + } + if (!param.action) { /* GET */ + tlv_data_len = ((t_u16 *) (cfg11d->param.domain_tlv))[1]; + if (copy_to_user + (req->ifr_data + sizeof(param), &cfg11d->param.domain_tlv, + TLV_HEADER_LEN + tlv_data_len)) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + } + + done: + if (ioctl_req) + kfree(ioctl_req); + LEAVE(); + return ret; +} + +#if defined(DFS_TESTING_SUPPORT) +/** + * @brief configure dfs testing settings + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int +woal_uap_dfs_testing(struct net_device *dev, struct ifreq *req) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_ioctl_req *ioctl_req = NULL; + mlan_ds_11h_cfg *cfg11h = NULL; + dfs_testing_para param; + int ret = 0; + + ENTER(); + memset(¶m, 0, sizeof(param)); + + /* Sanity check */ + if (req->ifr_data == NULL) { + PRINTM(MERROR, "woal_uap_dfs_testing() corrupt data\n"); + ret = -EFAULT; + goto done; + } + + /* Copy from user */ + if (copy_from_user(¶m, req->ifr_data, sizeof(param))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + DBG_HEXDUMP(MCMD_D, "dfs_testing_para", (t_u8 *) & param, sizeof(param)); + + ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg)); + if (ioctl_req == NULL) { + LEAVE(); + return -ENOMEM; + } + cfg11h = (mlan_ds_11h_cfg *) ioctl_req->pbuf; + ioctl_req->req_id = MLAN_IOCTL_11H_CFG; + cfg11h->sub_command = MLAN_OID_11H_DFS_TESTING; + + if (!param.action) { + /* Get mib value from MLAN */ + ioctl_req->action = MLAN_ACT_GET; + } else { + /* Set mib value to MLAN */ + ioctl_req->action = MLAN_ACT_SET; + cfg11h->param.dfs_testing.usr_cac_period_msec = param.usr_cac_period; + cfg11h->param.dfs_testing.usr_nop_period_sec = param.usr_nop_period; + cfg11h->param.dfs_testing.usr_no_chan_change = param.no_chan_change; + cfg11h->param.dfs_testing.usr_fixed_new_chan = param.fixed_new_chan; + priv->phandle->cac_period_jiffies = param.usr_cac_period * HZ / 1000; + } + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + if (!param.action) { /* GET */ + param.usr_cac_period = cfg11h->param.dfs_testing.usr_cac_period_msec; + param.usr_nop_period = cfg11h->param.dfs_testing.usr_nop_period_sec; + param.no_chan_change = cfg11h->param.dfs_testing.usr_no_chan_change; + param.fixed_new_chan = cfg11h->param.dfs_testing.usr_fixed_new_chan; + } + /* Copy to user */ + if (copy_to_user(req->ifr_data, ¶m, sizeof(param))) { + PRINTM(MERROR, "Copy to user failed!\n"); + ret = -EFAULT; + goto done; + } + + done: + if (ioctl_req) + kfree(ioctl_req); + LEAVE(); + return ret; +} +#endif + +/** + * @brief Configure TX beamforming support + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int +woal_uap_tx_bf_cfg(struct net_device *dev, struct ifreq *req) +{ + int ret = 0; + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_ds_11n_tx_bf_cfg bf_cfg; + tx_bf_cfg_para_hdr param; + t_u16 action = 0; + + ENTER(); + + memset(¶m, 0, sizeof(param)); + memset(&bf_cfg, 0, sizeof(bf_cfg)); + + /* Sanity check */ + if (req->ifr_data == NULL) { + PRINTM(MERROR, "woal_uap_tx_bf_cfg corrupt data\n"); + ret = -EFAULT; + goto done; + } + if (copy_from_user(¶m, req->ifr_data, sizeof(param))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + if (!param.action) { + /* Get BF configurations */ + action = MLAN_ACT_GET; + } else { + /* Set BF configurations */ + action = MLAN_ACT_SET; + } + if (copy_from_user(&bf_cfg, req->ifr_data + sizeof(tx_bf_cfg_para_hdr), + sizeof(bf_cfg))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + DBG_HEXDUMP(MCMD_D, "bf_cfg", (t_u8 *) & bf_cfg, sizeof(bf_cfg)); + + if (MLAN_STATUS_SUCCESS != woal_set_get_tx_bf_cfg(priv, action, &bf_cfg)) { + ret = -EFAULT; + goto done; + } + + /* Copy to user */ + if (copy_to_user(req->ifr_data + sizeof(tx_bf_cfg_para_hdr), + &bf_cfg, sizeof(bf_cfg))) { + PRINTM(MERROR, "Copy to user failed!\n"); + ret = -EFAULT; + goto done; + } + + done: + LEAVE(); + return ret; +} + +/** + * @brief uap hs_cfg ioctl handler + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int +woal_uap_hs_cfg(struct net_device *dev, struct ifreq *req, + BOOLEAN invoke_hostcmd) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_ds_hs_cfg hscfg; + ds_hs_cfg hs_cfg; + mlan_bss_info bss_info; + t_u16 action; + int ret = 0; + + ENTER(); + + memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg)); + memset(&hs_cfg, 0, sizeof(ds_hs_cfg)); + + /* Sanity check */ + if (req->ifr_data == NULL) { + PRINTM(MERROR, "uap_hs_cfg() corrupt data\n"); + ret = -EFAULT; + goto done; + } + if (copy_from_user(&hs_cfg, req->ifr_data, sizeof(ds_hs_cfg))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + PRINTM(MIOCTL, "ioctl hscfg: flags=0x%x condition=0x%x gpio=%d gap=0x%x\n", + hs_cfg.flags, hs_cfg.conditions, (int) hs_cfg.gpio, hs_cfg.gap); + + /* HS config is blocked if HS is already activated */ + if ((hs_cfg.flags & HS_CFG_FLAG_CONDITION) && + (hs_cfg.conditions != HOST_SLEEP_CFG_CANCEL || + invoke_hostcmd == MFALSE)) { + memset(&bss_info, 0, sizeof(bss_info)); + woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info); + if (bss_info.is_hs_configured) { + PRINTM(MERROR, "HS already configured\n"); + ret = -EFAULT; + goto done; + } + } + + if (hs_cfg.flags & HS_CFG_FLAG_SET) { + action = MLAN_ACT_SET; + if (hs_cfg.flags != HS_CFG_FLAG_ALL) { + woal_set_get_hs_params(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT, &hscfg); + } + if (hs_cfg.flags & HS_CFG_FLAG_CONDITION) + hscfg.conditions = hs_cfg.conditions; + if (hs_cfg.flags & HS_CFG_FLAG_GPIO) + hscfg.gpio = hs_cfg.gpio; + if (hs_cfg.flags & HS_CFG_FLAG_GAP) + hscfg.gap = hs_cfg.gap; + + if (invoke_hostcmd == MTRUE) { + /* Issue IOCTL to set up parameters */ + hscfg.is_invoke_hostcmd = MFALSE; + if (MLAN_STATUS_SUCCESS != + woal_set_get_hs_params(priv, action, MOAL_IOCTL_WAIT, &hscfg)) { + ret = -EFAULT; + goto done; + } + } + } else { + action = MLAN_ACT_GET; + } + + /* Issue IOCTL to invoke hostcmd */ + hscfg.is_invoke_hostcmd = invoke_hostcmd; + if (MLAN_STATUS_SUCCESS != + woal_set_get_hs_params(priv, action, MOAL_IOCTL_WAIT, &hscfg)) { + ret = -EFAULT; + goto done; + } + if (!(hs_cfg.flags & HS_CFG_FLAG_SET)) { + hs_cfg.flags = + HS_CFG_FLAG_CONDITION | HS_CFG_FLAG_GPIO | HS_CFG_FLAG_GAP; + hs_cfg.conditions = hscfg.conditions; + hs_cfg.gpio = hscfg.gpio; + hs_cfg.gap = hscfg.gap; + /* Copy to user */ + if (copy_to_user(req->ifr_data, &hs_cfg, sizeof(ds_hs_cfg))) { + PRINTM(MERROR, "Copy to user failed!\n"); + ret = -EFAULT; + goto done; + } + } + + done: + LEAVE(); + return ret; +} + +/** + * @brief Set Host Sleep parameters + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_uap_hs_set_para(struct net_device *dev, struct ifreq *req) +{ + int ret = 0; + + ENTER(); + + if (req->ifr_data != NULL) { + ret = woal_uap_hs_cfg(dev, req, MFALSE); + goto done; + } else { + PRINTM(MERROR, "Invalid data\n"); + ret = -EINVAL; + goto done; + } + done: + LEAVE(); + return ret; +} + +/** + * @brief uap mgmt_frame_control ioctl handler + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int +woal_uap_mgmt_frame_control(struct net_device *dev, struct ifreq *req) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + int ret = 0; + t_u16 action = 0; + mgmt_frame_ctrl param; + mlan_uap_bss_param sys_config; + + ENTER(); + + /* Sanity check */ + if (req->ifr_data == NULL) { + PRINTM(MERROR, "uap_mgmt_frame_ctrl() corrupt data\n"); + ret = -EFAULT; + goto done; + } + + /* Get user data */ + if (copy_from_user(¶m, req->ifr_data, sizeof(param))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + if (param.action) { + action = MLAN_ACT_SET; + } else { + action = MLAN_ACT_GET; + } + if (action == MLAN_ACT_SET) { + /* Initialize the invalid values so that the correct values below are + downloaded to firmware */ + woal_set_sys_config_invalid_data(&sys_config); + sys_config.mgmt_ie_passthru_mask = param.mask; + } + + if (MLAN_STATUS_SUCCESS != + woal_set_get_sys_config(priv, action, MOAL_IOCTL_WAIT, &sys_config)) { + ret = -EFAULT; + goto done; + } + + if (action == MLAN_ACT_GET) { + param.mask = sys_config.mgmt_ie_passthru_mask; + if (copy_to_user(req->ifr_data, ¶m, sizeof(param))) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + } + } + done: + LEAVE(); + return ret; +} + +/** + * @brief Set/Get tx rate + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_uap_tx_rate_cfg(struct net_device *dev, struct ifreq *req) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + int ret = 0, i = 0; + mlan_ds_rate *rate = NULL; + mlan_ioctl_req *mreq = NULL; + tx_rate_cfg_t tx_rate_config; + + ENTER(); + + /* Sanity check */ + if (req->ifr_data == NULL) { + PRINTM(MERROR, "uap_tx_rate_cfg() corrupt data\n"); + ret = -EFAULT; + goto done; + } + + memset(&tx_rate_config, 0, sizeof(tx_rate_cfg_t)); + /* Get user data */ + if (copy_from_user(&tx_rate_config, req->ifr_data, sizeof(tx_rate_cfg_t))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + mreq = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate)); + if (mreq == NULL) { + ret = -ENOMEM; + goto done; + } + rate = (mlan_ds_rate *) mreq->pbuf; + rate->param.rate_cfg.rate_type = MLAN_RATE_INDEX; + rate->sub_command = MLAN_OID_RATE_CFG; + mreq->req_id = MLAN_IOCTL_RATE; + if (!(tx_rate_config.action)) + mreq->action = MLAN_ACT_GET; + else { + mreq->action = MLAN_ACT_SET; + if (tx_rate_config.rate == AUTO_RATE) + rate->param.rate_cfg.is_rate_auto = 1; + else { + if ((tx_rate_config.rate != MLAN_RATE_INDEX_MCS32) && + ((tx_rate_config.rate < 0) || + (tx_rate_config.rate > MLAN_RATE_INDEX_MCS15))) { + ret = -EINVAL; + goto done; + } + } + rate->param.rate_cfg.rate = tx_rate_config.rate; + } + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, mreq, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + if (tx_rate_config.action) { + priv->rate_index = tx_rate_config.action; + } else { + if (rate->param.rate_cfg.is_rate_auto) + tx_rate_config.rate = AUTO_RATE; + else + tx_rate_config.rate = rate->param.rate_cfg.rate; + for (i = 0; i < MAX_BITMAP_RATES_SIZE; i++) { + tx_rate_config.bitmap_rates[i] = + rate->param.rate_cfg.bitmap_rates[i]; + } + + if (copy_to_user(req->ifr_data, &tx_rate_config, sizeof(tx_rate_cfg_t))) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + } + } + done: + if (mreq) + kfree(mreq); + LEAVE(); + return ret; +} + +/** + * @brief Set/Get RF antenna mode + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_uap_antenna_cfg(struct net_device *dev, struct ifreq *req) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + int ret = 0; + mlan_ds_radio_cfg *radio = NULL; + mlan_ioctl_req *mreq = NULL; + ant_cfg_t antenna_config; + + ENTER(); + + /* Sanity check */ + if (req->ifr_data == NULL) { + PRINTM(MERROR, "uap_antenna_cfg() corrupt data\n"); + ret = -EFAULT; + goto done; + } + + memset(&antenna_config, 0, sizeof(ant_cfg_t)); + /* Get user data */ + if (copy_from_user(&antenna_config, req->ifr_data, sizeof(ant_cfg_t))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + mreq = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg)); + if (mreq == NULL) { + ret = -ENOMEM; + goto done; + } + radio = (mlan_ds_radio_cfg *) mreq->pbuf; + radio->sub_command = MLAN_OID_ANT_CFG; + mreq->req_id = MLAN_IOCTL_RADIO_CFG; + if (!(antenna_config.action)) + mreq->action = MLAN_ACT_GET; + else { + mreq->action = MLAN_ACT_SET; + radio->param.ant_cfg.tx_antenna = antenna_config.tx_mode; + radio->param.ant_cfg.rx_antenna = antenna_config.rx_mode; + } + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, mreq, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + if (mreq->action == MLAN_ACT_GET) { + antenna_config.tx_mode = radio->param.ant_cfg.tx_antenna; + antenna_config.rx_mode = radio->param.ant_cfg.rx_antenna; + if (copy_to_user(req->ifr_data, &antenna_config, sizeof(ant_cfg_t))) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + } + } + done: + if (mreq) + kfree(mreq); + LEAVE(); + return ret; +} + +/** + * @brief uap ioctl handler + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int +woal_uap_ioctl(struct net_device *dev, struct ifreq *req) +{ + int ret = 0; + t_u32 subcmd = 0; + ENTER(); + /* Sanity check */ + if (req->ifr_data == NULL) { + PRINTM(MERROR, "uap_ioctl() corrupt data\n"); + ret = -EFAULT; + goto done; + } + if (copy_from_user(&subcmd, req->ifr_data, sizeof(subcmd))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + PRINTM(MIOCTL, "ioctl subcmd=%d\n", (int) subcmd); + switch (subcmd) { + case UAP_ADDBA_PARA: + ret = woal_uap_addba_param(dev, req); + break; + case UAP_AGGR_PRIOTBL: + ret = woal_uap_aggr_priotbl(dev, req); + break; + case UAP_ADDBA_REJECT: + ret = woal_uap_addba_reject(dev, req); + break; + case UAP_FW_INFO: + ret = woal_uap_get_fw_info(dev, req); + break; + case UAP_DEEP_SLEEP: + ret = woal_uap_deep_sleep(dev, req); + break; + case UAP_TX_DATA_PAUSE: + ret = woal_uap_txdatapause(dev, req); + break; + case UAP_SDCMD52_RW: + ret = woal_uap_sdcmd52_rw(dev, req); + break; + case UAP_SNMP_MIB: + ret = woal_uap_snmp_mib(dev, req); + break; + case UAP_DOMAIN_INFO: + ret = woal_uap_domain_info(dev, req); + break; +#ifdef DFS_TESTING_SUPPORT + case UAP_DFS_TESTING: + ret = woal_uap_dfs_testing(dev, req); + break; +#endif + case UAP_TX_BF_CFG: + ret = woal_uap_tx_bf_cfg(dev, req); + break; + case UAP_HS_CFG: + ret = woal_uap_hs_cfg(dev, req, MTRUE); + break; + case UAP_HS_SET_PARA: + ret = woal_uap_hs_set_para(dev, req); + break; + case UAP_MGMT_FRAME_CONTROL: + ret = woal_uap_mgmt_frame_control(dev, req); + break; + case UAP_TX_RATE_CFG: + ret = woal_uap_tx_rate_cfg(dev, req); + break; + case UAP_ANTENNA_CFG: + ret = woal_uap_antenna_cfg(dev, req); + break; + default: + break; + } + done: + LEAVE(); + return ret; +} + +/** + * @brief uap station deauth ioctl handler + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int +woal_uap_sta_deauth_ioctl(struct net_device *dev, struct ifreq *req) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_ioctl_req *ioctl_req = NULL; + mlan_ds_bss *bss = NULL; + mlan_deauth_param deauth_param; + int ret = 0; + + ENTER(); + + memset(&deauth_param, 0, sizeof(mlan_deauth_param)); + /* Sanity check */ + if (req->ifr_data == NULL) { + PRINTM(MERROR, "uap_sta_deauth_ioctl() corrupt data\n"); + ret = -EFAULT; + goto done; + } + if (copy_from_user(&deauth_param, req->ifr_data, sizeof(mlan_deauth_param))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + PRINTM(MIOCTL, + "ioctl deauth station: %02x:%02x:%02x:%02x:%02x:%02x, reason=%d\n", + deauth_param.mac_addr[0], deauth_param.mac_addr[1], + deauth_param.mac_addr[2], deauth_param.mac_addr[3], + deauth_param.mac_addr[4], deauth_param.mac_addr[5], + deauth_param.reason_code); + + ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + if (ioctl_req == NULL) { + ret = -ENOMEM; + goto done; + } + bss = (mlan_ds_bss *) ioctl_req->pbuf; + + bss->sub_command = MLAN_OID_UAP_DEAUTH_STA; + ioctl_req->req_id = MLAN_IOCTL_BSS; + ioctl_req->action = MLAN_ACT_SET; + + memcpy(&bss->param.deauth_param, &deauth_param, sizeof(mlan_deauth_param)); + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + if (copy_to_user(req->ifr_data, &ioctl_req->status_code, sizeof(t_u32))) + PRINTM(MERROR, "Copy to user failed!\n"); + goto done; + } + + done: + if (ioctl_req) + kfree(ioctl_req); + LEAVE(); + return ret; +} + +/** + * @brief Set/Get radio + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_uap_radio_ctl(struct net_device *dev, struct ifreq *req) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + int ret = 0; + mlan_ds_radio_cfg *radio = NULL; + mlan_ioctl_req *mreq = NULL; + int data[2] = { 0, 0 }; + mlan_bss_info bss_info; + + ENTER(); + + /* Sanity check */ + if (req->ifr_data == NULL) { + PRINTM(MERROR, "uap_radio_ctl() corrupt data\n"); + ret = -EFAULT; + goto done; + } + + /* Get user data */ + if (copy_from_user(&data, req->ifr_data, sizeof(data))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + if (data[0]) { + mreq = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg)); + if (mreq == NULL) { + ret = -ENOMEM; + goto done; + } + radio = (mlan_ds_radio_cfg *) mreq->pbuf; + radio->sub_command = MLAN_OID_RADIO_CTRL; + mreq->req_id = MLAN_IOCTL_RADIO_CFG; + mreq->action = MLAN_ACT_SET; + radio->param.radio_on_off = (t_u32) data[1]; + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, mreq, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + } + if (mreq) + kfree(mreq); + } else { + /* Get radio status */ + memset(&bss_info, 0, sizeof(bss_info)); + woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info); + + data[1] = bss_info.radio_on; + if (copy_to_user(req->ifr_data, data, sizeof(data))) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + } + } + done: + LEAVE(); + return ret; +} + +/** + * @brief uap bss control ioctl handler + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int +woal_uap_bss_ctrl_ioctl(struct net_device *dev, struct ifreq *req) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + int ret = 0, data = 0; + + ENTER(); + + /* Sanity check */ + if (req->ifr_data == NULL) { + PRINTM(MERROR, "uap_bss_ctrl() corrupt data\n"); + ret = -EFAULT; + goto done; + } + if (copy_from_user(&data, req->ifr_data, sizeof(data))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, data); + + done: + LEAVE(); + return ret; +} + +/** + * @brief uap power mode ioctl handler + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int +woal_uap_power_mode_ioctl(struct net_device *dev, struct ifreq *req) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_ioctl_req *ioctl_req = NULL; + mlan_ds_pm_cfg *pm_cfg = NULL; + mlan_ds_ps_mgmt ps_mgmt; + int ret = 0; + + ENTER(); + + memset(&ps_mgmt, 0, sizeof(mlan_ds_ps_mgmt)); + + /* Sanity check */ + if (req->ifr_data == NULL) { + PRINTM(MERROR, "uap_power_mode_ioctl() corrupt data\n"); + ret = -EFAULT; + goto done; + } + if (copy_from_user(&ps_mgmt, req->ifr_data, sizeof(mlan_ds_ps_mgmt))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + PRINTM(MIOCTL, + "ioctl power: flag=0x%x ps_mode=%d ctrl_bitmap=%d min_sleep=%d max_sleep=%d " + "inact_to=%d min_awake=%d max_awake=%d\n", ps_mgmt.flags, + (int) ps_mgmt.ps_mode, (int) ps_mgmt.sleep_param.ctrl_bitmap, + (int) ps_mgmt.sleep_param.min_sleep, + (int) ps_mgmt.sleep_param.max_sleep, + (int) ps_mgmt.inact_param.inactivity_to, + (int) ps_mgmt.inact_param.min_awake, + (int) ps_mgmt.inact_param.max_awake); + + if (ps_mgmt. + flags & ~(PS_FLAG_PS_MODE | PS_FLAG_SLEEP_PARAM | + PS_FLAG_INACT_SLEEP_PARAM)) { + PRINTM(MERROR, "Invalid parameter: flags = 0x%x\n", ps_mgmt.flags); + ret = -EINVAL; + goto done; + } + + if (ps_mgmt.ps_mode > PS_MODE_INACTIVITY) { + PRINTM(MERROR, "Invalid parameter: ps_mode = %d\n", + (int) ps_mgmt.flags); + ret = -EINVAL; + goto done; + } + + ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg)); + if (ioctl_req == NULL) { + ret = -ENOMEM; + goto done; + } + pm_cfg = (mlan_ds_pm_cfg *) ioctl_req->pbuf; + pm_cfg->sub_command = MLAN_OID_PM_CFG_PS_MODE; + ioctl_req->req_id = MLAN_IOCTL_PM_CFG; + if (ps_mgmt.flags) { + ioctl_req->action = MLAN_ACT_SET; + memcpy(&pm_cfg->param.ps_mgmt, &ps_mgmt, sizeof(mlan_ds_ps_mgmt)); + } else { + ioctl_req->action = MLAN_ACT_GET; + } + + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + if (copy_to_user(req->ifr_data, &ioctl_req->status_code, sizeof(t_u32))) + PRINTM(MERROR, "Copy to user failed!\n"); + goto done; + } + if (!ps_mgmt.flags) { + /* Copy to user */ + if (copy_to_user + (req->ifr_data, &pm_cfg->param.ps_mgmt, sizeof(mlan_ds_ps_mgmt))) { + PRINTM(MERROR, "Copy to user failed!\n"); + ret = -EFAULT; + goto done; + } + } + done: + if (ioctl_req) + kfree(ioctl_req); + LEAVE(); + return ret; +} + +/** + * @brief uap BSS config ioctl handler + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int +woal_uap_bss_cfg_ioctl(struct net_device *dev, struct ifreq *req) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + int ret = 0; + mlan_ds_bss *bss = NULL; + mlan_ioctl_req *ioctl_req = NULL; + int offset = 0; + t_u32 action = 0; + + ENTER(); + + /* Sanity check */ + if (req->ifr_data == NULL) { + PRINTM(MERROR, "uap_bss_cfg_ioctl() corrupt data\n"); + ret = -EFAULT; + goto done; + } + + /* Get action */ + if (copy_from_user(&action, req->ifr_data + offset, sizeof(action))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + offset += sizeof(action); + + /* Allocate an IOCTL request buffer */ + ioctl_req = + (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + if (ioctl_req == NULL) { + ret = -ENOMEM; + goto done; + } + + bss = (mlan_ds_bss *) ioctl_req->pbuf; + bss->sub_command = MLAN_OID_UAP_BSS_CONFIG; + ioctl_req->req_id = MLAN_IOCTL_BSS; + if (action == 1) { + ioctl_req->action = MLAN_ACT_SET; + } else { + ioctl_req->action = MLAN_ACT_GET; + } + + if (ioctl_req->action == MLAN_ACT_SET) { + /* Get the BSS config from user */ + if (copy_from_user + (&bss->param.bss_config, req->ifr_data + offset, + sizeof(mlan_uap_bss_param))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + } + + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + if (ioctl_req->action == MLAN_ACT_GET) { + offset = sizeof(action); + + /* Copy to user : BSS config */ + if (copy_to_user + (req->ifr_data + offset, &bss->param.bss_config, + sizeof(mlan_uap_bss_param))) { + PRINTM(MERROR, "Copy to user failed!\n"); + ret = -EFAULT; + goto done; + } + } + done: + if (ioctl_req) + kfree(ioctl_req); + LEAVE(); + return ret; +} + +/** + * @brief uap get station list handler + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int +woal_uap_get_sta_list_ioctl(struct net_device *dev, struct ifreq *req) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + int ret = 0; + mlan_ds_get_info *info = NULL; + mlan_ioctl_req *ioctl_req = NULL; + + ENTER(); + + /* Sanity check */ + if (req->ifr_data == NULL) { + PRINTM(MERROR, "uap_get_sta_list_ioctl() corrupt data\n"); + ret = -EFAULT; + goto done; + } + + /* Allocate an IOCTL request buffer */ + ioctl_req = + (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info)); + if (ioctl_req == NULL) { + ret = -ENOMEM; + goto done; + } + + info = (mlan_ds_get_info *) ioctl_req->pbuf; + info->sub_command = MLAN_OID_UAP_STA_LIST; + ioctl_req->req_id = MLAN_IOCTL_GET_INFO; + ioctl_req->action = MLAN_ACT_GET; + + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + if (ioctl_req->action == MLAN_ACT_GET) { + /* Copy to user : sta_list */ + if (copy_to_user + (req->ifr_data, &info->param.sta_list, sizeof(mlan_ds_sta_list))) { + PRINTM(MERROR, "Copy to user failed!\n"); + ret = -EFAULT; + goto done; + } + } + done: + if (ioctl_req) + kfree(ioctl_req); + LEAVE(); + return ret; +} + +/** + * @brief uAP set WAPI key ioctl + * + * @param priv A pointer to moal_private structure + * @param msg A pointer to wapi_msg structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_uap_set_wapi_key_ioctl(moal_private * priv, wapi_msg * msg) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_sec_cfg *sec = NULL; + int ret = 0; + wapi_key_msg *key_msg = NULL; + t_u8 bcast_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + ENTER(); + if (msg->msg_len != sizeof(wapi_key_msg)) { + ret = -EINVAL; + goto done; + } + key_msg = (wapi_key_msg *) msg->msg; + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + sec = (mlan_ds_sec_cfg *) req->pbuf; + sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY; + req->req_id = MLAN_IOCTL_SEC_CFG; + req->action = MLAN_ACT_SET; + + sec->param.encrypt_key.is_wapi_key = MTRUE; + sec->param.encrypt_key.key_len = MLAN_MAX_KEY_LENGTH; + memcpy(sec->param.encrypt_key.mac_addr, key_msg->mac_addr, ETH_ALEN); + sec->param.encrypt_key.key_index = key_msg->key_id; + if (0 == memcmp(key_msg->mac_addr, bcast_addr, ETH_ALEN)) + sec->param.encrypt_key.key_flags = KEY_FLAG_GROUP_KEY; + else + sec->param.encrypt_key.key_flags = KEY_FLAG_SET_TX_KEY; + memcpy(sec->param.encrypt_key.key_material, key_msg->key, + sec->param.encrypt_key.key_len); + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) + ret = -EFAULT; + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Enable/Disable wapi in firmware + * + * @param priv A pointer to moal_private structure + * @param enable MTRUE/MFALSE + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +static mlan_status +woal_enable_wapi(moal_private * priv, t_u8 enable) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_bss *bss = NULL; + mlan_status status; + + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + if (req == NULL) { + status = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill request buffer */ + bss = (mlan_ds_bss *) req->pbuf; + bss->sub_command = MLAN_OID_UAP_BSS_CONFIG; + req->req_id = MLAN_IOCTL_BSS; + req->action = MLAN_ACT_GET; + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); + if (status != MLAN_STATUS_SUCCESS) { + PRINTM(MERROR, "Get AP setting failed! status=%d, error_code=0x%x\n", + status, req->status_code); + } + + /* Change AP default setting */ + req->action = MLAN_ACT_SET; + if (enable == MFALSE) { + bss->param.bss_config.auth_mode = MLAN_AUTH_MODE_OPEN; + bss->param.bss_config.protocol = PROTOCOL_NO_SECURITY; + } else { + bss->param.bss_config.auth_mode = MLAN_AUTH_MODE_OPEN; + bss->param.bss_config.protocol = PROTOCOL_WAPI; + } + + /* Send IOCTL request to MLAN */ + status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); + if (status != MLAN_STATUS_SUCCESS) { + PRINTM(MERROR, "Set AP setting failed! status=%d, error_code=0x%x\n", + status, req->status_code); + } + if (enable) + woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START); + done: + if (req) + kfree(req); + LEAVE(); + return status; +} + +/** + * @brief uAP set WAPI flag ioctl + * + * @param priv A pointer to moal_private structure + * @param msg A pointer to wapi_msg structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_uap_set_wapi_flag_ioctl(moal_private * priv, wapi_msg * msg) +{ + t_u8 wapi_psk_ie[] = + { 0x44, 0x14, 0x01, 0x00, 0x01, 0x00, 0x00, 0x14, 0x72, 0x02, + 0x01, 0x00, 0x00, 0x14, 0x72, 0x01, 0x00, 0x14, 0x72, 0x01, + 0x00, 0x00 + }; + t_u8 wapi_cert_ie[] = + { 0x44, 0x14, 0x01, 0x00, 0x01, 0x00, 0x00, 0x14, 0x72, 0x01, + 0x01, 0x00, 0x00, 0x14, 0x72, 0x01, 0x00, 0x14, 0x72, 0x01, + 0x00, 0x00 + }; + mlan_ds_misc_cfg *misc = NULL; + mlan_ioctl_req *req = NULL; + int ret = 0; + + ENTER(); + + woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + misc = (mlan_ds_misc_cfg *) req->pbuf; + misc->sub_command = MLAN_OID_MISC_GEN_IE; + req->req_id = MLAN_IOCTL_MISC_CFG; + req->action = MLAN_ACT_SET; + + misc->param.gen_ie.type = MLAN_IE_TYPE_GEN_IE; + misc->param.gen_ie.len = sizeof(wapi_psk_ie); + if (msg->msg[0] & WAPI_MODE_PSK) { + memcpy(misc->param.gen_ie.ie_data, wapi_psk_ie, misc->param.gen_ie.len); + } else if (msg->msg[0] & WAPI_MODE_CERT) { + memcpy(misc->param.gen_ie.ie_data, wapi_cert_ie, + misc->param.gen_ie.len); + } else if (msg->msg[0] == 0) { + /* disable WAPI in driver */ + if (MLAN_STATUS_SUCCESS != + woal_set_wapi_enable(priv, MOAL_IOCTL_WAIT, 0)) + ret = -EFAULT; + woal_enable_wapi(priv, MFALSE); + goto done; + } else { + ret = -EINVAL; + goto done; + } + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + woal_enable_wapi(priv, MTRUE); + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief set wapi ioctl function + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @return 0 --success, otherwise fail + */ +static int +woal_uap_set_wapi(struct net_device *dev, struct ifreq *req) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + wapi_msg msg; + int ret = 0; + + ENTER(); + + /* Sanity check */ + if (req->ifr_data == NULL) { + PRINTM(MERROR, "uap_set_wapi() corrupt data\n"); + ret = -EFAULT; + goto done; + } + + memset(&msg, 0, sizeof(msg)); + + if (copy_from_user(&msg, req->ifr_data, sizeof(msg))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + + PRINTM(MIOCTL, "set wapi msg_type = %d, msg_len=%d\n", msg.msg_type, + msg.msg_len); + DBG_HEXDUMP(MCMD_D, "wapi msg", msg.msg, MIN(msg.msg_len, sizeof(msg.msg))); + + switch (msg.msg_type) { + case P80211_PACKET_WAPIFLAG: + ret = woal_uap_set_wapi_flag_ioctl(priv, &msg); + break; + case P80211_PACKET_SETKEY: + ret = woal_uap_set_wapi_key_ioctl(priv, &msg); + break; + default: + ret = -EOPNOTSUPP; + break; + } + done: + LEAVE(); + return ret; +} + +/******************************************************** + Global Functions +********************************************************/ +/** + * @brief Initialize the members of mlan_uap_bss_param + * which are uploaded from firmware + * + * @param priv A pointer to moal_private structure + * @param sys_cfg A pointer to mlan_uap_bss_param structure + * @param wait_option Wait option + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +woal_uap_get_bss_param(moal_private * priv, mlan_uap_bss_param * sys_cfg, + t_u8 wait_option) +{ + mlan_ds_bss *info = NULL; + mlan_ioctl_req *req = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + if (req == NULL) { + LEAVE(); + return MLAN_STATUS_FAILURE; + } + + info = (mlan_ds_bss *) req->pbuf; + info->sub_command = MLAN_OID_UAP_BSS_CONFIG; + req->req_id = MLAN_IOCTL_BSS; + req->action = MLAN_ACT_GET; + + status = woal_request_ioctl(priv, req, wait_option); + if (status != MLAN_STATUS_SUCCESS) { + PRINTM(MERROR, "Get bss info failed!\n"); + status = MLAN_STATUS_FAILURE; + goto done; + } + memcpy(sys_cfg, &info->param.bss_config, sizeof(mlan_uap_bss_param)); + + done: + if (req && (status != MLAN_STATUS_PENDING)) + kfree(req); + + LEAVE(); + return status; +} + +/** + * @brief Set 11n status based on the configured security mode + * + * @param sys_cfg A pointer to mlan_uap_bss_param structure + * @param action MLAN_ACT_DISABLE or MLAN_ACT_ENABLE + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +woal_uap_set_11n_status(mlan_uap_bss_param * sys_cfg, t_u8 action) +{ + mlan_status status = MLAN_STATUS_SUCCESS; + + ENTER(); + if (action == MLAN_ACT_DISABLE) { + if ((sys_cfg->supported_mcs_set[0] == 0) + && (sys_cfg->supported_mcs_set[4] == 0) + && (sys_cfg->supported_mcs_set[1] == 0) + ) { + goto done; + } else { + sys_cfg->supported_mcs_set[0] = 0; + sys_cfg->supported_mcs_set[4] = 0; + sys_cfg->supported_mcs_set[1] = 0; + } + } + + if (action == MLAN_ACT_ENABLE) { + if ((sys_cfg->supported_mcs_set[0] != 0) + || (sys_cfg->supported_mcs_set[4] != 0) + || (sys_cfg->supported_mcs_set[1] != 0) + ) { + goto done; + } else { + sys_cfg->supported_mcs_set[0] = 0xFF; + sys_cfg->supported_mcs_set[4] = 0x01; + sys_cfg->supported_mcs_set[1] = 0xFF; + } + } + + done: + LEAVE(); + return status; +} + +/** + * @brief Parse AP configuration from ASCII string + * + * @param ap_cfg A pointer to mlan_uap_bss_param structure + * @param buf A pointer to user data + * + * @return 0 --success, otherwise fail + */ +int +woal_uap_ap_cfg_parse_data(mlan_uap_bss_param * ap_cfg, t_s8 * buf) +{ + int ret = 0, atoi_ret; + int set_sec = 0, set_key = 0, set_chan = 0; + int set_preamble = 0, set_scb = 0, set_ssid = 0; + t_s8 *begin = buf, *value = NULL, *opt = NULL; + + ENTER(); + + while (begin) { + value = woal_strsep(&begin, ',', '/'); + opt = woal_strsep(&value, '=', '/'); + if (opt && !strncmp(opt, "END", strlen("END"))) { + if (!ap_cfg->ssid.ssid_len) { + PRINTM(MERROR, "Minimum option required is SSID\n"); + ret = -EINVAL; + goto done; + } + PRINTM(MINFO, "Parsing terminated by string END\n"); + break; + } + if (!opt || !value || !value[0]) { + PRINTM(MERROR, "Invalid option\n"); + ret = -EINVAL; + goto done; + } else if (!strncmp(opt, "ASCII_CMD", strlen("ASCII_CMD"))) { + if (strncmp(value, "AP_CFG", strlen("AP_CFG"))) { + PRINTM(MERROR, "ASCII_CMD: %s not matched with AP_CFG\n", + value); + ret = -EFAULT; + goto done; + } + value = woal_strsep(&begin, ',', '/'); + opt = woal_strsep(&value, '=', '/'); + if (!opt || !value || !value[0]) { + PRINTM(MERROR, "Minimum option required is SSID\n"); + ret = -EINVAL; + goto done; + } else if (!strncmp(opt, "SSID", strlen("SSID"))) { + if (set_ssid) { + PRINTM(MWARN, "Skipping SSID, found again!\n"); + continue; + } + if (strlen(value) > MLAN_MAX_SSID_LENGTH) { + PRINTM(MERROR, "SSID length exceeds max length\n"); + ret = -EFAULT; + goto done; + } + ap_cfg->ssid.ssid_len = strlen(value); + strncpy((char *) ap_cfg->ssid.ssid, value, strlen(value)); + PRINTM(MINFO, "ssid=%s, len=%d\n", ap_cfg->ssid.ssid, + (int) ap_cfg->ssid.ssid_len); + set_ssid = 1; + } else { + PRINTM(MERROR, "AP_CFG: Invalid option %s, " + "expect SSID\n", opt); + ret = -EINVAL; + goto done; + } + } else if (!strncmp(opt, "SEC", strlen("SEC"))) { + if (set_sec) { + PRINTM(MWARN, "Skipping SEC, found again!\n"); + continue; + } + if (!strnicmp(value, "open", strlen("open"))) { + ap_cfg->auth_mode = MLAN_AUTH_MODE_OPEN; + if (set_key) + ap_cfg->wpa_cfg.length = 0; + ap_cfg->key_mgmt = KEY_MGMT_NONE; + ap_cfg->protocol = PROTOCOL_NO_SECURITY; + } else if (!strnicmp(value, "wpa2-psk", strlen("wpa2-psk"))) { + ap_cfg->auth_mode = MLAN_AUTH_MODE_OPEN; + ap_cfg->protocol = PROTOCOL_WPA2; + ap_cfg->key_mgmt = KEY_MGMT_PSK; + ap_cfg->wpa_cfg.pairwise_cipher_wpa = CIPHER_AES_CCMP; + ap_cfg->wpa_cfg.pairwise_cipher_wpa2 = CIPHER_AES_CCMP; + ap_cfg->wpa_cfg.group_cipher = CIPHER_AES_CCMP; + } else if (!strnicmp(value, "wpa-psk", strlen("wpa-psk"))) { + ap_cfg->auth_mode = MLAN_AUTH_MODE_OPEN; + ap_cfg->protocol = PROTOCOL_WPA; + ap_cfg->key_mgmt = KEY_MGMT_PSK; + ap_cfg->wpa_cfg.pairwise_cipher_wpa = CIPHER_TKIP; + ap_cfg->wpa_cfg.group_cipher = CIPHER_TKIP; + } else if (!strnicmp(value, "wep128", strlen("wep128"))) { + ap_cfg->auth_mode = MLAN_AUTH_MODE_OPEN; + if (set_key) + ap_cfg->wpa_cfg.length = 0; + ap_cfg->key_mgmt = KEY_MGMT_NONE; + ap_cfg->protocol = PROTOCOL_STATIC_WEP; + } else { + PRINTM(MERROR, "AP_CFG: Invalid value=%s for %s\n", value, opt); + ret = -EFAULT; + goto done; + } + set_sec = 1; + } else if (!strncmp(opt, "KEY", strlen("KEY"))) { + if (set_key) { + PRINTM(MWARN, "Skipping KEY, found again!\n"); + continue; + } + if (set_sec && ap_cfg->protocol == PROTOCOL_STATIC_WEP) { + if (strlen(value) != MAX_WEP_KEY_SIZE) { + PRINTM(MERROR, "Invalid WEP KEY length\n"); + ret = -EFAULT; + goto done; + } + ap_cfg->wep_cfg.key0.key_index = 0; + ap_cfg->wep_cfg.key0.is_default = 1; + ap_cfg->wep_cfg.key0.length = strlen(value); + memcpy(ap_cfg->wep_cfg.key0.key, value, strlen(value)); + set_key = 1; + continue; + } + if (set_sec && ap_cfg->protocol != PROTOCOL_WPA2 + && ap_cfg->protocol != PROTOCOL_WPA) { + PRINTM(MWARN, "Warning! No KEY for open mode\n"); + set_key = 1; + continue; + } + if (strlen(value) < MLAN_MIN_PASSPHRASE_LENGTH || + strlen(value) > MLAN_PMK_HEXSTR_LENGTH) { + PRINTM(MERROR, "Invalid PSK/PMK length\n"); + ret = -EINVAL; + goto done; + } + ap_cfg->wpa_cfg.length = strlen(value); + memcpy(ap_cfg->wpa_cfg.passphrase, value, strlen(value)); + set_key = 1; + } else if (!strncmp(opt, "CHANNEL", strlen("CHANNEL"))) { + if (set_chan) { + PRINTM(MWARN, "Skipping CHANNEL, found again!\n"); + continue; + } + if (woal_atoi(&atoi_ret, value)) { + ret = -EINVAL; + goto done; + } + if (atoi_ret < 1 || atoi_ret > MLAN_MAX_CHANNEL) { + PRINTM(MERROR, "AP_CFG: Channel must be between 1 and %d" + "(both included)\n", MLAN_MAX_CHANNEL); + ret = -EINVAL; + goto done; + } + ap_cfg->channel = atoi_ret; + set_chan = 1; + } else if (!strncmp(opt, "PREAMBLE", strlen("PREAMBLE"))) { + if (set_preamble) { + PRINTM(MWARN, "Skipping PREAMBLE, found again!\n"); + continue; + } + if (woal_atoi(&atoi_ret, value)) { + ret = -EINVAL; + goto done; + } + /* This is a READ only value from FW, so we can not set this and + pass it successfully */ + set_preamble = 1; + } else if (!strncmp(opt, "MAX_SCB", strlen("MAX_SCB"))) { + if (set_scb) { + PRINTM(MWARN, "Skipping MAX_SCB, found again!\n"); + continue; + } + if (woal_atoi(&atoi_ret, value)) { + ret = -EINVAL; + goto done; + } + if (atoi_ret < 1 || atoi_ret > MAX_STA_COUNT) { + PRINTM(MERROR, "AP_CFG: MAX_SCB must be between 1 to %d " + "(both included)\n", MAX_STA_COUNT); + ret = -EINVAL; + goto done; + } + ap_cfg->max_sta_count = (t_u16) atoi_ret; + set_scb = 1; + } else { + PRINTM(MERROR, "Invalid option %s\n", opt); + ret = -EINVAL; + goto done; + } + } + + done: + LEAVE(); + return ret; +} + +/** + * @brief Set AP configuration + * + * @param priv A pointer to moal_private structure + * @param data A pointer to user data + * @param len Length of buf + * + * @return 0 --success, otherwise fail + */ +int +woal_uap_set_ap_cfg(moal_private * priv, t_u8 * data, int len) +{ + int ret = 0; + static t_s8 buf[MAX_BUF_LEN]; + mlan_uap_bss_param sys_config; + int restart = 0; + + ENTER(); + +#define MIN_AP_CFG_CMD_LEN 16 /* strlen("ASCII_CMD=AP_CFG") */ + if ((len - 1) <= MIN_AP_CFG_CMD_LEN) { + PRINTM(MERROR, "Invalid length of command\n"); + ret = -EINVAL; + goto done; + } + + memset(buf, 0, MAX_BUF_LEN); + memcpy(buf, data, len); + + /* Initialize the uap bss values which are uploaded from firmware */ + woal_uap_get_bss_param(priv, &sys_config, MOAL_IOCTL_WAIT); + + /* Setting the default values */ + sys_config.channel = 6; + sys_config.preamble_type = 0; + + if ((ret = woal_uap_ap_cfg_parse_data(&sys_config, buf))) + goto done; + + /* If BSS already started stop it first and restart after changing the + setting */ + if (priv->bss_started == MTRUE) { + if ((ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP))) + goto done; + restart = 1; + } + + /* If the security mode is configured as WEP or WPA-PSK, it will disable + 11n automatically, and if configured as open(off) or wpa2-psk, it will + automatically enable 11n */ + if ((sys_config.protocol == PROTOCOL_STATIC_WEP) || + (sys_config.protocol == PROTOCOL_WPA)) { + if (MLAN_STATUS_SUCCESS != + woal_uap_set_11n_status(&sys_config, MLAN_ACT_DISABLE)) { + ret = -EFAULT; + goto done; + } + } else { + if (MLAN_STATUS_SUCCESS != + woal_uap_set_11n_status(&sys_config, MLAN_ACT_ENABLE)) { + ret = -EFAULT; + goto done; + } + } + + if (MLAN_STATUS_SUCCESS != + woal_set_get_sys_config(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, + &sys_config)) { + ret = -EFAULT; + goto done; + } + + /* Start the BSS after successful configuration */ + if (restart) + ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START); + + done: + LEAVE(); + return ret; +} + +/** + * @brief uap BSS control ioctl handler + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * @param data BSS control type + * @return 0 --success, otherwise fail + */ +int +woal_uap_bss_ctrl(moal_private * priv, t_u8 wait_option, int data) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_bss *bss = NULL; + int ret = 0; + + ENTER(); + + PRINTM(MIOCTL, "ioctl bss ctrl=%d\n", data); + if ((data != UAP_BSS_START) && (data != UAP_BSS_STOP) && + (data != UAP_BSS_RESET)) { + PRINTM(MERROR, "Invalid parameter: %d\n", data); + ret = -EINVAL; + goto done; + } + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + bss = (mlan_ds_bss *) req->pbuf; + switch (data) { + case UAP_BSS_START: + if (priv->bss_started == MTRUE) { + PRINTM(MWARN, "Warning: BSS already started!\n"); + // goto done; + } else { + /* about to start bss: issue channel check */ + woal_11h_channel_check_ioctl(priv); + } + bss->sub_command = MLAN_OID_BSS_START; + break; + case UAP_BSS_STOP: + if (priv->bss_started == MFALSE) { + PRINTM(MWARN, "Warning: BSS already stopped!\n"); + // goto done; + } + bss->sub_command = MLAN_OID_BSS_STOP; + break; + case UAP_BSS_RESET: + bss->sub_command = MLAN_OID_UAP_BSS_RESET; + woal_cancel_cac_block(priv); + break; + } + req->req_id = MLAN_IOCTL_BSS; + req->action = MLAN_ACT_SET; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + if (data == UAP_BSS_STOP || data == UAP_BSS_RESET) + priv->bss_started = MFALSE; + + done: + if (req) + kfree(req); + + LEAVE(); + return ret; +} + +/** + * @brief This function sets multicast addresses to firmware + * + * @param dev A pointer to net_device structure + * @return N/A + */ +void +woal_uap_set_multicast_list(struct net_device *dev) +{ + ENTER(); + + LEAVE(); +} + +/** + * @brief ioctl function - entry point + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @param cmd Command + * + * @return 0 --success, otherwise fail + */ +int +woal_uap_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd) +{ + int ret = 0; + ENTER(); + PRINTM(MIOCTL, "uap_do_ioctl: ioctl cmd = 0x%x\n", cmd); + switch (cmd) { + case UAP_HOSTCMD: + ret = woal_hostcmd_ioctl(dev, req); + break; + case UAP_IOCTL_CMD: + ret = woal_uap_ioctl(dev, req); + break; + case UAP_POWER_MODE: + ret = woal_uap_power_mode_ioctl(dev, req); + break; + case UAP_BSS_CTRL: + ret = woal_uap_bss_ctrl_ioctl(dev, req); + break; + case UAP_WAPI_MSG: + ret = woal_uap_set_wapi(dev, req); + break; + case UAP_BSS_CONFIG: + ret = woal_uap_bss_cfg_ioctl(dev, req); + break; + case UAP_STA_DEAUTH: + ret = woal_uap_sta_deauth_ioctl(dev, req); + break; + case UAP_RADIO_CTL: + ret = woal_uap_radio_ctl(dev, req); + break; + case UAP_GET_STA_LIST: + ret = woal_uap_get_sta_list_ioctl(dev, req); + break; + case UAP_CUSTOM_IE: + ret = woal_custom_ie_ioctl(dev, req); + break; + case UAP_GET_BSS_TYPE: + ret = woal_get_bss_type(dev, req); + break; + case WOAL_ANDROID_PRIV_CMD: + ret = woal_android_priv_cmd(dev, req); + break; + default: +#ifdef UAP_WEXT + ret = woal_uap_do_priv_ioctl(dev, req, cmd); +#else + ret = -EOPNOTSUPP; +#endif + break; + } + + LEAVE(); + return ret; +} + +/** + * @brief Get version + * + * @param priv A pointer to moal_private structure + * @param version A pointer to version buffer + * @param max_len max length of version buffer + * + * @return N/A + */ +void +woal_uap_get_version(moal_private * priv, char *version, int max_len) +{ + mlan_ds_get_info *info = NULL; + mlan_ioctl_req *req = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info)); + if (req == NULL) { + LEAVE(); + return; + } + + info = (mlan_ds_get_info *) req->pbuf; + info->sub_command = MLAN_OID_GET_VER_EXT; + req->req_id = MLAN_IOCTL_GET_INFO; + req->action = MLAN_ACT_GET; + + status = woal_request_ioctl(priv, req, MOAL_PROC_WAIT); + if (status == MLAN_STATUS_SUCCESS) { + PRINTM(MINFO, "MOAL UAP VERSION: %s\n", + info->param.ver_ext.version_str); + snprintf(version, max_len, driver_version, + info->param.ver_ext.version_str); + } + + if (req && (status != MLAN_STATUS_PENDING)) + kfree(req); + + LEAVE(); + return; +} + +/** + * @brief Get uap statistics + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * @param ustats A pointer to mlan_ds_uap_stats structure + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +mlan_status +woal_uap_get_stats(moal_private * priv, t_u8 wait_option, + mlan_ds_uap_stats * ustats) +{ + mlan_ds_get_info *info = NULL; + mlan_ioctl_req *req = NULL; + mlan_status status = MLAN_STATUS_SUCCESS; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info)); + if (req == NULL) { + LEAVE(); + return MLAN_STATUS_FAILURE; + } + + info = (mlan_ds_get_info *) req->pbuf; + info->sub_command = MLAN_OID_GET_STATS; + req->req_id = MLAN_IOCTL_GET_INFO; + req->action = MLAN_ACT_GET; + + status = woal_request_ioctl(priv, req, wait_option); + if (status == MLAN_STATUS_SUCCESS) { + if (ustats) + memcpy(ustats, &info->param.ustats, sizeof(mlan_ds_uap_stats)); +#ifdef UAP_WEXT + priv->w_stats.discard.fragment = info->param.ustats.fcs_error_count; + priv->w_stats.discard.retries = info->param.ustats.retry_count; + priv->w_stats.discard.misc = info->param.ustats.ack_failure_count; +#endif + } + + if (req && (status != MLAN_STATUS_PENDING)) + kfree(req); + + LEAVE(); + return status; +} + +/** + * @brief Set/Get system configuration parameters + * + * @param priv A pointer to moal_private structure + * @param action MLAN_ACT_SET or MLAN_ACT_GET + * @param wait_option Wait option + * @param sys_cfg A pointer to mlan_uap_bss_param structure + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +woal_set_get_sys_config(moal_private * priv, t_u16 action, t_u8 wait_option, + mlan_uap_bss_param * sys_cfg) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_ds_bss *bss = NULL; + mlan_ioctl_req *req = NULL; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + if (req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + bss = (mlan_ds_bss *) req->pbuf; + bss->sub_command = MLAN_OID_UAP_BSS_CONFIG; + req->req_id = MLAN_IOCTL_BSS; + req->action = action; + + if (action == MLAN_ACT_SET) { + memcpy(&bss->param.bss_config, sys_cfg, sizeof(mlan_uap_bss_param)); + } + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, wait_option)) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + if (action == MLAN_ACT_GET) { + memcpy(sys_cfg, &bss->param.bss_config, sizeof(mlan_uap_bss_param)); + } + + done: + if (req) + kfree(req); + + LEAVE(); + return ret; +} + +/** + * @brief Set invalid data for each member of mlan_uap_bss_param + * structure + * + * @param config A pointer to mlan_uap_bss_param structure + * + * @return N/A + */ +void +woal_set_sys_config_invalid_data(mlan_uap_bss_param * config) +{ + ENTER(); + + memset(config, 0, sizeof(mlan_uap_bss_param)); + config->bcast_ssid_ctl = 0x7F; + config->radio_ctl = 0x7F; + config->dtim_period = 0x7F; + config->beacon_period = 0x7FFF; + config->tx_data_rate = 0x7FFF; + config->mcbc_data_rate = 0x7FFF; + config->tx_power_level = 0x7F; + config->tx_antenna = 0x7F; + config->rx_antenna = 0x7F; + config->pkt_forward_ctl = 0x7F; + config->max_sta_count = 0x7FFF; + config->auth_mode = 0x7F; + config->sta_ageout_timer = 0x7FFFFFFF; + config->pairwise_update_timeout = 0x7FFFFFFF; + config->pwk_retries = 0x7FFFFFFF; + config->groupwise_update_timeout = 0x7FFFFFFF; + config->gwk_retries = 0x7FFFFFFF; + config->mgmt_ie_passthru_mask = 0x7FFFFFFF; + config->ps_sta_ageout_timer = 0x7FFFFFFF; + config->rts_threshold = 0x7FFF; + config->frag_threshold = 0x7FFF; + config->retry_limit = 0x7FFF; + config->filter.filter_mode = 0x7FFF; + config->filter.mac_count = 0x7FFF; + config->wpa_cfg.rsn_protection = 0x7F; + config->wpa_cfg.gk_rekey_time = 0x7FFFFFFF; + config->enable_2040coex = 0x7F; + config->wmm_para.qos_info = 0x7F; + + LEAVE(); +} diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap.h b/drivers/net/wireless/sd8797/mlinux/moal_uap.h new file mode 100644 index 000000000000..a30d0ceec87f --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/moal_uap.h @@ -0,0 +1,410 @@ +/** @file moal_uap.h + * + * @brief This file contains uap driver specific defines etc. + * + * Copyright (C) 2009-2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +/******************************************************** +Change log: + 02/02/2009: initial version +********************************************************/ + +#ifndef _MOAL_UAP_H +#define _MOAL_UAP_H + +/** Maximum buffer length for WOAL_UAP_SET_GET_256_CHAR */ +#define MAX_BUF_LEN 256 + +/** Private command ID to Host command */ +#define UAP_HOSTCMD (SIOCDEVPRIVATE + 1) +/** Private command ID to send ioctl */ +#define UAP_IOCTL_CMD (SIOCDEVPRIVATE + 2) +/** Updating ADDBA variables */ +#define UAP_ADDBA_PARA 0 +/** Updating priority table for AMPDU/AMSDU */ +#define UAP_AGGR_PRIOTBL 1 +/** Updating addbareject table */ +#define UAP_ADDBA_REJECT 2 +/** Get FW INFO */ +#define UAP_FW_INFO 4 +/** Updating Deep sleep variables */ +#define UAP_DEEP_SLEEP 3 +/** Tx data pause subcommand */ +#define UAP_TX_DATA_PAUSE 5 +/** sdcmd52 read write subcommand */ +#define UAP_SDCMD52_RW 6 +/** snmp mib subcommand */ +#define UAP_SNMP_MIB 7 +/** domain info subcommand */ +#define UAP_DOMAIN_INFO 8 +/** TX beamforming configuration */ +#define UAP_TX_BF_CFG 9 +#ifdef DFS_TESTING_SUPPORT +/** dfs testing subcommand */ +#define UAP_DFS_TESTING 10 +#endif +/** sub command ID to set/get Host Sleep configuration */ +#define UAP_HS_CFG 11 +/** sub command ID to set/get Host Sleep Parameters */ +#define UAP_HS_SET_PARA 12 + +/** Management Frame Control Mask */ +#define UAP_MGMT_FRAME_CONTROL 13 + +#define UAP_TX_RATE_CFG 14 + +/** Subcommand ID to set/get antenna configuration */ +#define UAP_ANTENNA_CFG 15 + +/** Private command ID to Power Mode */ +#define UAP_POWER_MODE (SIOCDEVPRIVATE + 3) + +/** Private command id to start/stop/reset bss */ +#define UAP_BSS_CTRL (SIOCDEVPRIVATE + 4) +/** BSS START */ +#define UAP_BSS_START 0 +/** BSS STOP */ +#define UAP_BSS_STOP 1 +/** BSS RESET */ +#define UAP_BSS_RESET 2 +/** Band config 5GHz */ +#define BAND_CONFIG_5GHZ 0x01 + +/** wapi_msg */ +typedef struct _wapi_msg +{ + /** message type */ + t_u16 msg_type; + /** message len */ + t_u16 msg_len; + /** message */ + t_u8 msg[96]; +} wapi_msg; + +/* wapi key msg */ +typedef struct _wapi_key_msg +{ + /** mac address */ + t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH]; + /** pad */ + t_u8 pad; + /** key id */ + t_u8 key_id; + /** key */ + t_u8 key[32]; +} wapi_key_msg; + +typedef struct _tx_rate_cfg_t +{ + /** sub command */ + int subcmd; + /** Action */ + int action; + /** Rate configured */ + int rate; + /** Rate bitmap */ + t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE]; +} tx_rate_cfg_t; + +/** ant_cfg structure */ +typedef struct _ant_cfg_t +{ + /** Subcommand */ + int subcmd; + /** Action */ + int action; + /** TX mode configured */ + int tx_mode; + /** RX mode configured */ + int rx_mode; +} ant_cfg_t; + +/** Private command ID to set wapi info */ +#define UAP_WAPI_MSG (SIOCDEVPRIVATE + 10) +/** set wapi flag */ +#define P80211_PACKET_WAPIFLAG 0x0001 +/** set wapi key */ +#define P80211_PACKET_SETKEY 0x0003 +/** wapi mode psk */ +#define WAPI_MODE_PSK 0x04 +/** wapi mode certificate */ +#define WAPI_MODE_CERT 0x08 + +/** radio control command */ +#define UAP_RADIO_CTL (SIOCDEVPRIVATE + 5) + +/** Private command ID to BSS config */ +#define UAP_BSS_CONFIG (SIOCDEVPRIVATE + 6) + +/** deauth station */ +#define UAP_STA_DEAUTH (SIOCDEVPRIVATE + 7) + +/** uap get station list */ +#define UAP_GET_STA_LIST (SIOCDEVPRIVATE + 11) + +/** Private command ID to set/get custom IE buffer */ +#define UAP_CUSTOM_IE (SIOCDEVPRIVATE + 13) + +/** HS WAKE UP event id */ +#define UAP_EVENT_ID_HS_WAKEUP 0x80000001 +/** HS_ACTIVATED event id */ +#define UAP_EVENT_ID_DRV_HS_ACTIVATED 0x80000002 +/** HS DEACTIVATED event id */ +#define UAP_EVENT_ID_DRV_HS_DEACTIVATED 0x80000003 + +/** Host sleep flag set */ +#define HS_CFG_FLAG_GET 0 +/** Host sleep flag get */ +#define HS_CFG_FLAG_SET 1 +/** Host sleep flag for condition */ +#define HS_CFG_FLAG_CONDITION 2 +/** Host sleep flag for GPIO */ +#define HS_CFG_FLAG_GPIO 4 +/** Host sleep flag for Gap */ +#define HS_CFG_FLAG_GAP 8 +/** Host sleep flag for all */ +#define HS_CFG_FLAG_ALL 0x0f +/** Host sleep mask to get condition */ +#define HS_CFG_CONDITION_MASK 0x0f + +/** ds_hs_cfg */ +typedef struct _ds_hs_cfg +{ + /** subcmd */ + t_u32 subcmd; + /** Bit0: 0 - Get, 1 Set + * Bit1: 1 - conditions is valid + * Bit2: 2 - gpio is valid + * Bit3: 3 - gap is valid + */ + t_u32 flags; + /** Host sleep config condition */ + /** Bit0: non-unicast data + * Bit1: unicast data + * Bit2: mac events + * Bit3: magic packet + */ + t_u32 conditions; + /** GPIO */ + t_u32 gpio; + /** Gap in milliseconds */ + t_u32 gap; +} ds_hs_cfg; + +/** Private command ID to get BSS type */ +#define UAP_GET_BSS_TYPE (SIOCDEVPRIVATE + 15) + +/** addba_param */ +typedef struct _addba_param +{ + /** subcmd */ + t_u32 subcmd; + /** Set/Get */ + t_u32 action; + /** block ack timeout for ADDBA request */ + t_u32 timeout; + /** Buffer size for ADDBA request */ + t_u32 txwinsize; + /** Buffer size for ADDBA response */ + t_u32 rxwinsize; + /** amsdu for ADDBA request */ + t_u8 txamsdu; + /** amsdu for ADDBA response */ + t_u8 rxamsdu; +} addba_param; + +/** aggr_prio_tbl */ +typedef struct _aggr_prio_tbl +{ + /** subcmd */ + t_u32 subcmd; + /** Set/Get */ + t_u32 action; + /** ampdu priority table */ + t_u8 ampdu[MAX_NUM_TID]; + /** amsdu priority table */ + t_u8 amsdu[MAX_NUM_TID]; +} aggr_prio_tbl; + +/** addba_reject parameters */ +typedef struct _addba_reject_para +{ + /** subcmd */ + t_u32 subcmd; + /** Set/Get */ + t_u32 action; + /** BA Reject paramters */ + t_u8 addba_reject[MAX_NUM_TID]; +} addba_reject_para; + +/** fw_info */ +typedef struct _fw_info +{ + /** subcmd */ + t_u32 subcmd; + /** Get */ + t_u32 action; + /** Firmware release number */ + t_u32 fw_release_number; + /** Device support for MIMO abstraction of MCSs */ + t_u8 hw_dev_mcs_support; +} fw_info; + +typedef struct _tx_bf_cfg_para_hdr +{ + /** Sub command */ + t_u32 subcmd; + /** Action: Set/Get */ + t_u32 action; +} tx_bf_cfg_para_hdr; + +/** sdcmd52rw parameters */ +typedef struct _sdcmd52_para +{ + /** subcmd */ + t_u32 subcmd; + /** Write /Read */ + t_u32 action; + /** Command 52 paramters */ + t_u8 cmd52_params[3]; +} sdcmd52_para; + +/** deep_sleep parameters */ +typedef struct _deep_sleep_para +{ + /** subcmd */ + t_u32 subcmd; + /** Set/Get */ + t_u32 action; + /** enable/disable deepsleep*/ + t_u16 deep_sleep; + /** idle_time */ + t_u16 idle_time; +} deep_sleep_para; + +/** tx_data_pause parameters */ +typedef struct _tx_data_pause_para +{ + /** subcmd */ + t_u32 subcmd; + /** Set/Get */ + t_u32 action; + /** enable/disable Tx data pause*/ + t_u16 txpause; + /** Max number of TX buffer allowed for all PS client*/ + t_u16 txbufcnt; +} tx_data_pause_para; + +/** mgmt_frame_ctrl */ +typedef struct _mgmt_frame_ctrl +{ + /** subcmd */ + t_u32 subcmd; + /** Set/Get */ + t_u32 action; + /** mask */ + t_u32 mask; +} mgmt_frame_ctrl; + +typedef struct _snmp_mib_para +{ + /** subcmd */ + t_u32 subcmd; + /** Set/Get */ + t_u32 action; + /** oid to set/get */ + t_u16 oid; + /** length of oid value */ + t_u16 oid_val_len; + /** oid value to set/get */ + t_u8 oid_value[0]; +} snmp_mib_para; + +/** Max length for oid_value field */ +#define MAX_SNMP_VALUE_SIZE 128 + +/** Oid for 802.11D enable/disable */ +#define OID_80211D_ENABLE 0x0009 +/** Oid for 802.11H enable/disable */ +#define OID_80211H_ENABLE 0x000a + +/** domain_info parameters */ +typedef struct _domain_info_param +{ + /** subcmd */ + t_u32 subcmd; + /** Set/Get */ + t_u32 action; + /** domain_param TLV (incl. header) */ + t_u8 tlv[0]; +} domain_info_para; + +/** DOMAIN_INFO param sizes */ +#define TLV_HEADER_LEN (2 + 2) +#define SUB_BAND_LEN 3 +#define MAX_SUB_BANDS 40 + +/** MAX domain TLV length */ +#define MAX_DOMAIN_TLV_LEN (TLV_HEADER_LEN + COUNTRY_CODE_LEN \ + + (SUB_BAND_LEN * MAX_SUB_BANDS)) + +#ifdef DFS_TESTING_SUPPORT +/** dfs_testing parameters */ +typedef struct _dfs_testing_param +{ + /** subcmd */ + t_u32 subcmd; + /** Set/Get */ + t_u32 action; + /** user CAC period (msec) */ + t_u16 usr_cac_period; + /** user NOP period (sec) */ + t_u16 usr_nop_period; + /** don't change channel on radar */ + t_u8 no_chan_change; + /** fixed channel to change to on radar */ + t_u8 fixed_new_chan; +} dfs_testing_para; +#endif + +void woal_uap_set_multicast_list(struct net_device *dev); +int woal_uap_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd); +int woal_uap_bss_ctrl(moal_private * priv, t_u8 wait_option, int data); +void woal_uap_get_version(moal_private * priv, char *version, int max_len); +mlan_status woal_uap_get_stats(moal_private * priv, t_u8 wait_option, + mlan_ds_uap_stats * ustats); +#if defined(UAP_WEXT) || defined(UAP_CFG80211) +extern struct iw_handler_def woal_uap_handler_def; +struct iw_statistics *woal_get_uap_wireless_stats(struct net_device *dev); +/** IOCTL function for wireless private IOCTLs */ +int woal_uap_do_priv_ioctl(struct net_device *dev, struct ifreq *req, int cmd); +#endif +/** Set invalid data for each member of mlan_uap_bss_param */ +void woal_set_sys_config_invalid_data(mlan_uap_bss_param * config); +/** Set/Get system configuration parameters */ +mlan_status woal_set_get_sys_config(moal_private * priv, + t_u16 action, t_u8 wait_option, + mlan_uap_bss_param * sys_cfg); +int woal_uap_set_ap_cfg(moal_private * priv, t_u8 * data, int len); +mlan_status woal_uap_set_11n_status(mlan_uap_bss_param * sys_cfg, t_u8 action); +#ifdef UAP_WEXT +void woal_ioctl_get_uap_info_resp(moal_private * priv, mlan_ds_get_info * info); +int woal_set_get_custom_ie(moal_private * priv, t_u16 mask, t_u8 * ie, + int ie_len); +#endif /* UAP_WEXT */ +#endif /* _MOAL_UAP_H */ diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.c b/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.c new file mode 100644 index 000000000000..e83d4de4d282 --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.c @@ -0,0 +1,1762 @@ +/** @file moal_uap_cfg80211.c + * + * @brief This file contains the functions for uAP CFG80211. + * + * Copyright (C) 2011-2012, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +#include "moal_cfg80211.h" +#include "moal_uap_cfg80211.h" + +/* these 3 function will be called in woal_cfg80211_wifi_direct_ops */ +int woal_cfg80211_add_beacon(struct wiphy *wiphy, + struct net_device *dev, + struct beacon_parameters *params); + +int woal_cfg80211_set_beacon(struct wiphy *wiphy, + struct net_device *dev, + struct beacon_parameters *params); + +int woal_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev); + +static int woal_uap_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_scan_request *request); + +static int woal_uap_cfg80211_connect(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_connect_params *sme); + +static int woal_uap_cfg80211_disconnect(struct wiphy *wiphy, + struct net_device *dev, + t_u16 reason_code); + +int woal_uap_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, + u8 * mac, struct station_info *stainfo); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS) +static const struct ieee80211_txrx_stypes + ieee80211_uap_mgmt_stypes[NUM_NL80211_IFTYPES] = { + [NL80211_IFTYPE_ADHOC] = { + .tx = 0x0000, + .rx = 0x0000, + }, + [NL80211_IFTYPE_STATION] = { + .tx = BIT(IEEE80211_STYPE_ACTION >> 4), + .rx = BIT(IEEE80211_STYPE_ACTION >> 4), + }, + [NL80211_IFTYPE_AP] = { + .tx = 0xffff, + .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) | + BIT(IEEE80211_STYPE_PROBE_REQ >> 4) | + BIT(IEEE80211_STYPE_DISASSOC >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4) | + BIT(IEEE80211_STYPE_ACTION >> 4), + }, + [NL80211_IFTYPE_AP_VLAN] = { + .tx = 0x0000, + .rx = 0x0000, + }, + [NL80211_IFTYPE_P2P_CLIENT] = { + .tx = 0x0000, + .rx = 0x0000, + }, + [NL80211_IFTYPE_P2P_GO] = { + .tx = 0x0000, + .rx = 0x0000, + }, + [NL80211_IFTYPE_MESH_POINT] = { + .tx = 0x0000, + .rx = 0x0000, + }, +}; +#endif + +/** cfg80211 uAP operations */ +static struct cfg80211_ops woal_cfg80211_uap_ops = { + .add_virtual_intf = woal_cfg80211_add_virtual_intf, + .del_virtual_intf = woal_cfg80211_del_virtual_intf, + .set_channel = woal_cfg80211_set_channel, + .scan = woal_uap_cfg80211_scan, + .connect = woal_uap_cfg80211_connect, + .disconnect = woal_uap_cfg80211_disconnect, + .set_wiphy_params = woal_cfg80211_set_wiphy_params, + .change_virtual_intf = woal_cfg80211_change_virtual_intf, + .add_key = woal_cfg80211_add_key, + .del_key = woal_cfg80211_del_key, + .set_default_key = woal_cfg80211_set_default_key, + .add_beacon = woal_cfg80211_add_beacon, + .set_beacon = woal_cfg80211_set_beacon, + .del_beacon = woal_cfg80211_del_beacon, + .get_station = woal_uap_cfg80211_get_station, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS) + .mgmt_frame_register = woal_cfg80211_mgmt_frame_register, + .mgmt_tx = woal_cfg80211_mgmt_tx, +#endif +}; + +/******************************************************** + Local Variables +********************************************************/ + +/******************************************************** + Global Variables +********************************************************/ + +/******************************************************** + Local Functions +********************************************************/ + +/******************************************************** + Global Functions +********************************************************/ +/** + * @brief Filter specific IE in ie buf + * + * @param ie Pointer to IEs + * @param len Total length of ie + * @param ie_out Pointer to out IE buf + * + * @return out IE length + */ +static t_u16 +woal_filter_beacon_ies(const t_u8 * ie, int len, t_u8 * ie_out) +{ + int left_len = len; + const t_u8 *pos = ie; + int length; + t_u8 id = 0; + t_u16 out_len = 0; + + /* ERP_INFO and RSN IE will be fileter out */ + while (left_len >= 2) { + length = *(pos + 1); + id = *pos; + if ((length + 2) > left_len) + break; + switch (id) { + case ERP_INFO: + case RSN_IE: + break; + default: + memcpy(ie_out + out_len, pos, length + 2); + out_len += length + 2; + break; + } + pos += (length + 2); + left_len -= (length + 2); + } + return out_len; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0) && !defined(COMPAT_WIRELESS) +/** + * @brief Verify RSN IE + * + * @param rsn_ie Pointer RSN IE + * @param sys_config Pointer to mlan_uap_bss_param structure + * + * @return MTRUE/MFALSE + */ +static t_u8 +woal_check_rsn_ie(IEEEtypes_Rsn_t * rsn_ie, mlan_uap_bss_param * sys_config) +{ + int left = 0; + int count = 0; + int i = 0; + wpa_suite_auth_key_mgmt_t *key_mgmt = NULL; + left = rsn_ie->len + 2; + if (left < sizeof(IEEEtypes_Rsn_t)) + return MFALSE; + sys_config->wpa_cfg.group_cipher = 0; + sys_config->wpa_cfg.pairwise_cipher_wpa2 = 0; + /* check the group cipher */ + switch (rsn_ie->group_cipher.type) { + case WPA_CIPHER_TKIP: + sys_config->wpa_cfg.group_cipher = CIPHER_TKIP; + break; + case WPA_CIPHER_AES_CCM: + sys_config->wpa_cfg.group_cipher = CIPHER_AES_CCMP; + break; + default: + break; + } + count = le16_to_cpu(rsn_ie->pairwise_cipher.count); + for (i = 0; i < count; i++) { + switch (rsn_ie->pairwise_cipher.list[i].type) { + case WPA_CIPHER_TKIP: + sys_config->wpa_cfg.pairwise_cipher_wpa2 |= CIPHER_TKIP; + break; + case WPA_CIPHER_AES_CCM: + sys_config->wpa_cfg.pairwise_cipher_wpa2 |= CIPHER_AES_CCMP; + break; + default: + break; + } + } + left -= sizeof(IEEEtypes_Rsn_t) + (count - 1) * sizeof(wpa_suite); + if (left < sizeof(wpa_suite_auth_key_mgmt_t)) + return MFALSE; + key_mgmt = + (wpa_suite_auth_key_mgmt_t *) ((u8 *) rsn_ie + sizeof(IEEEtypes_Rsn_t) + + (count - 1) * sizeof(wpa_suite)); + count = le16_to_cpu(key_mgmt->count); + if (left < + (sizeof(wpa_suite_auth_key_mgmt_t) + (count - 1) * sizeof(wpa_suite))) + return MFALSE; + + for (i = 0; i < count; i++) { + switch (key_mgmt->list[i].type) { + case RSN_AKM_8021X: + sys_config->key_mgmt = KEY_MGMT_EAP; + break; + case RSN_AKM_PSK: + sys_config->key_mgmt = KEY_MGMT_PSK; + break; + } + } + return MTRUE; +} + +/** + * @brief Verify WPA IE + * + * @param wpa_ie Pointer WPA IE + * @param sys_config Pointer to mlan_uap_bss_param structure + * + * @return MTRUE/MFALSE + */ +static t_u8 +woal_check_wpa_ie(IEEEtypes_Wpa_t * wpa_ie, mlan_uap_bss_param * sys_config) +{ + int left = 0; + int count = 0; + int i = 0; + wpa_suite_auth_key_mgmt_t *key_mgmt = NULL; + left = wpa_ie->len + 2; + if (left < sizeof(IEEEtypes_Wpa_t)) + return MFALSE; + sys_config->wpa_cfg.group_cipher = 0; + sys_config->wpa_cfg.pairwise_cipher_wpa = 0; + switch (wpa_ie->group_cipher.type) { + case WPA_CIPHER_TKIP: + sys_config->wpa_cfg.group_cipher = CIPHER_TKIP; + break; + case WPA_CIPHER_AES_CCM: + sys_config->wpa_cfg.group_cipher = CIPHER_AES_CCMP; + break; + default: + break; + } + count = le16_to_cpu(wpa_ie->pairwise_cipher.count); + for (i = 0; i < count; i++) { + switch (wpa_ie->pairwise_cipher.list[i].type) { + case WPA_CIPHER_TKIP: + sys_config->wpa_cfg.pairwise_cipher_wpa |= CIPHER_TKIP; + break; + case WPA_CIPHER_AES_CCM: + sys_config->wpa_cfg.pairwise_cipher_wpa |= CIPHER_AES_CCMP; + break; + default: + break; + } + } + left -= sizeof(IEEEtypes_Wpa_t) + (count - 1) * sizeof(wpa_suite); + if (left < sizeof(wpa_suite_auth_key_mgmt_t)) + return MFALSE; + key_mgmt = + (wpa_suite_auth_key_mgmt_t *) ((u8 *) wpa_ie + sizeof(IEEEtypes_Wpa_t) + + (count - 1) * sizeof(wpa_suite)); + count = le16_to_cpu(key_mgmt->count); + if (left < + (sizeof(wpa_suite_auth_key_mgmt_t) + (count - 1) * sizeof(wpa_suite))) + return MFALSE; + for (i = 0; i < count; i++) { + switch (key_mgmt->list[i].type) { + case RSN_AKM_8021X: + sys_config->key_mgmt = KEY_MGMT_EAP; + break; + case RSN_AKM_PSK: + sys_config->key_mgmt = KEY_MGMT_PSK; + break; + } + } + return MTRUE; +} + +/** + * @brief Find RSN/WPA IES + * + * @param ie Pointer IE buffer + * @param sys_config Pointer to mlan_uap_bss_param structure + * + * @return MTRUE/MFALSE + */ +static t_u8 +woal_find_wpa_ies(t_u8 * ie, int len, mlan_uap_bss_param * sys_config) +{ + int bytes_left = len; + t_u8 *pcurrent_ptr = ie; + t_u16 total_ie_len; + t_u8 element_len; + t_u8 wpa2 = 0; + t_u8 wpa = 0; + t_u8 ret = MFALSE; + IEEEtypes_ElementId_e element_id; + IEEEtypes_VendorSpecific_t *pvendor_ie; + const t_u8 wpa_oui[4] = { 0x00, 0x50, 0xf2, 0x01 }; + + while (bytes_left >= 2) { + element_id = (IEEEtypes_ElementId_e) (*((t_u8 *) pcurrent_ptr)); + element_len = *((t_u8 *) pcurrent_ptr + 1); + total_ie_len = element_len + sizeof(IEEEtypes_Header_t); + if (bytes_left < total_ie_len) { + PRINTM(MERROR, "InterpretIE: Error in processing IE, " + "bytes left < IE length\n"); + bytes_left = 0; + continue; + } + switch (element_id) { + case RSN_IE: + wpa2 = + woal_check_rsn_ie((IEEEtypes_Rsn_t *) pcurrent_ptr, sys_config); + break; + case VENDOR_SPECIFIC_221: + pvendor_ie = (IEEEtypes_VendorSpecific_t *) pcurrent_ptr; + if (!memcmp(pvendor_ie->vend_hdr.oui, wpa_oui, sizeof(wpa_oui))) + wpa = + woal_check_wpa_ie((IEEEtypes_Wpa_t *) pcurrent_ptr, + sys_config); + break; + default: + break; + } + pcurrent_ptr += element_len + 2; + /* Need to account for IE ID and IE Len */ + bytes_left -= (element_len + 2); + } + if (wpa && wpa2) { + sys_config->protocol = PROTOCOL_WPA | PROTOCOL_WPA2; + ret = MTRUE; + } else if (wpa2) { + sys_config->protocol = PROTOCOL_WPA2; + ret = MTRUE; + } else if (wpa) { + sys_config->protocol = PROTOCOL_WPA; + ret = MTRUE; + } + return ret; +} +#endif + +/** + * @brief Look up specific IE in a buf + * + * @param ie Pointer to IEs + * @param len Total length of ie + * @param id Element id to lookup + * + * @return Pointer of the specific IE -- success, NULL -- fail + */ +static const t_u8 * +woal_parse_ie_tlv(const t_u8 * ie, int len, t_u8 id) +{ + int left_len = len; + const t_u8 *pos = ie; + int length; + + /* IE format: | u8 | id | | u8 | len | | var | data | */ + while (left_len >= 2) { + length = *(pos + 1); + if ((*pos == id) && (length + 2) <= left_len) + return pos; + pos += (length + 2); + left_len -= (length + 2); + } + + return NULL; +} + +/** + * @brief Add custom ie to mgmt frames. + * + * @param priv A pointer to moal private structure + * @param beacon_ies_data Beacon ie + * @param beacon_index The index for beacon when auto index + * @param proberesp_ies_data Probe resp ie + * @param proberesp_index The index for probe resp when auto index + * @param assocresp_ies_data Assoc resp ie + * @param assocresp_index The index for assoc resp when auto index + * @param probereq_ies_data Probe req ie + * @param probereq_index The index for probe req when auto index * + * + * @return 0 -- success, otherwise fail + */ +static int +woal_cfg80211_custom_ie(moal_private * priv, + custom_ie * beacon_ies_data, t_u16 * beacon_index, + custom_ie * proberesp_ies_data, t_u16 * proberesp_index, + custom_ie * assocresp_ies_data, t_u16 * assocresp_index, + custom_ie * probereq_ies_data, t_u16 * probereq_index) +{ + mlan_ioctl_req *ioctl_req = NULL; + mlan_ds_misc_cfg *misc = NULL; + mlan_ds_misc_custom_ie *custom_ie = NULL; + t_u8 *pos = NULL; + t_u16 len = 0; + int ret = 0; + + ENTER(); + + if (!(custom_ie = kmalloc(sizeof(mlan_ds_misc_custom_ie), GFP_KERNEL))) { + ret = -ENOMEM; + goto done; + } + + memset(custom_ie, 0x00, sizeof(mlan_ds_misc_custom_ie)); + custom_ie->type = TLV_TYPE_MGMT_IE; + + pos = (t_u8 *) custom_ie->ie_data_list; + if (beacon_ies_data) { + len = sizeof(*beacon_ies_data) - MAX_IE_SIZE + + beacon_ies_data->ie_length; + memcpy(pos, beacon_ies_data, len); + pos += len; + custom_ie->len += len; + } + + if (proberesp_ies_data) { + len = sizeof(*proberesp_ies_data) - MAX_IE_SIZE + + proberesp_ies_data->ie_length; + memcpy(pos, proberesp_ies_data, len); + pos += len; + custom_ie->len += len; + } + + if (assocresp_ies_data) { + len = sizeof(*assocresp_ies_data) - MAX_IE_SIZE + + assocresp_ies_data->ie_length; + memcpy(pos, assocresp_ies_data, len); + custom_ie->len += len; + } + + if (probereq_ies_data) { + len = sizeof(*probereq_ies_data) - MAX_IE_SIZE + + probereq_ies_data->ie_length; + memcpy(pos, probereq_ies_data, len); + pos += len; + custom_ie->len += len; + } + + ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (ioctl_req == NULL) { + ret = -ENOMEM; + goto done; + } + + misc = (mlan_ds_misc_cfg *) ioctl_req->pbuf; + misc->sub_command = MLAN_OID_MISC_CUSTOM_IE; + ioctl_req->req_id = MLAN_IOCTL_MISC_CFG; + ioctl_req->action = MLAN_ACT_SET; + + memcpy(&misc->param.cust_ie, custom_ie, sizeof(mlan_ds_misc_custom_ie)); + + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + /* get the assigned index */ + pos = (t_u8 *) (&misc->param.cust_ie.ie_data_list[0].ie_index); + if (beacon_ies_data && beacon_ies_data->ie_length + && beacon_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) { + /* save beacon ie index after auto-indexing */ + *beacon_index = misc->param.cust_ie.ie_data_list[0].ie_index; + len = sizeof(*beacon_ies_data) - MAX_IE_SIZE + + beacon_ies_data->ie_length; + pos += len; + } + + if (proberesp_ies_data && proberesp_ies_data->ie_length + && proberesp_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) { + /* save probe resp ie index after auto-indexing */ + *proberesp_index = *((t_u16 *) pos); + len = sizeof(*proberesp_ies_data) - MAX_IE_SIZE + + proberesp_ies_data->ie_length; + pos += len; + } + + if (assocresp_ies_data && assocresp_ies_data->ie_length + && assocresp_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) { + /* save assoc resp ie index after auto-indexing */ + *assocresp_index = *((t_u16 *) pos); + len = sizeof(*assocresp_ies_data) - MAX_IE_SIZE + + assocresp_ies_data->ie_length; + pos += len; + } + if (probereq_ies_data && probereq_ies_data->ie_length + && probereq_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) { + /* save probe resp ie index after auto-indexing */ + *probereq_index = *((t_u16 *) pos); + len = sizeof(*probereq_ies_data) - MAX_IE_SIZE + + probereq_ies_data->ie_length; + pos += len; + } + + if (ioctl_req->status_code == MLAN_ERROR_IOCTL_FAIL) + ret = -EFAULT; + + done: + if (ioctl_req) + kfree(ioctl_req); + if (custom_ie) + kfree(custom_ie); + LEAVE(); + return ret; +} + +/** + * @brief This function returns priv + * based on mgmt ie index + * + * @param handle A pointer to moal_handle + * @param index mgmt ie index + * + * @return Pointer to moal_private + */ +static moal_private * +woal_get_priv_by_mgmt_index(moal_handle * handle, t_u16 index) +{ + int i; + + for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) { + if (handle->priv[i]) { + if (handle->priv[i]->probereq_index == index) + return (handle->priv[i]); + } + } + return NULL; +} + +/** + * @brief config AP or GO for mgmt frame ies. + * + * @param priv A pointer to moal private structure + * @param beacon_ies A pointer to beacon ies + * @param beacon_ies_len Beacon ies length + * @param proberesp_ies A pointer to probe resp ies + * @param proberesp_ies_len Probe resp ies length + * @param assocresp_ies A pointer to probe resp ies + * @param assocresp_ies_len Assoc resp ies length + * @param probereq_ies A pointer to probe req ies + * @param probereq_ies_len Probe req ies length * + * @param mask Mgmt frame mask + * + * @return 0 -- success, otherwise fail + */ +int +woal_cfg80211_mgmt_frame_ie(moal_private * priv, + const t_u8 * beacon_ies, size_t beacon_ies_len, + const t_u8 * proberesp_ies, + size_t proberesp_ies_len, + const t_u8 * assocresp_ies, + size_t assocresp_ies_len, const t_u8 * probereq_ies, + size_t probereq_ies_len, t_u16 mask) +{ + int ret = 0; + t_u8 *pos = NULL; + custom_ie *beacon_ies_data = NULL; + custom_ie *proberesp_ies_data = NULL; + custom_ie *assocresp_ies_data = NULL; + custom_ie *probereq_ies_data = NULL; + + /* static variables for mgmt frame ie auto-indexing */ + static t_u16 beacon_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; + static t_u16 proberesp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; + static t_u16 assocresp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; + static t_u16 probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; + moal_private *pmpriv = NULL; + static t_u16 rsn_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; + const t_u8 *rsn_ie; + + ENTER(); + + if (mask & MGMT_MASK_BEACON) { + if (!(beacon_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) { + ret = -ENOMEM; + goto done; + } + if (beacon_ies && beacon_ies_len) { + rsn_ie = + woal_parse_ie_tlv((t_u8 *) beacon_ies, (int) beacon_ies_len, + RSN_IE); + if (rsn_ie) { + beacon_ies_data->ie_index = rsn_index; + beacon_ies_data->mgmt_subtype_mask = + MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP | + MGMT_MASK_ASSOC_RESP; + beacon_ies_data->ie_length = rsn_ie[1] + 2; + memcpy(beacon_ies_data->ie_buffer, rsn_ie, rsn_ie[1] + 2); + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_custom_ie(priv, beacon_ies_data, &rsn_index, + NULL, &proberesp_index, NULL, + &assocresp_index, NULL, + &probereq_index)) { + ret = -EFAULT; + goto done; + } + } + } else { + /* clear rsn_ie */ + if (rsn_index <= MAX_MGMT_IE_INDEX) { + beacon_ies_data->ie_index = rsn_index; + beacon_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK; + beacon_ies_data->ie_length = 0; + rsn_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_custom_ie(priv, beacon_ies_data, &rsn_index, + NULL, &proberesp_index, NULL, + &assocresp_index, NULL, + &probereq_index)) { + ret = -EFAULT; + goto done; + } + } + } + } + + if (mask & MGMT_MASK_PROBE_RESP) { + if (!(proberesp_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) { + ret = -ENOMEM; + goto done; + } + } + + if (mask & MGMT_MASK_ASSOC_RESP) { + if (!(assocresp_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) { + ret = -ENOMEM; + goto done; + } + } + if (mask & MGMT_MASK_PROBE_REQ) { + if (!(probereq_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) { + ret = -ENOMEM; + goto done; + } + } + + if (beacon_ies_data) { + memset(beacon_ies_data, 0x00, sizeof(custom_ie)); + if (beacon_ies && beacon_ies_len) { + /* set the beacon ies */ + beacon_ies_data->ie_index = beacon_index; + beacon_ies_data->mgmt_subtype_mask = MGMT_MASK_BEACON; + beacon_ies_data->mgmt_subtype_mask |= MGMT_MASK_ASSOC_RESP; + beacon_ies_data->ie_length = woal_filter_beacon_ies(beacon_ies, + beacon_ies_len, + beacon_ies_data-> + ie_buffer); + } else { + /* clear the beacon ies */ + if (beacon_index > MAX_MGMT_IE_INDEX) { + PRINTM(MERROR, "Invalid beacon index for mgmt frame ie.\n"); + goto done; + } + + beacon_ies_data->ie_index = beacon_index; + beacon_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK; + beacon_ies_data->ie_length = 0; + beacon_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; + } + } + + if (proberesp_ies_data) { + memset(proberesp_ies_data, 0x00, sizeof(custom_ie)); + if (proberesp_ies && proberesp_ies_len) { + /* set the probe response ies */ + // proberesp_ies_data->ie_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; + proberesp_ies_data->ie_index = proberesp_index; + proberesp_ies_data->mgmt_subtype_mask = MGMT_MASK_PROBE_RESP; + proberesp_ies_data->ie_length = proberesp_ies_len; + pos = proberesp_ies_data->ie_buffer; + memcpy(pos, proberesp_ies, proberesp_ies_len); + } else { + /* clear the probe response ies */ + if (proberesp_index > MAX_MGMT_IE_INDEX) { + PRINTM(MERROR, "Invalid probe resp index for mgmt frame ie.\n"); + goto done; + } + + proberesp_ies_data->ie_index = proberesp_index; + proberesp_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK; + proberesp_ies_data->ie_length = 0; + proberesp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; + } + } + if (assocresp_ies_data) { + memset(assocresp_ies_data, 0x00, sizeof(custom_ie)); + if (assocresp_ies && assocresp_ies_len) { + /* set the assoc response ies */ + assocresp_ies_data->ie_index = assocresp_index; + assocresp_ies_data->mgmt_subtype_mask = MGMT_MASK_ASSOC_RESP; + assocresp_ies_data->ie_length = assocresp_ies_len; + pos = assocresp_ies_data->ie_buffer; + memcpy(pos, assocresp_ies, assocresp_ies_len); + } else { + /* clear the assoc response ies */ + if (assocresp_index > MAX_MGMT_IE_INDEX) { + PRINTM(MERROR, "Invalid assoc resp index for mgmt frame ie.\n"); + goto done; + } + + assocresp_ies_data->ie_index = assocresp_index; + assocresp_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK; + assocresp_ies_data->ie_length = 0; + assocresp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; + } + } + + if (probereq_ies_data) { + memset(probereq_ies_data, 0x00, sizeof(custom_ie)); + if ((probereq_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK) && + (priv->probereq_index != probereq_index)) { + pmpriv = woal_get_priv_by_mgmt_index(priv->phandle, probereq_index); + if (pmpriv) { + probereq_ies_data->ie_index = probereq_index; + probereq_ies_data->mgmt_subtype_mask = + MLAN_CUSTOM_IE_DELETE_MASK; + probereq_ies_data->ie_length = 0; + probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; + pmpriv->probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_custom_ie(pmpriv, NULL, &beacon_index, + NULL, &proberesp_index, + NULL, &assocresp_index, + probereq_ies_data, + &probereq_index)) { + ret = -EFAULT; + goto done; + } + memset(probereq_ies_data, 0x00, sizeof(custom_ie)); + } + } + if (probereq_ies && probereq_ies_len) { + /* set the probe req ies */ + probereq_ies_data->ie_index = probereq_index; + probereq_ies_data->mgmt_subtype_mask = MGMT_MASK_PROBE_REQ; + probereq_ies_data->ie_length = probereq_ies_len; + pos = probereq_ies_data->ie_buffer; + memcpy(pos, probereq_ies, probereq_ies_len); + } else { + /* clear the probe req ies */ + if (probereq_index > MAX_MGMT_IE_INDEX) { + PRINTM(MERROR, "Invalid probe resp index for mgmt frame ie.\n"); + goto done; + } + probereq_ies_data->ie_index = probereq_index; + probereq_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK; + probereq_ies_data->ie_length = 0; + probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; + } + } + + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_custom_ie(priv, beacon_ies_data, &beacon_index, + proberesp_ies_data, &proberesp_index, + assocresp_ies_data, &assocresp_index, + probereq_ies_data, &probereq_index)) { + ret = -EFAULT; + goto done; + } + if (probereq_ies_data) + priv->probereq_index = probereq_index; + + done: + if (beacon_ies_data) + kfree(beacon_ies_data); + if (proberesp_ies_data) + kfree(proberesp_ies_data); + if (assocresp_ies_data) + kfree(assocresp_ies_data); + + LEAVE(); + + return ret; +} + +/** + * @brief initialize AP or GO bss config + * + * @param priv A pointer to moal private structure + * @param params A pointer to beacon_parameters structure + * @return 0 -- success, otherwise fail + */ +static int +woal_cfg80211_beacon_config(moal_private * priv, + struct beacon_parameters *params) +{ + int ret = 0; + mlan_uap_bss_param sys_config; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0) || defined(COMPAT_WIRELESS) + int i = 0; +#else + const t_u8 *ssid_ie = NULL; + struct ieee80211_mgmt *head = NULL; + t_u16 capab_info = 0; +#endif + + ENTER(); + + if (params == NULL) { + ret = -EFAULT; + goto done; + } + + if (priv->bss_type != MLAN_BSS_TYPE_UAP +#ifdef WIFI_DIRECT_SUPPORT + && priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT +#endif + ) { + ret = -EFAULT; + goto done; + } + + /* Initialize the uap bss values which are uploaded from firmware */ + if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, + MLAN_ACT_GET, + MOAL_IOCTL_WAIT, + &sys_config)) { + PRINTM(MERROR, "Error getting AP confiruration\n"); + ret = -EFAULT; + goto done; + } + + /* Setting the default values */ + sys_config.channel = 6; + sys_config.preamble_type = 0; + + if (priv->bss_type == MLAN_BSS_TYPE_UAP) { + if (params->interval) + sys_config.beacon_period = params->interval; + if (params->dtim_period) + sys_config.dtim_period = params->dtim_period; + } + if (priv->channel) + sys_config.channel = priv->channel; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0) || defined(COMPAT_WIRELESS) + if (!params->ssid || !params->ssid_len) { + ret = -EINVAL; + goto done; + } + memcpy(sys_config.ssid.ssid, params->ssid, + MIN(MLAN_MAX_SSID_LENGTH, params->ssid_len)); + sys_config.ssid.ssid_len = MIN(MLAN_MAX_SSID_LENGTH, params->ssid_len); + if (params->hidden_ssid) + sys_config.bcast_ssid_ctl = 0; + else + sys_config.bcast_ssid_ctl = 1; + if (params->auth_type == NL80211_AUTHTYPE_SHARED_KEY) + sys_config.auth_mode = MLAN_AUTH_MODE_SHARED; + else + sys_config.auth_mode = MLAN_AUTH_MODE_OPEN; + + for (i = 0; i < params->crypto.n_akm_suites; i++) { + switch (params->crypto.akm_suites[i]) { + case WLAN_AKM_SUITE_8021X: + sys_config.key_mgmt = KEY_MGMT_EAP; + if ((params->crypto.wpa_versions & NL80211_WPA_VERSION_1) && + (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)) + sys_config.protocol = PROTOCOL_WPA | PROTOCOL_WPA2; + else if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2) + sys_config.protocol = PROTOCOL_WPA2; + else if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1) + sys_config.protocol = PROTOCOL_WPA; + break; + case WLAN_AKM_SUITE_PSK: + sys_config.key_mgmt = KEY_MGMT_PSK; + if ((params->crypto.wpa_versions & NL80211_WPA_VERSION_1) && + (params->crypto.wpa_versions & NL80211_WPA_VERSION_2)) + sys_config.protocol = PROTOCOL_WPA | PROTOCOL_WPA2; + else if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2) + sys_config.protocol = PROTOCOL_WPA2; + else if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1) + sys_config.protocol = PROTOCOL_WPA; + break; + } + } + sys_config.wpa_cfg.pairwise_cipher_wpa = 0; + sys_config.wpa_cfg.pairwise_cipher_wpa2 = 0; + for (i = 0; i < params->crypto.n_ciphers_pairwise; i++) { + switch (params->crypto.ciphers_pairwise[i]) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + break; + case WLAN_CIPHER_SUITE_TKIP: + if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1) + sys_config.wpa_cfg.pairwise_cipher_wpa |= CIPHER_TKIP; + if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2) + sys_config.wpa_cfg.pairwise_cipher_wpa2 |= CIPHER_TKIP; + break; + case WLAN_CIPHER_SUITE_CCMP: + if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1) + sys_config.wpa_cfg.pairwise_cipher_wpa |= CIPHER_AES_CCMP; + if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2) + sys_config.wpa_cfg.pairwise_cipher_wpa2 |= CIPHER_AES_CCMP; + break; + } + } + switch (params->crypto.cipher_group) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + if ((priv->cipher == WLAN_CIPHER_SUITE_WEP40) || + (priv->cipher == WLAN_CIPHER_SUITE_WEP104)) { + sys_config.protocol = PROTOCOL_STATIC_WEP; + sys_config.key_mgmt = KEY_MGMT_NONE; + sys_config.wpa_cfg.length = 0; + sys_config.wep_cfg.key0.key_index = priv->key_index; + sys_config.wep_cfg.key0.is_default = 1; + sys_config.wep_cfg.key0.length = priv->key_len; + memcpy(sys_config.wep_cfg.key0.key, priv->key_material, + priv->key_len); + } + break; + case WLAN_CIPHER_SUITE_TKIP: + sys_config.wpa_cfg.group_cipher = CIPHER_TKIP; + break; + case WLAN_CIPHER_SUITE_CCMP: + sys_config.wpa_cfg.group_cipher = CIPHER_AES_CCMP; + break; + } +#else + /* Since in Android ICS 4.0.1's wpa_supplicant, there is no way to set ssid + when GO (AP) starts up, so get it from beacon head parameter TODO: right + now use hard code 24 -- ieee80211 header lenth, 12 -- fixed element + length for beacon */ +#define BEACON_IE_OFFSET 36 + /* Find SSID in head SSID IE id: 0, right now use hard code */ + ssid_ie = woal_parse_ie_tlv(params->head + BEACON_IE_OFFSET, + params->head_len - BEACON_IE_OFFSET, 0); + if (!ssid_ie) { + PRINTM(MERROR, "No ssid IE found.\n"); + ret = -EFAULT; + goto done; + } + if (*(ssid_ie + 1) > 32) { + PRINTM(MERROR, "ssid len error: %d\n", *(ssid_ie + 1)); + ret = -EFAULT; + goto done; + } + memcpy(sys_config.ssid.ssid, ssid_ie + 2, *(ssid_ie + 1)); + sys_config.ssid.ssid_len = *(ssid_ie + 1); + head = (struct ieee80211_mgmt *) params->head; + capab_info = le16_to_cpu(head->u.beacon.capab_info); + PRINTM(MIOCTL, "capab_info=0x%x\n", head->u.beacon.capab_info); + sys_config.auth_mode = MLAN_AUTH_MODE_OPEN; + /** For ICS, we don't support OPEN mode */ + if ((priv->cipher == WLAN_CIPHER_SUITE_WEP40) || + (priv->cipher == WLAN_CIPHER_SUITE_WEP104)) { + sys_config.protocol = PROTOCOL_STATIC_WEP; + sys_config.key_mgmt = KEY_MGMT_NONE; + sys_config.wpa_cfg.length = 0; + sys_config.wep_cfg.key0.key_index = priv->key_index; + sys_config.wep_cfg.key0.is_default = 1; + sys_config.wep_cfg.key0.length = priv->key_len; + memcpy(sys_config.wep_cfg.key0.key, priv->key_material, priv->key_len); + } else { + /** Get cipher and key_mgmt from RSN/WPA IE */ + if (capab_info & WLAN_CAPABILITY_PRIVACY) { + if (MFALSE == + woal_find_wpa_ies(params->tail, params->tail_len, + &sys_config)) { + /* hard code setting to wpa2-psk */ + sys_config.protocol = PROTOCOL_WPA2; + sys_config.key_mgmt = KEY_MGMT_PSK; + sys_config.wpa_cfg.pairwise_cipher_wpa2 = CIPHER_AES_CCMP; + sys_config.wpa_cfg.group_cipher = CIPHER_AES_CCMP; + } + } + } +#endif /* COMPAT_WIRELESS */ + /* If the security mode is configured as WEP or WPA-PSK, it will disable + 11n automatically, and if configured as open(off) or wpa2-psk, it will + automatically enable 11n */ + if ((sys_config.protocol == PROTOCOL_STATIC_WEP) || + (sys_config.protocol == PROTOCOL_WPA)) + woal_uap_set_11n_status(&sys_config, MLAN_ACT_DISABLE); + else + woal_uap_set_11n_status(&sys_config, MLAN_ACT_ENABLE); + if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, + MLAN_ACT_SET, + MOAL_IOCTL_WAIT, + &sys_config)) { + ret = -EFAULT; + goto done; + } + done: + LEAVE(); + return ret; +} + +static int +woal_mon_open(struct net_device *ndev) +{ + ENTER(); + LEAVE(); + return 0; +} + +static int +woal_mon_close(struct net_device *ndev) +{ + ENTER(); + LEAVE(); + return 0; +} + +static int +woal_mon_set_mac_address(struct net_device *ndev, void *addr) +{ + ENTER(); + LEAVE(); + return 0; +} + +static void +woal_mon_set_multicast_list(struct net_device *ndev) +{ + ENTER(); + LEAVE(); +} + +static int +woal_mon_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + int len_rthdr; + int qos_len = 0; + int dot11_hdr_len = 24; + int snap_len = 6; + unsigned char *pdata; + unsigned short fc; + unsigned char src_mac_addr[6]; + unsigned char dst_mac_addr[6]; + struct ieee80211_hdr *dot11_hdr; + struct ieee80211_radiotap_header *prthdr = + (struct ieee80211_radiotap_header *) skb->data; + monitor_iface *mon_if = netdev_priv(ndev); + + if (mon_if == NULL || mon_if->base_ndev == NULL) { + goto fail; + } + + ENTER(); + /* check for not even having the fixed radiotap header part */ + if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header))) { + PRINTM(MERROR, "Invalid radiotap hdr length," + "skb->len: %d\n", skb->len); + goto fail; /* too short to be possibly valid */ + } + + /* is it a header version we can trust to find length from? */ + if (unlikely(prthdr->it_version)) + goto fail; /* only version 0 is supported */ + + /* then there must be a radiotap header with a length we can use */ + len_rthdr = ieee80211_get_radiotap_len(skb->data); + + /* does the skb contain enough to deliver on the alleged length? */ + if (unlikely(skb->len < len_rthdr)) { + PRINTM(MERROR, "Invalid data length," "skb->len: %d\n", skb->len); + goto fail; /* skb too short for claimed rt header extent */ + } + + /* Skip the ratiotap header */ + skb_pull(skb, len_rthdr); + + dot11_hdr = (struct ieee80211_hdr *) skb->data; + fc = le16_to_cpu(dot11_hdr->frame_control); + if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) { + /* Check if this ia a Wireless Distribution System (WDS) frame which + has 4 MAC addresses */ + if (dot11_hdr->frame_control & 0x0080) + qos_len = 2; + if ((dot11_hdr->frame_control & 0x0300) == 0x0300) + dot11_hdr_len += 6; + + memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr)); + memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr)); + + /* Skip the 802.11 header, QoS (if any) and SNAP, but leave spaces for + for two MAC addresses */ + skb_pull(skb, + dot11_hdr_len + qos_len + snap_len - sizeof(src_mac_addr) * 2); + pdata = (unsigned char *) skb->data; + memcpy(pdata, dst_mac_addr, sizeof(dst_mac_addr)); + memcpy(pdata + sizeof(dst_mac_addr), src_mac_addr, + sizeof(src_mac_addr)); + + LEAVE(); + return woal_hard_start_xmit(skb, mon_if->base_ndev); + } + + fail: + dev_kfree_skb(skb); + return NETDEV_TX_OK; +} + +static const struct net_device_ops woal_cfg80211_mon_if_ops = { + .ndo_open = woal_mon_open, + .ndo_start_xmit = woal_mon_hard_start_xmit, + .ndo_stop = woal_mon_close, + .ndo_set_mac_address = woal_mon_set_mac_address, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,2,0) + .ndo_set_rx_mode = woal_mon_set_multicast_list, +#else + .ndo_set_multicast_list = woal_mon_set_multicast_list, +#endif +}; + +static void +woal_mon_if_setup(struct net_device *dev) +{ + ENTER(); + ether_setup(dev); + dev->netdev_ops = &woal_cfg80211_mon_if_ops; + dev->destructor = free_netdev; + LEAVE(); +} + +/** + * @brief Request the driver to add a monitor interface + * + * @param wiphy A pointer to wiphy structure + * @param name Virtual interface name + * @param flags Flags for the virtual interface + * @param params A pointer to vif_params structure + * @param new_dev Netdevice to be passed out + * + * @return A pointer to net_device -- success, otherwise null + */ +static int +woal_cfg80211_add_mon_if(struct wiphy *wiphy, char *name, + u32 * flags, struct vif_params *params, + struct net_device **new_dev) +{ + int ret; + struct net_device *ndev; + monitor_iface *mon_if; + moal_private *priv; + + ENTER(); + + ASSERT_RTNL(); + + priv = (moal_private *) woal_get_wiphy_priv(wiphy); + + ndev = alloc_netdev_mq(sizeof(*mon_if), name, woal_mon_if_setup, 1); + if (!ndev) { + PRINTM(MFATAL, "Init virtual ethernet device failed\n"); + ret = -EFAULT; + goto fail; + } + + dev_net_set(ndev, wiphy_net(wiphy)); + + ret = dev_alloc_name(ndev, ndev->name); + if (ret < 0) { + PRINTM(MFATAL, "Net device alloc name fail.\n"); + goto fail; + } + + memcpy(ndev->perm_addr, wiphy->perm_addr, ETH_ALEN); + memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN); + SET_NETDEV_DEV(ndev, wiphy_dev(wiphy)); + + mon_if = netdev_priv(ndev); + ndev->ieee80211_ptr = &mon_if->wdev; + mon_if->wdev.iftype = NL80211_IFTYPE_MONITOR; + mon_if->wdev.wiphy = wiphy; + memcpy(mon_if->ifname, ndev->name, IFNAMSIZ); + + ndev->type = ARPHRD_IEEE80211_RADIOTAP; + ndev->netdev_ops = &woal_cfg80211_mon_if_ops; + + mon_if->priv = priv; + mon_if->mon_ndev = ndev; + mon_if->base_ndev = priv->netdev; + mon_if->radiotap_enabled = 1; + mon_if->flag = 1; + + ret = register_netdevice(ndev); + if (ret) { + PRINTM(MFATAL, "register net_device failed, ret=%d\n", ret); + goto fail; + } + + if (new_dev) + *new_dev = ndev; + + fail: + if (ret && ndev) + free_netdev(ndev); + LEAVE(); + return ret; +} + +/** + * @brief Request the driver to add a virtual interface + * + * @param wiphy A pointer to wiphy structure + * @param name Virtual interface name + * @param type Virtual interface type + * @param flags Flags for the virtual interface + * @param params A pointer to vif_params structure + * + * @return A pointer to net_device -- success, otherwise null + */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS) +struct net_device * +woal_cfg80211_add_virtual_intf(struct wiphy *wiphy, + char *name, enum nl80211_iftype type, + u32 * flags, struct vif_params *params) +#else +int +woal_cfg80211_add_virtual_intf(struct wiphy *wiphy, + char *name, enum nl80211_iftype type, + u32 * flags, struct vif_params *params) +#endif +{ + struct net_device *ndev = NULL; + int ret = 0; + + ENTER(); + PRINTM(MIOCTL, "add virtual intf: %d\n", type); + switch (type) { + case NL80211_IFTYPE_MONITOR: + ret = woal_cfg80211_add_mon_if(wiphy, name, flags, params, &ndev); + break; + default: + PRINTM(MWARN, "Not supported if type: %d\n", type); + ret = -EFAULT; + break; + } + LEAVE(); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS) + if (ret) + return NULL; + else + return ndev; +#else + return ret; +#endif +} + +/** + * @brief Request the driver to del a virtual interface + * + * @param wiphy A pointer to wiphy structure + * @param dev The pointer to net_device + * + * @return 0 -- success, otherwise fail + */ +int +woal_cfg80211_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev) +{ + ENTER(); + + PRINTM(MIOCTL, "del virtual intf\n"); + ASSERT_RTNL(); + unregister_netdevice(dev); + + LEAVE(); + return 0; +} + +static int +woal_uap_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_scan_request *request) +{ + ENTER(); + + cfg80211_scan_done(request, MTRUE); + + LEAVE(); + return 0; +} + +static int +woal_uap_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_connect_params *sme) +{ + ENTER(); + LEAVE(); + return 0; +} + +static int +woal_uap_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, + t_u16 reason_code) +{ + ENTER(); + LEAVE(); + return 0; +} + +/** + * @brief initialize AP or GO parameters + + * + * @param wiphy A pointer to wiphy structure + * @param dev A pointer to net_device structure + * @param params A pointer to beacon_parameters structure + * @return 0 -- success, otherwise fail + */ +int +woal_cfg80211_add_beacon(struct wiphy *wiphy, + struct net_device *dev, + struct beacon_parameters *params) +{ + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + int ret = 0; + + ENTER(); + + PRINTM(MIOCTL, "add beacon\n"); + if (params != NULL) { + /* bss config */ + if (MLAN_STATUS_SUCCESS != woal_cfg80211_beacon_config(priv, params)) { + ret = -EFAULT; + goto done; + } + + /* set mgmt frame ies */ + if (MLAN_STATUS_SUCCESS != woal_cfg80211_mgmt_frame_ie(priv, +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0) && !defined(COMPAT_WIRELESS) + params->tail, + params->tail_len, + NULL, 0, NULL, 0, + NULL, 0, + MGMT_MASK_BEACON +#else + params->tail, + params->tail_len, + params-> + proberesp_ies, + params-> + proberesp_ies_len, + params-> + assocresp_ies, + params-> + assocresp_ies_len, + NULL, 0, + MGMT_MASK_BEACON + | + MGMT_MASK_PROBE_RESP + | + MGMT_MASK_ASSOC_RESP +#endif + )) { + ret = -EFAULT; + goto done; + } + } + + /* if the bss is stopped, then start it */ + if (priv->bss_started == MFALSE) { + if (MLAN_STATUS_SUCCESS != + woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START)) { + ret = -EFAULT; + goto done; + } + } + + done: + LEAVE(); + return ret; +} + +/** + * @brief set AP or GO parameter + * + * @param wiphy A pointer to wiphy structure + * @param dev A pointer to net_device structure + * @param params A pointer to beacon_parameters structure + * @return 0 -- success, otherwise fail + */ +int +woal_cfg80211_set_beacon(struct wiphy *wiphy, + struct net_device *dev, + struct beacon_parameters *params) +{ + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + int ret = 0; + + ENTER(); + + PRINTM(MIOCTL, "set beacon\n"); + if (params != NULL) { +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0) && !defined(COMPAT_WIRELESS) + if (params->tail && params->tail_len) { + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_mgmt_frame_ie(priv, + params->tail, params->tail_len, + NULL, 0, NULL, 0, NULL, 0, + MGMT_MASK_BEACON)) { + ret = -EFAULT; + goto done; + } + } +#else + if (params->beacon_ies && params->beacon_ies_len) { + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_mgmt_frame_ie(priv, params->tail, + params->tail_len, NULL, 0, NULL, 0, + NULL, 0, MGMT_MASK_BEACON)) { + ret = -EFAULT; + goto done; + } + } + + if (params->proberesp_ies && params->proberesp_ies_len) { + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, + params->proberesp_ies, + params->proberesp_ies_len, NULL, 0, + NULL, 0, MGMT_MASK_PROBE_RESP)) { + ret = -EFAULT; + goto done; + } + } + + if (params->assocresp_ies && params->assocresp_ies_len) { + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, NULL, 0, + params->assocresp_ies, + params->assocresp_ies_len, NULL, 0, + MGMT_MASK_ASSOC_RESP)) { + ret = -EFAULT; + goto done; + } + } +#endif + } + + done: + LEAVE(); + return ret; +} + +/** + * @brief reset AP or GO parameters + * + * @param wiphy A pointer to wiphy structure + * @param dev A pointer to net_device structure + * + * @return 0 -- success, otherwise fail + */ +int +woal_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) +{ + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + int ret = 0; + + ENTER(); + + PRINTM(MIOCTL, "del beacon\n"); + /* if the bss is still running, then stop it */ + if (priv->bss_started == MTRUE) { + if (MLAN_STATUS_SUCCESS != + woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP)) { + ret = -EFAULT; + goto done; + } + if (MLAN_STATUS_SUCCESS != + woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_RESET)) { + ret = -EFAULT; + goto done; + } + } + + /* clear mgmt frame ies */ + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, NULL, 0, NULL, 0, NULL, 0, + MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP | + MGMT_MASK_ASSOC_RESP)) { + ret = -EFAULT; + goto done; + } + + priv->cipher = 0; + priv->key_len = 0; + done: + LEAVE(); + return ret; +} + +/** + * @brief Get station info + * + * @param wiphy A pointer to wiphy structure + * @param dev A pointer to net_device structure + * @param mac A pointer to station mac address + * @param stainfo A pointer to station_info structure + * + * @return 0 -- success, otherwise fail + */ +int +woal_uap_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, + u8 * mac, struct station_info *stainfo) +{ + moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + int ret = -EFAULT; + int i = 0; + mlan_ds_get_info *info = NULL; + mlan_ioctl_req *ioctl_req = NULL; + + ENTER(); + if (priv->media_connected == MFALSE) { + PRINTM(MINFO, "cfg80211: Media not connected!\n"); + LEAVE(); + return -ENOENT; + } + + /* Allocate an IOCTL request buffer */ + ioctl_req = + (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info)); + if (ioctl_req == NULL) { + ret = -ENOMEM; + goto done; + } + + info = (mlan_ds_get_info *) ioctl_req->pbuf; + info->sub_command = MLAN_OID_UAP_STA_LIST; + ioctl_req->req_id = MLAN_IOCTL_GET_INFO; + ioctl_req->action = MLAN_ACT_GET; + + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) { + goto done; + } + for (i = 0; i < info->param.sta_list.sta_count; i++) { + if (!memcmp(info->param.sta_list.info[i].mac_address, mac, ETH_ALEN)) { + PRINTM(MIOCTL, + "Get station: %02x:%02x:%02x:%02x:%02x:%02x RSSI=%d\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], + (int) info->param.sta_list.info[i].rssi); + stainfo->filled = STATION_INFO_INACTIVE_TIME | STATION_INFO_SIGNAL; + stainfo->inactive_time = 0; + stainfo->signal = info->param.sta_list.info[i].rssi; + ret = 0; + break; + } + } + done: + if (ioctl_req) + kfree(ioctl_req); + LEAVE(); + return ret; +} + +/** + * @brief Sets up the CFG802.11 specific HT capability fields + * with default values + * + * @param ht_info A pointer to ieee80211_sta_ht_cap structure + * @param ap_cfg A pointer to mlan_uap_bss_param + * + * @return N/A + */ +static void +woal_cfg80211_setup_uap_ht_cap(struct ieee80211_sta_ht_cap *ht_info, + mlan_uap_bss_param * ap_cfg) +{ + ENTER(); + + ht_info->ht_supported = true; + ht_info->ampdu_factor = ap_cfg->ampdu_param & (MBIT(1) | MBIT(0)); + ht_info->ampdu_density = + ap_cfg->ampdu_param & (MBIT(4) | MBIT(3) | MBIT(2)); + + memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); + memcpy(ht_info->mcs.rx_mask, ap_cfg->supported_mcs_set, + sizeof(ht_info->mcs.rx_mask)); + + ht_info->cap = 0; + if (ap_cfg->ht_cap_info & MBIT(1)) /* 20/40 Mhz enable */ + ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; + if (ap_cfg->ht_cap_info & MBIT(4)) /* Green field supported */ + ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; + if (ap_cfg->ht_cap_info & MBIT(5)) /* Short GI @ 20Mhz supported */ + ht_info->cap |= IEEE80211_HT_CAP_SGI_20; + if (ap_cfg->ht_cap_info & MBIT(6)) /* Short GI @ 40Mhz supported */ + ht_info->cap |= IEEE80211_HT_CAP_SGI_40; + if (ap_cfg->ht_cap_info & MBIT(12)) /* DSS/CCK mode in 40MHz enable */ + ht_info->cap |= IEEE80211_HT_CAP_DSSSCCK40; + ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; + + LEAVE(); +} + +/** + * @brief Initialize the uAP wiphy + * + * @param priv A pointer to moal_private structure + * @param wait_option Wait option + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +woal_cfg80211_uap_init_wiphy(moal_private * priv, t_u8 wait_option) +{ + struct wiphy *wiphy = priv->wdev->wiphy; + mlan_uap_bss_param ap_cfg; + + ENTER(); + + if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, + MLAN_ACT_GET, + wait_option, &ap_cfg)) { + LEAVE(); + return MLAN_STATUS_FAILURE; + } + + /* Initialize parameters for 2GHz and 5GHz bands */ + woal_cfg80211_setup_uap_ht_cap(&wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap, + &ap_cfg); + if (wiphy->bands[IEEE80211_BAND_5GHZ]) + woal_cfg80211_setup_uap_ht_cap(&wiphy->bands[IEEE80211_BAND_5GHZ]-> + ht_cap, &ap_cfg); + + /* Set retry limit count to wiphy */ + wiphy->retry_long = (t_u8) ap_cfg.retry_limit; + wiphy->retry_short = (t_u8) ap_cfg.retry_limit; + wiphy->max_scan_ie_len = MAX_IE_SIZE; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37) || defined(COMPAT_WIRELESS) + wiphy->mgmt_stypes = ieee80211_uap_mgmt_stypes; +#endif + /* Set RTS threshold to wiphy */ + wiphy->rts_threshold = (t_u32) ap_cfg.rts_threshold; + + /* Set fragment threshold to wiphy */ + wiphy->frag_threshold = (t_u32) ap_cfg.frag_threshold; + + LEAVE(); + return MLAN_STATUS_SUCCESS; +} + +/** + * @brief Register the device with cfg80211 + * + * @param dev A pointer to net_device structure + * @param bss_type BSS type + * + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + */ +mlan_status +woal_register_uap_cfg80211(struct net_device * dev, t_u8 bss_type) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + moal_private *priv = (moal_private *) netdev_priv(dev); + void *wdev_priv = NULL; + struct wireless_dev *wdev = NULL; + mlan_fw_info fw_info; + + ENTER(); + + /* Allocate wireless device */ + wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); + if (!wdev) { + PRINTM(MERROR, "Could not allocate wireless device\n"); + ret = MLAN_STATUS_FAILURE; + goto err_wdev; + } + + /* Allocate wiphy */ + wdev->wiphy = wiphy_new(&woal_cfg80211_uap_ops, sizeof(moal_private *)); + if (!wdev->wiphy) { + PRINTM(MERROR, "Could not allocate wiphy device\n"); + ret = MLAN_STATUS_FAILURE; + goto err_wdev; + } + if (bss_type == MLAN_BSS_TYPE_UAP) { + dev_set_name(&wdev->wiphy->dev, dev->name); + wdev->iftype = NL80211_IFTYPE_AP; + wdev->wiphy->interface_modes = + MBIT(NL80211_IFTYPE_AP) | MBIT(NL80211_IFTYPE_STATION) | + MBIT(NL80211_IFTYPE_MONITOR); + wdev->wiphy->max_scan_ssids = 10; + } + + /* Make this wiphy known to this driver only */ + wdev->wiphy->privid = mrvl_wiphy_privid; + + /* Supported bands */ + wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &cfg80211_band_2ghz; + if (MLAN_STATUS_SUCCESS == + woal_request_get_fw_info(priv, MOAL_CMD_WAIT, &fw_info)) { + if (fw_info.fw_bands & BAND_A) + wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &cfg80211_band_5ghz; + } + + /* Initialize cipher suits */ + wdev->wiphy->cipher_suites = cfg80211_cipher_suites; + wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cfg80211_cipher_suites); + + wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + + /* We are using custom domains */ + wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + + wdev->wiphy->reg_notifier = NULL; // TODO: woal_cfg80211_reg_notifier; + + /* Set moal_private pointer in wiphy_priv */ + wdev_priv = wiphy_priv(wdev->wiphy); + + *(unsigned long *) wdev_priv = (unsigned long) priv; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) || defined(COMPAT_WIRELESS) + set_wiphy_dev(wdev->wiphy, (struct device *) priv->phandle->hotplug_device); +#endif + + if (wiphy_register(wdev->wiphy) < 0) { + PRINTM(MERROR, "Wiphy device registration failed!\n"); + ret = MLAN_STATUS_FAILURE; + goto err_wdev; + } + + dev_net_set(dev, wiphy_net(wdev->wiphy)); + dev->ieee80211_ptr = wdev; + SET_NETDEV_DEV(dev, wiphy_dev(wdev->wiphy)); + priv->wdev = wdev; + + if (ret != MLAN_STATUS_SUCCESS) { + PRINTM(MERROR, "Wiphy device registration failed!\n"); + } else { + PRINTM(MINFO, "Successfully registered wiphy device\n"); + LEAVE(); + return ret; + } + + wiphy_unregister(wdev->wiphy); + err_wdev: + dev->ieee80211_ptr = NULL; + if (wdev && wdev->wiphy) + wiphy_free(wdev->wiphy); + kfree(wdev); + LEAVE(); + return ret; +} diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.h b/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.h new file mode 100644 index 000000000000..74c6f1a4e59b --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.h @@ -0,0 +1,30 @@ +/** @file moal_uap_cfg80211.h + * + * @brief This file contains the uAP CFG80211 specific defines. + * + * Copyright (C) 2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +#ifndef _MOAL_UAP_CFG80211_H_ +#define _MOAL_UAP_CFG80211_H_ + +#include "moal_uap.h" + +mlan_status woal_register_uap_cfg80211(struct net_device *dev, t_u8 bss_type); +mlan_status woal_cfg80211_uap_init_wiphy(moal_private * priv, t_u8 wait_option); + +#endif /* _MOAL_UAP_CFG80211_H_ */ diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap_priv.c b/drivers/net/wireless/sd8797/mlinux/moal_uap_priv.c new file mode 100644 index 000000000000..dd06e03ecb1e --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/moal_uap_priv.c @@ -0,0 +1,175 @@ +/** @file moal_uap_priv.c + * + * @brief This file contains standard ioctl functions + * + * Copyright (C) 2010-2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +/************************************************************************ +Change log: + 08/06/2010: initial version +************************************************************************/ + +#include "moal_main.h" +#include "moal_uap.h" +#include "moal_uap_priv.h" + +/******************************************************** + Local Variables +********************************************************/ + +/******************************************************** + Global Variables +********************************************************/ + +/******************************************************** + Local Functions +********************************************************/ + +/******************************************************** + Global Functions +********************************************************/ + +/** + * @brief ioctl function for wireless IOCTLs + * + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * @param cmd Command + * + * @return 0 --success, otherwise fail + */ +int +woal_uap_do_priv_ioctl(struct net_device *dev, struct ifreq *req, int cmd) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + struct iwreq *wrq = (struct iwreq *) req; + int ret = 0; + + ENTER(); + + switch (cmd) { + case WOAL_UAP_SETNONE_GETNONE: + switch (wrq->u.data.flags) { + case WOAL_UAP_START: + break; + case WOAL_UAP_STOP: + ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP); + break; + case WOAL_AP_BSS_START: + ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START); + break; + case WOAL_AP_BSS_STOP: + ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP); + break; + default: + ret = -EINVAL; + break; + } + break; + case WOAL_UAP_SETONEINT_GETWORDCHAR: + switch (wrq->u.data.flags) { + case WOAL_UAP_VERSION: + ret = woal_get_driver_version(priv, req); + break; + case WOAL_UAP_VEREXT: + ret = woal_get_driver_verext(priv, req); + break; + default: + ret = -EOPNOTSUPP; + break; + } + break; + case WOAL_UAP_SET_GET_256_CHAR: + switch (wrq->u.data.flags) { + case WOAL_WL_FW_RELOAD: + break; + case WOAL_AP_SET_CFG: + ret = woal_uap_set_ap_cfg(priv, wrq->u.data.pointer, + wrq->u.data.length); + break; + default: + ret = -EINVAL; + break; + } + break; +#if defined(WIFI_DIRECT_SUPPORT) +#if defined(STA_SUPPORT) && defined(UAP_SUPPORT) + case WOAL_UAP_SETONEINT_GETONEINT: + switch (wrq->u.data.flags) { + case WOAL_UAP_SET_GET_BSS_ROLE: + ret = woal_set_get_bss_role(priv, wrq); + break; + default: + ret = -EINVAL; + break; + } + break; +#endif +#endif + case WOAL_UAP_HOST_CMD: + ret = woal_host_command(priv, wrq); + break; + case WOAL_UAP_FROYO_START: + break; + case WOAL_UAP_FROYO_STOP: + ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP); + break; + case WOAL_UAP_FROYO_AP_BSS_START: + ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START); + break; + case WOAL_UAP_FROYO_AP_BSS_STOP: + ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP); + break; + case WOAL_UAP_FROYO_WL_FW_RELOAD: + break; + case WOAL_UAP_FROYO_AP_SET_CFG: + ret = woal_uap_set_ap_cfg(priv, wrq->u.data.pointer, + wrq->u.data.length); + break; + default: + ret = -EINVAL; + break; + } + + LEAVE(); + return ret; +} + +/** + * @brief Handle get info resp + * + * @param priv Pointer to moal_private structure + * @param info Pointer to mlan_ds_get_info structure + * + * @return N/A + */ +void +woal_ioctl_get_uap_info_resp(moal_private * priv, mlan_ds_get_info * info) +{ + ENTER(); + switch (info->sub_command) { + case MLAN_OID_GET_STATS: + priv->w_stats.discard.fragment = info->param.ustats.fcs_error_count; + priv->w_stats.discard.retries = info->param.ustats.retry_count; + priv->w_stats.discard.misc = info->param.ustats.ack_failure_count; + break; + default: + break; + } + LEAVE(); +} diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap_priv.h b/drivers/net/wireless/sd8797/mlinux/moal_uap_priv.h new file mode 100644 index 000000000000..fcd811efb168 --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/moal_uap_priv.h @@ -0,0 +1,194 @@ +/** @file moal_uap_priv.h + * + * @brief This file contains definition for extended private IOCTL call. + * + * Copyright (C) 2010-2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +/************************************************************************ +Change log: + 08/06/2010: initial version +************************************************************************/ + +#ifndef _MOAL_UAP_PRIV_H_ +#define _MOAL_UAP_PRIV_H_ + +/** Private command ID */ +#define WOAL_UAP_IOCTL 0x8BE0 + +/** Private command to get/set 256 chars */ +#define WOAL_UAP_SET_GET_256_CHAR (WOAL_UAP_IOCTL + 1) +/** Private command ID to FW reload */ +#define WOAL_WL_FW_RELOAD 1 +/** Private command ID to set AP configuration */ +#define WOAL_AP_SET_CFG 2 + +/** Private command ID to set/get none */ +#define WOAL_UAP_SETNONE_GETNONE (WOAL_UAP_IOCTL + 2) +/** Private command ID to start UAP */ +#define WOAL_UAP_START 1 +/** Private command ID to stop UAP */ +#define WOAL_UAP_STOP 2 +/** Private command ID to start AP BSS */ +#define WOAL_AP_BSS_START 3 +/** Private command ID to stop AP BSS */ +#define WOAL_AP_BSS_STOP 4 + +/** Private command ID to set one int/get word char */ +#define WOAL_UAP_SETONEINT_GETWORDCHAR (WOAL_UAP_IOCTL + 3) +/** Private command ID to get version */ +#define WOAL_UAP_VERSION 1 +/** Private command ID to get extended version */ +#define WOAL_UAP_VEREXT 2 + +#if defined(WIFI_DIRECT_SUPPORT) +#if defined(STA_SUPPORT) && defined(UAP_SUPPORT) +/** Private command ID to set one int/get one int */ +#define WOAL_UAP_SETONEINT_GETONEINT (WOAL_UAP_IOCTL + 5) +/** Private command ID for set/get BSS role */ +#define WOAL_UAP_SET_GET_BSS_ROLE 1 +#endif +#endif + +/** Private command ID for hostcmd */ +#define WOAL_UAP_HOST_CMD (WOAL_UAP_IOCTL + 17) + +/** The following command IDs are for Froyo app */ +/** Private command ID to start AP BSS */ +#define WOAL_UAP_FROYO_AP_BSS_START (WOAL_UAP_IOCTL + 24) +/** Private command ID to stop AP BSS */ +#define WOAL_UAP_FROYO_AP_BSS_STOP (WOAL_UAP_IOCTL + 26) +/** Private command ID to set AP config */ +#define WOAL_UAP_FROYO_AP_SET_CFG (WOAL_UAP_IOCTL + 27) +/** Private command ID to start driver */ +#define WOAL_UAP_FROYO_START (WOAL_UAP_IOCTL + 28) +/** Private command ID to reload FW */ +#define WOAL_UAP_FROYO_WL_FW_RELOAD (WOAL_UAP_IOCTL + 29) +/** Private command ID to stop driver */ +#define WOAL_UAP_FROYO_STOP (WOAL_UAP_IOCTL + 30) + +/** + * iwpriv ioctl handlers + */ +static const struct iw_priv_args woal_uap_priv_args[] = { + { + WOAL_UAP_SETNONE_GETNONE, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + ""}, + { + WOAL_UAP_START, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "start"}, + { + WOAL_UAP_STOP, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "stop"}, + { + WOAL_AP_BSS_START, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "bssstart"}, + { + WOAL_AP_BSS_STOP, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "bssstop"}, + { + WOAL_UAP_SETONEINT_GETWORDCHAR, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_CHAR | 128, + ""}, + { + WOAL_UAP_VERSION, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_CHAR | 128, + "version"}, + { + WOAL_UAP_VEREXT, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_CHAR | 128, + "verext"}, +#if defined(WIFI_DIRECT_SUPPORT) +#if defined(STA_SUPPORT) && defined(UAP_SUPPORT) + { + WOAL_UAP_SETONEINT_GETONEINT, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + ""}, + { + WOAL_UAP_SET_GET_BSS_ROLE, + IW_PRIV_TYPE_INT | 1, + IW_PRIV_TYPE_INT | 1, + "bssrole"}, +#endif +#endif + { + WOAL_UAP_SET_GET_256_CHAR, + IW_PRIV_TYPE_CHAR | 256, + IW_PRIV_TYPE_CHAR | 256, + ""}, + { + WOAL_WL_FW_RELOAD, + IW_PRIV_TYPE_CHAR | 256, + IW_PRIV_TYPE_CHAR | 256, + "fwreload"}, + { + WOAL_AP_SET_CFG, + IW_PRIV_TYPE_CHAR | 256, + IW_PRIV_TYPE_CHAR | 256, + "apcfg"}, + { + WOAL_UAP_HOST_CMD, + IW_PRIV_TYPE_BYTE | 2047, + IW_PRIV_TYPE_BYTE | 2047, + "hostcmd"}, + { + WOAL_UAP_FROYO_START, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "START"}, + { + WOAL_UAP_FROYO_STOP, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "STOP"}, + { + WOAL_UAP_FROYO_AP_BSS_START, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "AP_BSS_START"}, + { + WOAL_UAP_FROYO_AP_BSS_STOP, + IW_PRIV_TYPE_NONE, + IW_PRIV_TYPE_NONE, + "AP_BSS_STOP"}, + { + WOAL_UAP_FROYO_WL_FW_RELOAD, + IW_PRIV_TYPE_CHAR | 256, + IW_PRIV_TYPE_CHAR | 256, + "WL_FW_RELOAD"}, + { + WOAL_UAP_FROYO_AP_SET_CFG, + IW_PRIV_TYPE_CHAR | 256, + IW_PRIV_TYPE_CHAR | 256, + "AP_SET_CFG"}, +}; + +#endif /* _MOAL_UAP_PRIV_H_ */ diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap_wext.c b/drivers/net/wireless/sd8797/mlinux/moal_uap_wext.c new file mode 100644 index 000000000000..0426a28339cb --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/moal_uap_wext.c @@ -0,0 +1,1766 @@ +/** @file moal_uap_wext.c + * + * @brief This file contains wireless extension standard ioctl functions + * + * Copyright (C) 2010-2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +/************************************************************************ +Change log: + 08/06/2010: initial version +************************************************************************/ + +#include "moal_main.h" +#include "moal_uap.h" +#include "moal_wext.h" +#include "moal_uap_priv.h" + +/******************************************************** + Global Variables +********************************************************/ +typedef struct _chan_to_freq_t +{ + /** Channel */ + t_u16 channel; + /** Frequency */ + t_u32 freq; + /** Band */ + t_u8 band; +} chan_to_freq_t; + +const chan_to_freq_t chan_to_freq[] = { + {1, 2412, 0}, + {2, 2417, 0}, + {3, 2422, 0}, + {4, 2427, 0}, + {5, 2432, 0}, + {6, 2437, 0}, + {7, 2442, 0}, + {8, 2447, 0}, + {9, 2452, 0}, + {10, 2457, 0}, + {11, 2462, 0}, + {12, 2467, 0}, + {13, 2472, 0}, + {14, 2484, 0}, + {183, 4915, 1}, + {184, 4920, 1}, + {185, 4925, 1}, + {187, 4935, 1}, + {188, 4940, 1}, + {189, 4945, 1}, + {192, 4960, 1}, + {196, 4980, 1}, + {7, 5035, 1}, + {8, 5040, 1}, + {9, 5045, 1}, + {11, 5055, 1}, + {12, 5060, 1}, + {16, 5080, 1}, + {34, 5170, 1}, + {36, 5180, 1}, + {38, 5190, 1}, + {40, 5200, 1}, + {42, 5210, 1}, + {44, 5220, 1}, + {46, 5230, 1}, + {48, 5240, 1}, + {52, 5260, 1}, + {56, 5280, 1}, + {60, 5300, 1}, + {64, 5320, 1}, + {100, 5500, 1}, + {104, 5520, 1}, + {108, 5540, 1}, + {112, 5560, 1}, + {116, 5580, 1}, + {120, 5600, 1}, + {124, 5620, 1}, + {128, 5640, 1}, + {132, 5660, 1}, + {136, 5680, 1}, + {140, 5700, 1}, + {149, 5745, 1}, + {153, 5765, 1}, + {157, 5785, 1}, + {161, 5805, 1}, + {165, 5825, 1}, +}; + +/** Convertion from frequency to channel */ +#define freq_to_chan(x) ((((x) - 2412) / 5) + 1) + +/******************************************************** + Local Functions +********************************************************/ + +/** + * @brief Sort Channels + * + * @param freq A pointer to iw_freq structure + * @param num Number of Channels + * + * @return N/A + */ +static inline void +woal_sort_channels(struct iw_freq *freq, int num) +{ + int i, j; + struct iw_freq temp; + + for (i = 0; i < num; i++) + for (j = i + 1; j < num; j++) + if (freq[i].i > freq[j].i) { + temp.i = freq[i].i; + temp.m = freq[i].m; + + freq[i].i = freq[j].i; + freq[i].m = freq[j].m; + + freq[j].i = temp.i; + freq[j].m = temp.m; + } +} + +/** + * @brief Get frequency for channel in given band + * + * @param channel channel + * @param band band + * + * @return freq + */ +static int +channel_to_frequency(t_u16 channel, t_u8 band) +{ + int i = 0; + + ENTER(); + for (i = 0; i < sizeof(chan_to_freq) / sizeof(chan_to_freq_t); i++) { + if (channel == chan_to_freq[i].channel && band == chan_to_freq[i].band) { + LEAVE(); + return chan_to_freq[i].freq; + } + } + LEAVE(); + return 0; +} + +/** + * @brief Commit handler: called after a bunch of SET operations + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param cwrq A pointer to char buffer + * @param extra A pointer to extra data buf + * + * @return 0 --success + */ +static int +woal_config_commit(struct net_device *dev, + struct iw_request_info *info, char *cwrq, char *extra) +{ + ENTER(); + + LEAVE(); + return 0; +} + +/** + * @brief Get name + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param cwrq A pointer to char buffer + * @param extra A pointer to extra data buf + * + * @return 0 --success + */ +static int +woal_get_name(struct net_device *dev, struct iw_request_info *info, + char *cwrq, char *extra) +{ + ENTER(); + strcpy(cwrq, "IEEE 802.11-DS"); + LEAVE(); + return 0; +} + +/** + * @brief Get current BSSID + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param awrq A pointer to sockaddr structure + * @param extra A pointer to extra data buf + * + * @return 0 --success + */ +static int +woal_get_wap(struct net_device *dev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + int ret = 0; + + ENTER(); + + if (priv->bss_started) { + memcpy(awrq->sa_data, priv->current_addr, MLAN_MAC_ADDR_LENGTH); + } else { + memset(awrq->sa_data, 0, MLAN_MAC_ADDR_LENGTH); + } + awrq->sa_family = ARPHRD_ETHER; + + LEAVE(); + return ret; +} + +/** + * @brief Change the AP BSSID + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param awrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_wap(struct net_device *dev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + int ret = 0; + moal_private *priv = (moal_private *) netdev_priv(dev); + const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = { 0, 0, 0, 0, 0, 0 }; + + ENTER(); + + if (awrq->sa_family != ARPHRD_ETHER) { + ret = -EINVAL; + goto done; + } + + PRINTM(MINFO, "ASSOC: WAP: uAP bss : %02x:%02x:%02x:%02x:%02x:%02x\n", + (t_u8) awrq->sa_data[0], (t_u8) awrq->sa_data[1], + (t_u8) awrq->sa_data[2], (t_u8) awrq->sa_data[3], + (t_u8) awrq->sa_data[4], (t_u8) awrq->sa_data[5]); + + /* + * Using this ioctl to start/stop the BSS, return if bss + * is already started/stopped. + */ + if (memcmp(zero_mac, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) { + if (priv->bss_started == MFALSE) + ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START); + else + PRINTM(MINFO, "BSS is already started.\n"); + } else { + /* zero_mac means bss_stop */ + if (priv->bss_started == MTRUE) + ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP); + else + PRINTM(MINFO, "BSS is already stopped.\n"); + } + + done: + LEAVE(); + return ret; +} + +/** + * @brief Set frequency/channel + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param fwrq A pointer to iw_freq structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_freq(struct net_device *dev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_uap_bss_param *sys_cfg = NULL, *ap_cfg = NULL; + int ret = 0, chan = 0, i = 0; + + ENTER(); + + ap_cfg = kmalloc(sizeof(mlan_uap_bss_param), GFP_KERNEL); + if (ap_cfg == NULL) { + ret = -ENOMEM; + goto done; + } + + sys_cfg = kmalloc(sizeof(mlan_uap_bss_param), GFP_KERNEL); + if (sys_cfg == NULL) { + ret = -ENOMEM; + goto done; + } + + if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, + MLAN_ACT_GET, + MOAL_IOCTL_WAIT, + ap_cfg)) { + PRINTM(MERROR, "Error getting AP confiruration\n"); + ret = -EFAULT; + goto done; + } + i = ap_cfg->num_of_chan; + + /* Initialize the invalid values so that the correct values below are + downloaded to firmware */ + woal_set_sys_config_invalid_data(sys_cfg); + + /* If setting by frequency, convert to a channel */ + if (fwrq->e == 1) + chan = freq_to_chan(fwrq->m / 100000); + else + chan = fwrq->m; + if (chan > 0 && chan < MLAN_MAX_CHANNEL) + sys_cfg->channel = chan; + else { + ret = -EINVAL; + goto done; + } + for (i = 0; i < ap_cfg->num_of_chan; i++) + if (ap_cfg->chan_list[i].chan_number == chan) + break; + if (i == ap_cfg->num_of_chan) { + PRINTM(MERROR, "Channel %d is not supported\n", chan); + ret = -EINVAL; + goto done; + } + + if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, + MLAN_ACT_SET, + MOAL_IOCTL_WAIT, + sys_cfg)) { + PRINTM(MERROR, "Error setting AP confiruration\n"); + ret = -EFAULT; + goto done; + } + + done: + if (sys_cfg) + kfree(sys_cfg); + if (ap_cfg) + kfree(ap_cfg); + LEAVE(); + return ret; +} + +/** + * @brief Get frequency and channel + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param fwrq A pointer to iw_freq structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_get_freq(struct net_device *dev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_uap_bss_param ap_cfg; + t_u8 band = 0; + int ret = 0; + + ENTER(); + + if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, + MLAN_ACT_GET, + MOAL_IOCTL_WAIT, + &ap_cfg)) { + PRINTM(MERROR, "Error getting AP confiruration\n"); + LEAVE(); + return -EFAULT; + } + band = ap_cfg.band_cfg & BAND_CONFIG_5GHZ; + fwrq->i = (long) ap_cfg.channel; + fwrq->m = (long) (channel_to_frequency(ap_cfg.channel, band)) * 100000; + fwrq->e = 1; + + LEAVE(); + return ret; +} + +/** + * @brief Set wlan mode + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param uwrq A pointer to t_u32 string + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_bss_mode(struct net_device *dev, struct iw_request_info *info, + t_u32 * uwrq, char *extra) +{ + int ret = 0; + ENTER(); + + switch (*uwrq) { + case IW_MODE_AUTO: + case IW_MODE_MASTER: + PRINTM(MINFO, "This is correct mode in AP mode\n"); + break; + default: + PRINTM(MERROR, "Invalid mode for AP\n"); + ret = -EINVAL; + } + + LEAVE(); + return ret; +} + +/** + * @brief Get wlan mode + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param uwrq A pointer to t_u32 string + * @param extra A pointer to extra data buf + * + * @return 0 --success + */ +static int +woal_get_bss_mode(struct net_device *dev, struct iw_request_info *info, + t_u32 * uwrq, char *extra) +{ + ENTER(); + + *uwrq = IW_MODE_MASTER; + + LEAVE(); + return 0; +} + +/** + * @brief Set encryption key + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_encode(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + int ret = 0; + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_uap_bss_param *sys_cfg = NULL, *ap_cfg = NULL; + wep_key *pkey = NULL; + int key_index = 0; + + ENTER(); + + /* Check index */ + key_index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + if (key_index > 3) { + PRINTM(MERROR, "Key index #%d out of range\n", key_index); + ret = -EINVAL; + goto done; + } + + ap_cfg = kmalloc(sizeof(mlan_uap_bss_param), GFP_KERNEL); + if (ap_cfg == NULL) { + ret = -ENOMEM; + goto done; + } + + sys_cfg = kmalloc(sizeof(mlan_uap_bss_param), GFP_KERNEL); + if (sys_cfg == NULL) { + ret = -ENOMEM; + goto done; + } + + if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, + MLAN_ACT_GET, + MOAL_IOCTL_WAIT, + ap_cfg)) { + PRINTM(MERROR, "Error getting AP confiruration\n"); + ret = -EFAULT; + goto done; + } + + /* Initialize the invalid values so that the correct values below are + downloaded to firmware */ + woal_set_sys_config_invalid_data(sys_cfg); + sys_cfg->wep_cfg.key0.key_index = 0; + sys_cfg->wep_cfg.key1.key_index = 1; + sys_cfg->wep_cfg.key2.key_index = 2; + sys_cfg->wep_cfg.key3.key_index = 3; + + if (key_index >= 0 && key_index <= 3) { + if (key_index == 0) + pkey = &sys_cfg->wep_cfg.key0; + else if (key_index == 1) + pkey = &sys_cfg->wep_cfg.key1; + else if (key_index == 2) + pkey = &sys_cfg->wep_cfg.key2; + else if (key_index == 3) + pkey = &sys_cfg->wep_cfg.key3; + } + + if (!(dwrq->flags & IW_ENCODE_NOKEY) && dwrq->length) { + if (dwrq->length > MAX_WEP_KEY_SIZE) { + PRINTM(MERROR, "Key length (%d) out of range\n", dwrq->length); + ret = -E2BIG; + goto done; + } + if (key_index < 0) { + /* Get current default key index */ + if (ap_cfg->wep_cfg.key0.is_default) + pkey = &sys_cfg->wep_cfg.key0; + if (ap_cfg->wep_cfg.key1.is_default) + pkey = &sys_cfg->wep_cfg.key1; + if (ap_cfg->wep_cfg.key2.is_default) + pkey = &sys_cfg->wep_cfg.key2; + if (ap_cfg->wep_cfg.key3.is_default) + pkey = &sys_cfg->wep_cfg.key3; + } + + sys_cfg->protocol = PROTOCOL_STATIC_WEP; + memcpy(pkey->key, extra, dwrq->length); + /* Set the length */ + if (dwrq->length > MIN_WEP_KEY_SIZE) + pkey->length = MAX_WEP_KEY_SIZE; + else + pkey->length = MIN_WEP_KEY_SIZE; + /* Set current key index as default */ + pkey->is_default = MTRUE; + } else { + /* + * No key provided so it is either enable key, + * on or off + */ + if (dwrq->flags & IW_ENCODE_DISABLED) { + PRINTM(MINFO, "*** iwconfig mlanX key off ***\n"); + sys_cfg->protocol = PROTOCOL_NO_SECURITY; + } else { + /* + * iwconfig mlanX key [n] + * iwconfig mlanX key on + * Do we want to just set the transmit key index ? + */ + if (key_index < 0) { + PRINTM(MINFO, "*** iwconfig mlanX key on ***\n"); + } else { + /* Get current key configuration at key_index */ + if (key_index == 0) + memcpy(pkey, &ap_cfg->wep_cfg.key0, sizeof(wep_key)); + if (key_index == 1) + memcpy(pkey, &ap_cfg->wep_cfg.key1, sizeof(wep_key)); + if (key_index == 2) + memcpy(pkey, &ap_cfg->wep_cfg.key2, sizeof(wep_key)); + if (key_index == 3) + memcpy(pkey, &ap_cfg->wep_cfg.key3, sizeof(wep_key)); + /* Set current key index as default */ + pkey->is_default = MTRUE; + } + } + } + if (dwrq->flags & (IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN)) { + switch (dwrq->flags & 0xf000) { + case IW_ENCODE_RESTRICTED: + /* iwconfig mlanX restricted key [1] */ + sys_cfg->auth_mode = MLAN_AUTH_MODE_SHARED; + PRINTM(MINFO, "Auth mode restricted!\n"); + break; + case IW_ENCODE_OPEN: + /* iwconfig mlanX key [2] open */ + sys_cfg->auth_mode = MLAN_AUTH_MODE_OPEN; + PRINTM(MINFO, "Auth mode open!\n"); + break; + case IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN: + default: + /* iwconfig mlanX key [2] open restricted */ + PRINTM(MINFO, "Auth mode auto!\n"); + break; + } + } + + if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, + MLAN_ACT_SET, + MOAL_IOCTL_WAIT, + sys_cfg)) { + PRINTM(MERROR, "Error setting AP confiruration\n"); + ret = -EFAULT; + goto done; + } + + done: + if (sys_cfg) + kfree(sys_cfg); + if (ap_cfg) + kfree(ap_cfg); + LEAVE(); + return ret; +} + +/** + * @brief Get encryption key + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_get_encode(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + int index = (dwrq->flags & IW_ENCODE_INDEX); + wep_key *pkey = NULL; + mlan_uap_bss_param ap_cfg; + int ret = 0; + + ENTER(); + if (index < 0 || index > 4) { + PRINTM(MERROR, "Key index #%d out of range\n", index); + ret = -EINVAL; + goto done; + } + if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, + MLAN_ACT_GET, + MOAL_IOCTL_WAIT, + &ap_cfg)) { + PRINTM(MERROR, "Error getting AP confiruration\n"); + ret = -EFAULT; + goto done; + } + + dwrq->flags = 0; + /* + * Check encryption mode + */ + switch (ap_cfg.auth_mode) { + case MLAN_AUTH_MODE_OPEN: + dwrq->flags = IW_ENCODE_OPEN; + break; + case MLAN_AUTH_MODE_SHARED: + case MLAN_AUTH_MODE_NETWORKEAP: + dwrq->flags = IW_ENCODE_RESTRICTED; + break; + default: + dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN; + break; + } + + switch (ap_cfg.protocol) { + case PROTOCOL_NO_SECURITY: + dwrq->flags |= IW_ENCODE_DISABLED; + break; + case PROTOCOL_STATIC_WEP: + if (ap_cfg.wep_cfg.key0.is_default) + pkey = &ap_cfg.wep_cfg.key0; + else if (ap_cfg.wep_cfg.key1.is_default) + pkey = &ap_cfg.wep_cfg.key1; + else if (ap_cfg.wep_cfg.key2.is_default) + pkey = &ap_cfg.wep_cfg.key2; + else if (ap_cfg.wep_cfg.key3.is_default) + pkey = &ap_cfg.wep_cfg.key3; + if (pkey) { + dwrq->flags |= (pkey->key_index + 1); + dwrq->length = pkey->length; + memcpy(extra, pkey->key, pkey->length); + dwrq->flags &= ~IW_ENCODE_DISABLED; + } else { + ret = -EFAULT; + } + break; + case PROTOCOL_WPA: + case PROTOCOL_WPA2: + case PROTOCOL_WPA2_MIXED: + memcpy(extra, ap_cfg.wpa_cfg.passphrase, ap_cfg.wpa_cfg.length); + dwrq->length = ap_cfg.wpa_cfg.length; + dwrq->flags |= 1; + dwrq->flags &= ~IW_ENCODE_DISABLED; + break; + default: + dwrq->flags &= ~IW_ENCODE_DISABLED; + break; + } + dwrq->flags |= IW_ENCODE_NOKEY; + + done: + LEAVE(); + return ret; +} + +#if (WIRELESS_EXT >= 18) +/** + * @brief Get IE + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return -EOPNOTSUPP + */ +static int +woal_get_gen_ie(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + ENTER(); + LEAVE(); + return -EOPNOTSUPP; +} + +/** + * @brief Set IE + * + * Pass an opaque block of data, expected to be IEEE IEs, to the driver + * for eventual passthrough to the firmware in an associate/join + * (and potentially start) command. + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_gen_ie(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_uap_bss_param sys_cfg; + IEEEtypes_Header_t *tlv = NULL; + int tlv_hdr_len = sizeof(IEEEtypes_Header_t), tlv_buf_left = 0; + int ret = 0; + + ENTER(); + + /* Initialize the invalid values so that the correct values below are + downloaded to firmware */ + woal_set_sys_config_invalid_data(&sys_cfg); + + tlv_buf_left = dwrq->length; + tlv = (IEEEtypes_Header_t *) extra; + while (tlv_buf_left >= tlv_hdr_len) { + if (tlv->element_id == WPA_IE) { + sys_cfg.protocol |= PROTOCOL_WPA; + if (priv->pairwise_cipher == CIPHER_TKIP) { + sys_cfg.wpa_cfg.pairwise_cipher_wpa = CIPHER_TKIP; + PRINTM(MINFO, "Set IE Cipher TKIP\n"); + } + if (priv->pairwise_cipher == CIPHER_AES_CCMP) { + sys_cfg.wpa_cfg.pairwise_cipher_wpa = CIPHER_AES_CCMP; + PRINTM(MINFO, "Set IE Cipher CCMP\n"); + } + if (priv->pairwise_cipher == (CIPHER_TKIP | CIPHER_AES_CCMP)) { + sys_cfg.wpa_cfg.pairwise_cipher_wpa = + CIPHER_TKIP | CIPHER_AES_CCMP; + PRINTM(MINFO, "Set IE Cipher TKIP + CCMP\n"); + } + memcpy(priv->bcn_ie_buf + priv->bcn_ie_len, + ((t_u8 *) tlv), sizeof(IEEEtypes_Header_t) + tlv->len); + priv->bcn_ie_len += sizeof(IEEEtypes_Header_t) + tlv->len; + } + if (tlv->element_id == RSN_IE) { + sys_cfg.protocol |= PROTOCOL_WPA2; + if (priv->pairwise_cipher == CIPHER_TKIP) { + sys_cfg.wpa_cfg.pairwise_cipher_wpa2 = CIPHER_TKIP; + } + if (priv->pairwise_cipher == CIPHER_AES_CCMP) { + sys_cfg.wpa_cfg.pairwise_cipher_wpa2 = CIPHER_AES_CCMP; + } + if (priv->pairwise_cipher == (CIPHER_TKIP | CIPHER_AES_CCMP)) { + sys_cfg.wpa_cfg.pairwise_cipher_wpa2 = + (CIPHER_TKIP | CIPHER_AES_CCMP); + } + memcpy(priv->bcn_ie_buf + priv->bcn_ie_len, + ((t_u8 *) tlv), sizeof(IEEEtypes_Header_t) + tlv->len); + priv->bcn_ie_len += sizeof(IEEEtypes_Header_t) + tlv->len; + } + if (priv->group_cipher == CIPHER_TKIP) + sys_cfg.wpa_cfg.group_cipher = CIPHER_TKIP; + if (priv->group_cipher == CIPHER_AES_CCMP) + sys_cfg.wpa_cfg.group_cipher = CIPHER_AES_CCMP; + tlv_buf_left -= (tlv_hdr_len + tlv->len); + tlv = (IEEEtypes_Header_t *) ((t_u8 *) tlv + tlv_hdr_len + tlv->len); + } + sys_cfg.key_mgmt = priv->uap_key_mgmt; + if (sys_cfg.key_mgmt & KEY_MGMT_PSK) + sys_cfg.key_mgmt_operation |= 0x01; + if (sys_cfg.key_mgmt & KEY_MGMT_EAP) + sys_cfg.key_mgmt_operation |= 0x03; + + if (sys_cfg.protocol) { + if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, + MLAN_ACT_SET, + MOAL_IOCTL_WAIT, + &sys_cfg)) { + PRINTM(MERROR, "Error setting AP configuration\n"); + ret = -EFAULT; + goto done; + } + priv->pairwise_cipher = 0; + priv->group_cipher = 0; + + /* custom IE command to set priv->bcn_ie_buf */ + if (MLAN_STATUS_SUCCESS != +#define UAP_RSN_MASK (BIT(8) | BIT(5) | BIT(1) | BIT(3)) + woal_set_get_custom_ie(priv, UAP_RSN_MASK, priv->bcn_ie_buf, + priv->bcn_ie_len)) { + PRINTM(MERROR, "Error setting wpa-rsn IE\n"); + ret = -EFAULT; + } + } else if (dwrq->length == 0) { + /* custom IE command to re-set priv->bcn_ie_buf */ + if (MLAN_STATUS_SUCCESS != + woal_set_get_custom_ie(priv, 0, priv->bcn_ie_buf, + priv->bcn_ie_len)) { + PRINTM(MERROR, "Error resetting wpa-rsn IE\n"); + ret = -EFAULT; + } + priv->bcn_ie_len = 0; + } + + done: + LEAVE(); + return ret; +} + +/** + * @brief Extended version of encoding configuration + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_encode_ext(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; + moal_private *priv = (moal_private *) netdev_priv(dev); + int key_index; + t_u8 *pkey_material = NULL; + mlan_ioctl_req *req = NULL; + mlan_ds_sec_cfg *sec = NULL; + mlan_uap_bss_param sys_cfg; + wep_key *pwep_key = NULL; + int ret = 0; + + ENTER(); + + key_index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + if (key_index < 0 || key_index > 3) { + ret = -EINVAL; + goto done; + } + if (ext->key_len > (dwrq->length - sizeof(struct iw_encode_ext))) { + ret = -EINVAL; + goto done; + } + + /* Initialize the invalid values so that the correct values below are + downloaded to firmware */ + woal_set_sys_config_invalid_data(&sys_cfg); + + pkey_material = (t_u8 *) (ext + 1); + /* Disable Key */ + if ((dwrq->flags & IW_ENCODE_DISABLED) && !ext->key_len) { + sys_cfg.protocol = PROTOCOL_NO_SECURITY; + } else if (ext->alg == IW_ENCODE_ALG_WEP) { + sys_cfg.protocol = PROTOCOL_STATIC_WEP; + /* Set WEP key */ + switch (key_index) { + case 0: + pwep_key = &sys_cfg.wep_cfg.key0; + break; + case 1: + pwep_key = &sys_cfg.wep_cfg.key1; + break; + case 2: + pwep_key = &sys_cfg.wep_cfg.key2; + break; + case 3: + pwep_key = &sys_cfg.wep_cfg.key3; + break; + } + pwep_key->key_index = key_index; + pwep_key->is_default = MTRUE; + pwep_key->length = ext->key_len; + memcpy(pwep_key->key, pkey_material, ext->key_len); + } else { + /* Set GTK/PTK key */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + sec = (mlan_ds_sec_cfg *) req->pbuf; + sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY; + req->req_id = MLAN_IOCTL_SEC_CFG; + req->action = MLAN_ACT_SET; + sec->param.encrypt_key.key_len = ext->key_len; + sec->param.encrypt_key.key_index = key_index; + memcpy(sec->param.encrypt_key.key_material, pkey_material, + ext->key_len); + memcpy(sec->param.encrypt_key.mac_addr, ext->addr.sa_data, ETH_ALEN); + sec->param.encrypt_key.key_flags = ext->ext_flags; + if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { + memcpy(sec->param.encrypt_key.pn, (t_u8 *) ext->rx_seq, + SEQ_MAX_SIZE); + DBG_HEXDUMP(MCMD_D, "Uap Rx PN", sec->param.encrypt_key.pn, + SEQ_MAX_SIZE); + } + if (ext->ext_flags & IW_ENCODE_EXT_TX_SEQ_VALID) { + memcpy(sec->param.encrypt_key.pn, (t_u8 *) ext->tx_seq, + SEQ_MAX_SIZE); + DBG_HEXDUMP(MCMD_D, "Uap Tx PN", sec->param.encrypt_key.pn, + SEQ_MAX_SIZE); + } + PRINTM(MIOCTL, + "set uap wpa key key_index=%d, key_len=%d key_flags=0x%x %02x:%02x:%02x:%02x:%02x:%02x\n", + key_index, ext->key_len, sec->param.encrypt_key.key_flags, + sec->param.encrypt_key.mac_addr[0], + sec->param.encrypt_key.mac_addr[1], + sec->param.encrypt_key.mac_addr[2], + sec->param.encrypt_key.mac_addr[3], + sec->param.encrypt_key.mac_addr[4], + sec->param.encrypt_key.mac_addr[5]); + DBG_HEXDUMP(MCMD_D, "uap wpa key", pkey_material, ext->key_len); + + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + } + /* Cipher set will be done in set generic IE */ + priv->pairwise_cipher = ext->alg; + priv->group_cipher = ext->alg; + goto done; /* No AP configuration */ + } + if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, + MLAN_ACT_SET, + MOAL_IOCTL_WAIT, + &sys_cfg)) { + PRINTM(MERROR, "Error setting AP confiruration\n"); + ret = -EFAULT; + goto done; + } + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Extended version of encoding configuration + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return -EOPNOTSUPP + */ +static int +woal_get_encode_ext(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + ENTER(); + LEAVE(); + return -EOPNOTSUPP; +} + +/** + * @brief Request MLME operation + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return 0--success, otherwise fail + */ +static int +woal_set_mlme(struct net_device *dev, + struct iw_request_info *info, struct iw_point *dwrq, char *extra) +{ + struct iw_mlme *mlme = (struct iw_mlme *) extra; + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_ds_bss *bss = NULL; + mlan_ds_get_info *pinfo = NULL; + mlan_ioctl_req *req = NULL; + mlan_ds_sta_list *sta_list = NULL; + const t_u8 bc_addr[] = { 0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF }; + t_u8 sta_addr[ETH_ALEN]; + int ret = 0, i; + + ENTER(); + + memset(sta_addr, 0, ETH_ALEN); + if ((mlme->cmd == IW_MLME_DEAUTH) || (mlme->cmd == IW_MLME_DISASSOC)) { + memcpy(sta_addr, (t_u8 *) mlme->addr.sa_data, ETH_ALEN); + PRINTM(MIOCTL, "Deauth station: %02x:%02x:%02x:%02x:%02x:%02x, " + "reason=%d\n", sta_addr[0], sta_addr[1], sta_addr[2], + sta_addr[3], sta_addr[4], sta_addr[5], mlme->reason_code); + + /* FIXME: For flushing all stations we need to use zero MAC, but right + now the FW does not support this. So, manually delete each one + individually. */ + /* If deauth all station, get the connected STA list first */ + if (!memcmp(bc_addr, sta_addr, ETH_ALEN)) { + PRINTM(MIOCTL, "Deauth all stations\n"); + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info)); + if (req == NULL) { + LEAVE(); + return -ENOMEM; + } + pinfo = (mlan_ds_get_info *) req->pbuf; + pinfo->sub_command = MLAN_OID_UAP_STA_LIST; + req->req_id = MLAN_IOCTL_GET_INFO; + req->action = MLAN_ACT_GET; + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + sta_list = + (mlan_ds_sta_list *) kmalloc(sizeof(mlan_ds_sta_list), + GFP_KERNEL); + if (sta_list == NULL) { + PRINTM(MERROR, "Memory allocation failed!\n"); + ret = -ENOMEM; + goto done; + } + memcpy(sta_list, &pinfo->param.sta_list, sizeof(mlan_ds_sta_list)); + if (req) + kfree(req); + } + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + if (req == NULL) { + LEAVE(); + return -ENOMEM; + } + bss = (mlan_ds_bss *) req->pbuf; + bss->sub_command = MLAN_OID_UAP_DEAUTH_STA; + req->req_id = MLAN_IOCTL_BSS; + req->action = MLAN_ACT_SET; + + if (!memcmp(bc_addr, sta_addr, ETH_ALEN)) { + for (i = 0; i < sta_list->sta_count; i++) { + memcpy(bss->param.deauth_param.mac_addr, + sta_list->info[i].mac_address, ETH_ALEN); + bss->param.deauth_param.reason_code = mlme->reason_code; + + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + } + } else { + memcpy(bss->param.deauth_param.mac_addr, sta_addr, ETH_ALEN); + bss->param.deauth_param.reason_code = mlme->reason_code; + + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + } + } + + done: + if (req) + kfree(req); + if (sta_list) + kfree(sta_list); + + LEAVE(); + return ret; +} + +/** @brief Set authentication mode parameters + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_auth(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_uap_bss_param sys_cfg; + + ENTER(); + + /* Initialize the invalid values so that the correct values below are + downloaded to firmware */ + woal_set_sys_config_invalid_data(&sys_cfg); + + switch (vwrq->flags & IW_AUTH_INDEX) { + case IW_AUTH_CIPHER_PAIRWISE: + /* Rest are not supported now */ + if (vwrq->value & IW_AUTH_CIPHER_NONE); + else if (vwrq->value & IW_AUTH_CIPHER_WEP40); + else if (vwrq->value & IW_AUTH_CIPHER_WEP104); + else if (vwrq->value == IW_AUTH_CIPHER_TKIP) { + sys_cfg.wpa_cfg.pairwise_cipher_wpa = CIPHER_TKIP; + sys_cfg.wpa_cfg.pairwise_cipher_wpa2 = CIPHER_TKIP; + priv->pairwise_cipher = CIPHER_TKIP; + if (!priv->uap_key_mgmt) + priv->uap_key_mgmt = KEY_MGMT_PSK; + PRINTM(MINFO, "Set Auth Cipher TKIP\n"); + } else if (vwrq->value == IW_AUTH_CIPHER_CCMP) { + sys_cfg.wpa_cfg.pairwise_cipher_wpa = CIPHER_AES_CCMP; + sys_cfg.wpa_cfg.pairwise_cipher_wpa2 = CIPHER_AES_CCMP; + priv->pairwise_cipher = CIPHER_AES_CCMP; + if (!priv->uap_key_mgmt) + priv->uap_key_mgmt = KEY_MGMT_PSK; + PRINTM(MINFO, "Set Auth Cipher CCMP\n"); + } else if (vwrq->value == (IW_AUTH_CIPHER_TKIP | IW_AUTH_CIPHER_CCMP)) { + sys_cfg.wpa_cfg.pairwise_cipher_wpa = + (CIPHER_TKIP | CIPHER_AES_CCMP); + sys_cfg.wpa_cfg.pairwise_cipher_wpa2 = + (CIPHER_TKIP | CIPHER_AES_CCMP); + priv->pairwise_cipher = (CIPHER_TKIP | CIPHER_AES_CCMP); + if (!priv->uap_key_mgmt) + priv->uap_key_mgmt = KEY_MGMT_PSK; + PRINTM(MINFO, "Set Auth Cipher TKIP + CCMP\n"); + } + break; + case IW_AUTH_CIPHER_GROUP: + /* Rest are not supported now */ + if (vwrq->value & IW_AUTH_CIPHER_NONE); + else if (vwrq->value & IW_AUTH_CIPHER_WEP40); + else if (vwrq->value & IW_AUTH_CIPHER_WEP104); + else if (vwrq->value & IW_AUTH_CIPHER_TKIP) { + sys_cfg.wpa_cfg.group_cipher = CIPHER_TKIP; + priv->group_cipher = CIPHER_TKIP; + if (!priv->uap_key_mgmt) + priv->uap_key_mgmt = KEY_MGMT_PSK; + PRINTM(MINFO, "Set Auth Cipher TKIP\n"); + } else if (vwrq->value & IW_AUTH_CIPHER_CCMP) { + sys_cfg.wpa_cfg.group_cipher = CIPHER_AES_CCMP; + priv->group_cipher = CIPHER_AES_CCMP; + if (!priv->uap_key_mgmt) + priv->uap_key_mgmt = KEY_MGMT_PSK; + PRINTM(MINFO, "Set Auth Cipher CCMP\n"); + } + break; + case IW_AUTH_80211_AUTH_ALG: + switch (vwrq->value) { + case IW_AUTH_ALG_SHARED_KEY: + PRINTM(MINFO, "Auth mode shared key!\n"); + sys_cfg.auth_mode = MLAN_AUTH_MODE_SHARED; + break; + case IW_AUTH_ALG_LEAP: + break; + case IW_AUTH_ALG_OPEN_SYSTEM: + PRINTM(MINFO, "Auth mode open!\n"); + sys_cfg.auth_mode = MLAN_AUTH_MODE_OPEN; + break; + default: + PRINTM(MINFO, "Auth mode auto!\n"); + break; + } + break; + case IW_AUTH_WPA_VERSION: + switch (vwrq->value) { + case IW_AUTH_WPA_VERSION_DISABLED: + sys_cfg.protocol = PROTOCOL_NO_SECURITY; + break; + case IW_AUTH_WPA_VERSION_WPA: + sys_cfg.protocol = PROTOCOL_WPA; + break; + case IW_AUTH_WPA_VERSION_WPA2: + sys_cfg.protocol = PROTOCOL_WPA2; + break; + case IW_AUTH_WPA_VERSION_WPA | IW_AUTH_WPA_VERSION_WPA2: + sys_cfg.protocol = PROTOCOL_WPA2_MIXED; + break; + default: + break; + } + priv->uap_protocol = sys_cfg.protocol; + break; + case IW_AUTH_KEY_MGMT: + switch (vwrq->value) { + case IW_AUTH_KEY_MGMT_802_1X: + sys_cfg.key_mgmt |= KEY_MGMT_EAP; + priv->uap_key_mgmt |= KEY_MGMT_EAP; + break; + case IW_AUTH_KEY_MGMT_PSK: + sys_cfg.key_mgmt |= KEY_MGMT_PSK; + priv->uap_key_mgmt |= KEY_MGMT_PSK; + break; + default: + break; + } + break; + case IW_AUTH_WPA_ENABLED: + case IW_AUTH_TKIP_COUNTERMEASURES: + case IW_AUTH_DROP_UNENCRYPTED: + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + case IW_AUTH_ROAMING_CONTROL: + case IW_AUTH_PRIVACY_INVOKED: + default: + LEAVE(); + return -EOPNOTSUPP; /* No AP configuration */ + } + if (!sys_cfg.key_mgmt) + sys_cfg.key_mgmt = priv->uap_key_mgmt; + if (sys_cfg.key_mgmt & KEY_MGMT_PSK) + sys_cfg.key_mgmt_operation |= 0x01; + if (sys_cfg.key_mgmt & KEY_MGMT_EAP) + sys_cfg.key_mgmt_operation |= 0x03; + if (!sys_cfg.protocol) + sys_cfg.protocol = priv->uap_protocol; + + /* Set AP configuration */ + if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, + MLAN_ACT_SET, + MOAL_IOCTL_WAIT, + &sys_cfg)) { + PRINTM(MERROR, "Error setting AP confiruration\n"); + ret = -EFAULT; + goto done; + } + + done: + LEAVE(); + return 0; +} + +/** + * @brief Get authentication mode parameters + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_get_auth(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_uap_bss_param ap_cfg; + + ENTER(); + + if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, + MLAN_ACT_GET, + MOAL_IOCTL_WAIT, + &ap_cfg)) { + PRINTM(MERROR, "Error getting AP confiruration\n"); + LEAVE(); + return -EFAULT; + } + switch (vwrq->flags & IW_AUTH_INDEX) { + case IW_AUTH_CIPHER_PAIRWISE: + if (ap_cfg.wpa_cfg.pairwise_cipher_wpa == CIPHER_TKIP || + ap_cfg.wpa_cfg.pairwise_cipher_wpa2 == CIPHER_TKIP) + vwrq->value = IW_AUTH_CIPHER_TKIP; + else if (ap_cfg.wpa_cfg.pairwise_cipher_wpa == CIPHER_AES_CCMP || + ap_cfg.wpa_cfg.pairwise_cipher_wpa2 == CIPHER_AES_CCMP) + vwrq->value = IW_AUTH_CIPHER_CCMP; + else + vwrq->value = IW_AUTH_CIPHER_NONE; + break; + case IW_AUTH_CIPHER_GROUP: + if (ap_cfg.wpa_cfg.group_cipher == CIPHER_TKIP) + vwrq->value = IW_AUTH_CIPHER_TKIP; + else if (ap_cfg.wpa_cfg.group_cipher == CIPHER_AES_CCMP) + vwrq->value = IW_AUTH_CIPHER_CCMP; + else + vwrq->value = IW_AUTH_CIPHER_NONE; + break; + case IW_AUTH_80211_AUTH_ALG: + if (ap_cfg.auth_mode == MLAN_AUTH_MODE_SHARED) + vwrq->value = IW_AUTH_ALG_SHARED_KEY; + else if (ap_cfg.auth_mode == MLAN_AUTH_MODE_NETWORKEAP) + vwrq->value = IW_AUTH_ALG_LEAP; + else + vwrq->value = IW_AUTH_ALG_OPEN_SYSTEM; + break; + case IW_AUTH_WPA_ENABLED: + if (ap_cfg.protocol == PROTOCOL_WPA || + ap_cfg.protocol == PROTOCOL_WPA2 || + ap_cfg.protocol == PROTOCOL_WPA2_MIXED) + vwrq->value = 1; + else + vwrq->value = 0; + break; + case IW_AUTH_KEY_MGMT: + if (ap_cfg.key_mgmt & KEY_MGMT_EAP) + vwrq->value |= IW_AUTH_KEY_MGMT_802_1X; + if (ap_cfg.key_mgmt & KEY_MGMT_PSK) + vwrq->value |= IW_AUTH_KEY_MGMT_PSK; + break; + case IW_AUTH_WPA_VERSION: + case IW_AUTH_TKIP_COUNTERMEASURES: + case IW_AUTH_DROP_UNENCRYPTED: + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + case IW_AUTH_ROAMING_CONTROL: + case IW_AUTH_PRIVACY_INVOKED: + default: + LEAVE(); + return -EOPNOTSUPP; + } + + LEAVE(); + return 0; +} +#endif /* WE >= 18 */ + +/* Data rate listing + * MULTI_BANDS: + * abg a b b/g + * Infra G(12) A(8) B(4) G(12) + * Adhoc A+B(12) A(8) B(4) B(4) + * non-MULTI_BANDS: + b b/g + * Infra B(4) G(12) + * Adhoc B(4) B(4) + */ +/** + * @brief Get Range Info + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_get_range(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_uap_bss_param ap_cfg; + struct iw_range *range = (struct iw_range *) extra; + t_u8 band = 0; + int i; + + ENTER(); + + if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, + MLAN_ACT_GET, + MOAL_IOCTL_WAIT, + &ap_cfg)) { + PRINTM(MERROR, "Error getting AP confiruration\n"); + LEAVE(); + return -EFAULT; + } + dwrq->length = sizeof(struct iw_range); + memset(range, 0, sizeof(struct iw_range)); + + range->min_nwid = 0; + range->max_nwid = 0; + + range->num_bitrates = MAX_DATA_RATES; + for (i = 0; i < MIN(MAX_DATA_RATES, IW_MAX_BITRATES) && + ap_cfg.rates[i]; i++) { + range->bitrate[i] = (ap_cfg.rates[i] & 0x7f) * 500000; + } + range->num_bitrates = i; + PRINTM(MINFO, "IW_MAX_BITRATES=%d num_bitrates=%d\n", + IW_MAX_BITRATES, range->num_bitrates); + + range->num_frequency = MIN(ap_cfg.num_of_chan, IW_MAX_FREQUENCIES); + + for (i = 0; i < range->num_frequency; i++) { + range->freq[i].i = (long) ap_cfg.chan_list[i].chan_number; + band = ap_cfg.chan_list[i].band_config_type & BAND_CONFIG_5GHZ; + range->freq[i].m = + (long) channel_to_frequency(ap_cfg.chan_list[i].chan_number, + band) * 100000; + range->freq[i].e = 1; + } + + PRINTM(MINFO, "IW_MAX_FREQUENCIES=%d num_frequency=%d\n", + IW_MAX_FREQUENCIES, range->num_frequency); + + range->num_channels = range->num_frequency; + + woal_sort_channels(&range->freq[0], range->num_frequency); + + /* + * Set an indication of the max TCP throughput in bit/s that we can + * expect using this interface + */ + if (i > 2) + range->throughput = 5000 * 1000; + else + range->throughput = 1500 * 1000; + + range->min_rts = MLAN_RTS_MIN_VALUE; + range->max_rts = MLAN_RTS_MAX_VALUE; + range->min_frag = MLAN_FRAG_MIN_VALUE; + range->max_frag = MLAN_FRAG_MAX_VALUE; + + range->encoding_size[0] = 5; + range->encoding_size[1] = 13; + range->num_encoding_sizes = 2; + range->max_encoding_tokens = 4; + +/** Minimum power period */ +#define IW_POWER_PERIOD_MIN 1000000 /* 1 sec */ +/** Maximum power period */ +#define IW_POWER_PERIOD_MAX 120000000 /* 2 min */ +/** Minimum power timeout value */ +#define IW_POWER_TIMEOUT_MIN 1000 /* 1 ms */ +/** Maximim power timeout value */ +#define IW_POWER_TIMEOUT_MAX 1000000 /* 1 sec */ + + /* Power Management duration & timeout */ + range->min_pmp = IW_POWER_PERIOD_MIN; + range->max_pmp = IW_POWER_PERIOD_MAX; + range->min_pmt = IW_POWER_TIMEOUT_MIN; + range->max_pmt = IW_POWER_TIMEOUT_MAX; + range->pmp_flags = IW_POWER_PERIOD; + range->pmt_flags = IW_POWER_TIMEOUT; + range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R; + + /* + * Minimum version we recommend + */ + range->we_version_source = 15; + + /* + * Version we are compiled with + */ + range->we_version_compiled = WIRELESS_EXT; + + range->retry_capa = IW_RETRY_LIMIT; + range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + + range->min_retry = MLAN_TX_RETRY_MIN; + range->max_retry = MLAN_TX_RETRY_MAX; + +#if (WIRELESS_EXT >= 18) + if (ap_cfg.protocol & PROTOCOL_WPA) + range->enc_capa |= IW_ENC_CAPA_WPA; + if (ap_cfg.protocol & PROTOCOL_WPA2) + range->enc_capa |= IW_ENC_CAPA_WPA2; + if (ap_cfg.wpa_cfg.pairwise_cipher_wpa == CIPHER_TKIP || + ap_cfg.wpa_cfg.pairwise_cipher_wpa2 == CIPHER_TKIP || + ap_cfg.wpa_cfg.group_cipher == CIPHER_TKIP) + range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP; + if (ap_cfg.wpa_cfg.pairwise_cipher_wpa == CIPHER_AES_CCMP || + ap_cfg.wpa_cfg.pairwise_cipher_wpa2 == CIPHER_AES_CCMP || + ap_cfg.wpa_cfg.group_cipher == CIPHER_AES_CCMP) + range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP; +#endif + + LEAVE(); + return 0; +} + +/** + * @brief Set priv command + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_priv(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + ENTER(); + LEAVE(); + return -EOPNOTSUPP; +} + +/** + * @brief Set essid + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return 0--success, otherwise fail + */ +static int +woal_set_essid(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_uap_bss_param sys_cfg; + int ret = 0; + + ENTER(); + + /* Check the size of the string */ + if (dwrq->length > IW_ESSID_MAX_SIZE + 1) { + ret = -E2BIG; + goto done; + } + + /* Initialize the invalid values so that the correct values below are + downloaded to firmware */ + woal_set_sys_config_invalid_data(&sys_cfg); + + /* Set the SSID */ +#if WIRELESS_EXT > 20 + sys_cfg.ssid.ssid_len = dwrq->length; +#else + sys_cfg.ssid.ssid_len = dwrq->length - 1; +#endif + + memcpy(sys_cfg.ssid.ssid, extra, + MIN(sys_cfg.ssid.ssid_len, MLAN_MAX_SSID_LENGTH)); + if (!sys_cfg.ssid.ssid_len || sys_cfg.ssid.ssid[0] < 0x20) { + PRINTM(MERROR, "Invalid SSID - aborting set_essid\n"); + ret = -EINVAL; + goto done; + } + PRINTM(MINFO, "Requested new SSID = %s\n", + (sys_cfg.ssid.ssid_len > 0) ? (char *) sys_cfg.ssid.ssid : "NULL"); + + /* Set AP configuration */ + if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, + MLAN_ACT_SET, + MOAL_IOCTL_WAIT, + &sys_cfg)) { + PRINTM(MERROR, "Error setting AP confiruration\n"); + ret = -EFAULT; + goto done; + } + + done: + LEAVE(); + return ret; +} + +/** + * @brief Get current essid + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return 0--success, otherwise fail + */ +static int +woal_get_essid(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_uap_bss_param ap_cfg; + + ENTER(); + + if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, + MLAN_ACT_GET, + MOAL_IOCTL_WAIT, + &ap_cfg)) { + PRINTM(MERROR, "Error getting AP confiruration\n"); + LEAVE(); + return -EFAULT; + } + + if (priv->bss_started) { + dwrq->length = MIN(dwrq->length, ap_cfg.ssid.ssid_len); + memcpy(extra, ap_cfg.ssid.ssid, dwrq->length); + } else + dwrq->length = 0; + + dwrq->flags = 1; + + LEAVE(); + return 0; +} + +/** + * iwconfig settable callbacks + */ +static const iw_handler woal_handler[] = { + (iw_handler) woal_config_commit, /* SIOCSIWCOMMIT */ + (iw_handler) woal_get_name, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) woal_set_freq, /* SIOCSIWFREQ */ + (iw_handler) woal_get_freq, /* SIOCGIWFREQ */ + (iw_handler) woal_set_bss_mode, /* SIOCSIWMODE */ + (iw_handler) woal_get_bss_mode, /* SIOCGIWMODE */ + (iw_handler) NULL, /* SIOCSIWSENS */ + (iw_handler) NULL, /* SIOCGIWSENS */ + (iw_handler) NULL, /* SIOCSIWRANGE */ + (iw_handler) woal_get_range, /* SIOCGIWRANGE */ + (iw_handler) woal_set_priv, /* SIOCSIWPRIV */ + (iw_handler) NULL, /* SIOCGIWPRIV */ + (iw_handler) NULL, /* SIOCSIWSTATS */ + (iw_handler) NULL, /* SIOCGIWSTATS */ +#if WIRELESS_EXT > 15 + iw_handler_set_spy, /* SIOCSIWSPY */ + iw_handler_get_spy, /* SIOCGIWSPY */ + iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ + iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ +#else /* WIRELESS_EXT > 15 */ +#ifdef WIRELESS_SPY + (iw_handler) NULL, /* SIOCSIWSPY */ + (iw_handler) NULL, /* SIOCGIWSPY */ +#else /* WIRELESS_SPY */ + (iw_handler) NULL, /* SIOCSIWSPY */ + (iw_handler) NULL, /* SIOCGIWSPY */ +#endif /* WIRELESS_SPY */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ +#endif /* WIRELESS_EXT > 15 */ + (iw_handler) woal_set_wap, /* SIOCSIWAP */ + (iw_handler) woal_get_wap, /* SIOCGIWAP */ +#if WIRELESS_EXT >= 18 + (iw_handler) woal_set_mlme, /* SIOCSIWMLME */ +#else + (iw_handler) NULL, /* -- hole -- */ +#endif + /* (iw_handler) wlan_get_aplist, *//* SIOCGIWAPLIST */ + NULL, /* SIOCGIWAPLIST */ +#if WIRELESS_EXT > 13 + (iw_handler) NULL, /* SIOCSIWSCAN */ + (iw_handler) NULL, /* SIOCGIWSCAN */ +#else /* WIRELESS_EXT > 13 */ + (iw_handler) NULL, /* SIOCSIWSCAN */ + (iw_handler) NULL, /* SIOCGIWSCAN */ +#endif /* WIRELESS_EXT > 13 */ + (iw_handler) woal_set_essid, /* SIOCSIWESSID */ + (iw_handler) woal_get_essid, /* SIOCGIWESSID */ + (iw_handler) NULL, /* SIOCSIWNICKN */ + (iw_handler) NULL, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* SIOCSIWRATE */ + (iw_handler) NULL, /* SIOCGIWRATE */ + (iw_handler) NULL, /* SIOCSIWRTS */ + (iw_handler) NULL, /* SIOCGIWRTS */ + (iw_handler) NULL, /* SIOCSIWFRAG */ + (iw_handler) NULL, /* SIOCGIWFRAG */ + (iw_handler) NULL, /* SIOCSIWTXPOW */ + (iw_handler) NULL, /* SIOCGIWTXPOW */ + (iw_handler) NULL, /* SIOCSIWRETRY */ + (iw_handler) NULL, /* SIOCGIWRETRY */ + (iw_handler) woal_set_encode, /* SIOCSIWENCODE */ + (iw_handler) woal_get_encode, /* SIOCGIWENCODE */ + (iw_handler) NULL, /* SIOCSIWPOWER */ + (iw_handler) NULL, /* SIOCGIWPOWER */ +#if (WIRELESS_EXT >= 18) + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) woal_set_gen_ie, /* SIOCSIWGENIE */ + (iw_handler) woal_get_gen_ie, /* SIOCGIWGENIE */ + (iw_handler) woal_set_auth, /* SIOCSIWAUTH */ + (iw_handler) woal_get_auth, /* SIOCGIWAUTH */ + (iw_handler) woal_set_encode_ext, /* SIOCSIWENCODEEXT */ + (iw_handler) woal_get_encode_ext, /* SIOCGIWENCODEEXT */ +#endif /* WIRELESSS_EXT >= 18 */ +}; + +/** + * iwpriv settable callbacks + */ +static const iw_handler woal_private_handler[] = { + NULL, /* SIOCIWFIRSTPRIV */ +}; + +/******************************************************** + Global Functions +********************************************************/ + +/** wlan_handler_def */ +struct iw_handler_def woal_uap_handler_def = { + num_standard:sizeof(woal_handler) / sizeof(iw_handler), + num_private:sizeof(woal_private_handler) / sizeof(iw_handler), + num_private_args:sizeof(woal_uap_priv_args) / + sizeof(struct iw_priv_args), + standard:(iw_handler *) woal_handler, + private:(iw_handler *) woal_private_handler, + private_args:(struct iw_priv_args *) woal_uap_priv_args, +#if WIRELESS_EXT > 20 + get_wireless_stats:woal_get_uap_wireless_stats, +#endif +}; + +/** + * @brief Get wireless statistics + * + * @param dev A pointer to net_device structure + * + * @return A pointer to iw_statistics buf + */ +struct iw_statistics * +woal_get_uap_wireless_stats(struct net_device *dev) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + t_u16 wait_option = MOAL_NO_WAIT; + + ENTER(); + + /* + * Since schedule() is not allowed from an atomic context + * such as when dev_base_lock for netdevices is acquired + * for reading/writing in kernel before this call, HostCmd + * is issued in non-blocking way in such contexts and + * blocking in other cases. + */ + if (write_can_lock(&dev_base_lock) + && (!in_atomic() || current->exit_state)) + wait_option = MOAL_WSTATS_WAIT; + + priv->w_stats.qual.qual = 0; + priv->w_stats.qual.level = 0; + priv->w_stats.discard.code = 0; + priv->w_stats.status = IW_MODE_MASTER; + woal_uap_get_stats(priv, wait_option, NULL); + + LEAVE(); + return &priv->w_stats; +} diff --git a/drivers/net/wireless/sd8797/mlinux/moal_wext.c b/drivers/net/wireless/sd8797/mlinux/moal_wext.c new file mode 100644 index 000000000000..9b5ce1333ee8 --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/moal_wext.c @@ -0,0 +1,3048 @@ +/** @file moal_wext.c + * + * @brief This file contains wireless extension standard ioctl functions + * + * Copyright (C) 2008-2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +/************************************************************************ +Change log: + 10/21/2008: initial version +************************************************************************/ + +#include "moal_main.h" + +#ifdef STA_SUPPORT +/** Approximate amount of data needed to pass a scan result back to iwlist */ +#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \ + + MLAN_MAX_SSID_LENGTH \ + + IW_EV_UINT_LEN \ + + IW_EV_FREQ_LEN \ + + IW_EV_QUAL_LEN \ + + MLAN_MAX_SSID_LENGTH \ + + IW_EV_PARAM_LEN \ + + 40) /* 40 for WPAIE */ +/** Macro for minimum size of scan buffer */ +#define MIN_ACCEPTED_GET_SCAN_BUF 8000 + +/******************************************************** + Global Variables +********************************************************/ + +/******************************************************** + Local Functions +********************************************************/ +/** + * @brief This function validates a SSID as being able to be printed + * + * @param pssid SSID structure to validate + * + * @return MTRUE or MFALSE + */ +static BOOLEAN +woal_ssid_valid(mlan_802_11_ssid * pssid) +{ +#ifdef ASCII_SSID_CHECK + unsigned int ssid_idx; + + ENTER(); + + for (ssid_idx = 0; ssid_idx < pssid->ssid_len; ssid_idx++) { + if ((pssid->ssid[ssid_idx] < 0x20) || (pssid->ssid[ssid_idx] > 0x7e)) { + LEAVE(); + return MFALSE; + } + } + LEAVE(); +#endif + return MTRUE; +} + +/** + * @brief Compare two SSIDs + * + * @param ssid1 A pointer to ssid to compare + * @param ssid2 A pointer to ssid to compare + * + * @return 0--ssid is same, otherwise is different + */ +static t_s32 +woal_ssid_cmp(mlan_802_11_ssid * ssid1, mlan_802_11_ssid * ssid2) +{ + ENTER(); + + if (!ssid1 || !ssid2) { + LEAVE(); + return -1; + } + if (ssid1->ssid_len != ssid2->ssid_len) { + LEAVE(); + return -1; + } + + LEAVE(); + return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssid_len); +} + +/** + * @brief Sort Channels + * + * @param freq A pointer to iw_freq structure + * @param num Number of Channels + * + * @return N/A + */ +static inline void +woal_sort_channels(struct iw_freq *freq, int num) +{ + int i, j; + struct iw_freq temp; + + for (i = 0; i < num; i++) + for (j = i + 1; j < num; j++) + if (freq[i].i > freq[j].i) { + temp.i = freq[i].i; + temp.m = freq[i].m; + + freq[i].i = freq[j].i; + freq[i].m = freq[j].m; + + freq[j].i = temp.i; + freq[j].m = temp.m; + } +} + +/** + * @brief Convert RSSI to quality + * + * @param rssi RSSI in dBm + * + * @return Quality of the link (0-5) + */ +static t_u8 +woal_rssi_to_quality(t_s16 rssi) +{ +/** Macro for RSSI range */ +#define MOAL_RSSI_NO_SIGNAL -90 +#define MOAL_RSSI_VERY_LOW -80 +#define MOAL_RSSI_LOW -70 +#define MOAL_RSSI_GOOD -60 +#define MOAL_RSSI_VERY_GOOD -50 +#define MOAL_RSSI_INVALID 0 + if (rssi <= MOAL_RSSI_NO_SIGNAL || rssi == MOAL_RSSI_INVALID) + return 0; + else if (rssi <= MOAL_RSSI_VERY_LOW) + return 1; + else if (rssi <= MOAL_RSSI_LOW) + return 2; + else if (rssi <= MOAL_RSSI_GOOD) + return 3; + else if (rssi <= MOAL_RSSI_VERY_GOOD) + return 4; + else + return 5; +} + +/** + * @brief Set Adapter Node Name + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_nick(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + ENTER(); + /* + * Check the size of the string + */ + if (dwrq->length > 16) { + LEAVE(); + return -E2BIG; + } + memset(priv->nick_name, 0, sizeof(priv->nick_name)); + memcpy(priv->nick_name, extra, dwrq->length); + LEAVE(); + return 0; +} + +/** + * @brief Get Adapter Node Name + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return 0 --success + */ +static int +woal_get_nick(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + ENTER(); + /* + * Get the Nick Name saved + */ + strncpy(extra, (char *) priv->nick_name, 16); + extra[16] = '\0'; + /* + * If none, we may want to get the one that was set + */ + + /* + * Push it out ! + */ + dwrq->length = strlen(extra) + 1; + LEAVE(); + return 0; +} + +/** + * @brief Commit handler: called after a bunch of SET operations + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param cwrq A pointer to char buffer + * @param extra A pointer to extra data buf + * + * @return 0 --success + */ +static int +woal_config_commit(struct net_device *dev, + struct iw_request_info *info, char *cwrq, char *extra) +{ + ENTER(); + + LEAVE(); + return 0; +} + +/** + * @brief Get name + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param cwrq A pointer to char buffer + * @param extra A pointer to extra data buf + * + * @return 0 --success + */ +static int +woal_get_name(struct net_device *dev, struct iw_request_info *info, + char *cwrq, char *extra) +{ + ENTER(); + strcpy(cwrq, "IEEE 802.11-DS"); + LEAVE(); + return 0; +} + +/** + * @brief Set frequency + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param fwrq A pointer to iw_freq structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_freq(struct net_device *dev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + int ret = 0; + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_ds_bss *bss = NULL; + mlan_ioctl_req *req = NULL; + + ENTER(); + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + bss = (mlan_ds_bss *) req->pbuf; + /* + * If setting by frequency, convert to a channel + */ + if (fwrq->e == 1) { + long f = fwrq->m / 100000; + bss->param.bss_chan.freq = f; + } else + bss->param.bss_chan.channel = fwrq->m; + + bss->sub_command = MLAN_OID_BSS_CHANNEL; + req->req_id = MLAN_IOCTL_BSS; + req->action = MLAN_ACT_SET; + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + if (MLAN_STATUS_SUCCESS != + woal_change_adhoc_chan(priv, bss->param.bss_chan.channel)) + ret = -EFAULT; + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Get frequency + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param fwrq A pointer to iw_freq structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_get_freq(struct net_device *dev, struct iw_request_info *info, + struct iw_freq *fwrq, char *extra) +{ + int ret = 0; + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_ds_bss *bss = NULL; + mlan_ioctl_req *req = NULL; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + bss = (mlan_ds_bss *) req->pbuf; + bss->sub_command = MLAN_OID_BSS_CHANNEL; + req->req_id = MLAN_IOCTL_BSS; + req->action = MLAN_ACT_GET; + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + fwrq->m = (long) bss->param.bss_chan.freq * 100000; + fwrq->i = (long) bss->param.bss_chan.channel; + fwrq->e = 1; + fwrq->flags = IW_FREQ_FIXED; + done: + if (req) + kfree(req); + + LEAVE(); + return ret; +} + +/** + * @brief Set wlan mode + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param uwrq Wireless mode to set + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_bss_mode(struct net_device *dev, struct iw_request_info *info, + t_u32 * uwrq, char *extra) +{ + int ret = 0; + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_ds_bss *bss = NULL; + mlan_ioctl_req *req = NULL; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + bss = (mlan_ds_bss *) req->pbuf; + bss->sub_command = MLAN_OID_BSS_MODE; + req->req_id = MLAN_IOCTL_BSS; + req->action = MLAN_ACT_SET; + + switch (*uwrq) { + case IW_MODE_INFRA: + bss->param.bss_mode = MLAN_BSS_MODE_INFRA; + break; + case IW_MODE_ADHOC: + bss->param.bss_mode = MLAN_BSS_MODE_IBSS; + break; + case IW_MODE_AUTO: + bss->param.bss_mode = MLAN_BSS_MODE_AUTO; + break; + default: + ret = -EINVAL; + break; + } + if (ret) + goto done; + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Get current BSSID + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param awrq A pointer to sockaddr structure + * @param extra A pointer to extra data buf + * + * @return 0 --success + */ +static int +woal_get_wap(struct net_device *dev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + int ret = 0; + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_bss_info bss_info; + + ENTER(); + + memset(&bss_info, 0, sizeof(bss_info)); + + woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info); + + if (bss_info.media_connected == MTRUE) { + memcpy(awrq->sa_data, &bss_info.bssid, MLAN_MAC_ADDR_LENGTH); + } else { + memset(awrq->sa_data, 0, MLAN_MAC_ADDR_LENGTH); + } + awrq->sa_family = ARPHRD_ETHER; + + LEAVE(); + return ret; +} + +/** + * @brief Connect to the AP or Ad-hoc Network with specific bssid + * + * NOTE: Scan should be issued by application before this function is called + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param awrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_wap(struct net_device *dev, struct iw_request_info *info, + struct sockaddr *awrq, char *extra) +{ + int ret = 0; + const t_u8 bcast[MLAN_MAC_ADDR_LENGTH] = { 255, 255, 255, 255, 255, 255 }; + const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = { 0, 0, 0, 0, 0, 0 }; + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_ssid_bssid ssid_bssid; + mlan_bss_info bss_info; + + ENTER(); + + if (awrq->sa_family != ARPHRD_ETHER) { + ret = -EINVAL; + goto done; + } + + PRINTM(MINFO, "ASSOC: WAP: sa_data: %02x:%02x:%02x:%02x:%02x:%02x\n", + (t_u8) awrq->sa_data[0], (t_u8) awrq->sa_data[1], + (t_u8) awrq->sa_data[2], (t_u8) awrq->sa_data[3], + (t_u8) awrq->sa_data[4], (t_u8) awrq->sa_data[5]); + + if (MLAN_STATUS_SUCCESS != + woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) { + ret = -EFAULT; + goto done; + } +#ifdef REASSOCIATION + /* Cancel re-association */ + priv->reassoc_required = MFALSE; +#endif + + /* zero_mac means disconnect */ + if (!memcmp(zero_mac, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) { + woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL); + goto done; + } + + /* Broadcast MAC means search for best network */ + memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid)); + + if (memcmp(bcast, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) { + /* Check if we are already assoicated to the AP */ + if (bss_info.media_connected == MTRUE) { + if (!memcmp(awrq->sa_data, &bss_info.bssid, ETH_ALEN)) + goto done; + /* disconnect before try to assoicate to the new AP */ + woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL); + } + memcpy(&ssid_bssid.bssid, awrq->sa_data, ETH_ALEN); + } + + if (MLAN_STATUS_SUCCESS != woal_find_best_network(priv, + MOAL_IOCTL_WAIT, + &ssid_bssid)) { + PRINTM(MERROR, "ASSOC: WAP: MAC address not found in BSSID List\n"); + ret = -ENETUNREACH; + goto done; + } + /* Zero SSID implies use BSSID to connect */ + memset(&ssid_bssid.ssid, 0, sizeof(mlan_802_11_ssid)); + if (MLAN_STATUS_SUCCESS != woal_bss_start(priv, + MOAL_IOCTL_WAIT, &ssid_bssid)) { + ret = -EFAULT; + goto done; + } +#ifdef REASSOCIATION + memset(&bss_info, 0, sizeof(bss_info)); + if (MLAN_STATUS_SUCCESS != woal_get_bss_info(priv, + MOAL_IOCTL_WAIT, &bss_info)) { + ret = -EFAULT; + goto done; + } + memcpy(&priv->prev_ssid_bssid.ssid, &bss_info.ssid, + sizeof(mlan_802_11_ssid)); + memcpy(&priv->prev_ssid_bssid.bssid, &bss_info.bssid, MLAN_MAC_ADDR_LENGTH); +#endif /* REASSOCIATION */ + + done: + + LEAVE(); + return ret; +} + +/** + * @brief Get wlan mode + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param uwrq A pointer to t_u32 string + * @param extra A pointer to extra data buf + * + * @return 0 --success + */ +static int +woal_get_bss_mode(struct net_device *dev, struct iw_request_info *info, + t_u32 * uwrq, char *extra) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + ENTER(); + *uwrq = woal_get_mode(priv, MOAL_IOCTL_WAIT); + LEAVE(); + return 0; +} + +/** + * @brief Set sensitivity + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return 0 --success + */ +static int +woal_set_sens(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + + ENTER(); + + LEAVE(); + return ret; +} + +/** + * @brief Get sensitivity + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return -1 + */ +static int +woal_get_sens(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = -1; + + ENTER(); + + LEAVE(); + return ret; +} + +/** + * @brief Set Tx power + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_txpow(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_power_cfg_t power_cfg; + + ENTER(); + if (vwrq->disabled) { + woal_set_radio(priv, 0); + goto done; + } + woal_set_radio(priv, 1); + + if (!vwrq->fixed) + power_cfg.is_power_auto = 1; + else { + power_cfg.is_power_auto = 0; + power_cfg.power_level = vwrq->value; + } + + if (MLAN_STATUS_SUCCESS != + woal_set_get_tx_power(priv, MLAN_ACT_SET, &power_cfg)) { + ret = -EFAULT; + goto done; + } + + done: + LEAVE(); + return ret; +} + +/** + * @brief Get Tx power + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_get_txpow(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_power_cfg_t power_cfg; + mlan_bss_info bss_info; + + ENTER(); + + memset(&power_cfg, 0, sizeof(mlan_power_cfg_t)); + memset(&bss_info, 0, sizeof(bss_info)); + woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info); + + if (MLAN_STATUS_SUCCESS != + woal_set_get_tx_power(priv, MLAN_ACT_GET, &power_cfg)) { + ret = -EFAULT; + goto done; + } + + vwrq->value = power_cfg.power_level; + if (power_cfg.is_power_auto) + vwrq->fixed = 0; + else + vwrq->fixed = 1; + if (bss_info.radio_on) { + vwrq->disabled = 0; + vwrq->flags = IW_TXPOW_DBM; + } else { + vwrq->disabled = 1; + } + + done: + LEAVE(); + return ret; +} + +/** + * @brief Set power management + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return MLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int +woal_set_power(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0, disabled; + moal_private *priv = (moal_private *) netdev_priv(dev); + + ENTER(); + + disabled = vwrq->disabled; + + if (MLAN_STATUS_SUCCESS != woal_set_get_power_mgmt(priv, + MLAN_ACT_SET, &disabled, + vwrq->flags)) { + ret = -EFAULT; + } + + LEAVE(); + return ret; +} + +/** + * @brief Get power management + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return MLAN_STATUS_SUCCESS --success, otherwise fail + */ +static int +woal_get_power(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0, ps_mode; + moal_private *priv = (moal_private *) netdev_priv(dev); + + ENTER(); + + if (MLAN_STATUS_SUCCESS != woal_set_get_power_mgmt(priv, + MLAN_ACT_GET, &ps_mode, + 0)) { + ret = -EFAULT; + } + + if (ps_mode) + vwrq->disabled = 0; + else + vwrq->disabled = 1; + + vwrq->value = 0; + + LEAVE(); + return ret; +} + +/** + * @brief Set Tx retry count + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_retry(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0, retry_val = vwrq->value; + moal_private *priv = (moal_private *) netdev_priv(dev); + + ENTER(); + + if (vwrq->flags == IW_RETRY_LIMIT) { + /* + * The MAC has a 4-bit Total_Tx_Count register + * Total_Tx_Count = 1 + Tx_Retry_Count + */ + + if (MLAN_STATUS_SUCCESS != + woal_set_get_retry(priv, MLAN_ACT_SET, + MOAL_IOCTL_WAIT, &retry_val)) { + ret = -EFAULT; + goto done; + } + } else { + ret = -EOPNOTSUPP; + goto done; + } + + done: + LEAVE(); + return ret; +} + +/** + * @brief Get Tx retry count + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_get_retry(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int retry_val, ret = 0; + moal_private *priv = (moal_private *) netdev_priv(dev); + + ENTER(); + + if (MLAN_STATUS_SUCCESS != + woal_set_get_retry(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT, &retry_val)) { + ret = -EFAULT; + goto done; + } + + vwrq->disabled = 0; + if (!vwrq->flags) { + vwrq->flags = IW_RETRY_LIMIT; + /* Get Tx retry count */ + vwrq->value = retry_val; + } + + done: + LEAVE(); + return ret; +} + +/** + * @brief Set encryption key + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_encode(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + int ret = 0; + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_ds_sec_cfg *sec = NULL; + mlan_ioctl_req *req = NULL; + int index = 0; + t_u32 auth_mode = 0; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + sec = (mlan_ds_sec_cfg *) req->pbuf; + sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY; + req->req_id = MLAN_IOCTL_SEC_CFG; + req->action = MLAN_ACT_SET; + + /* Check index */ + index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + if (index > 3) { + PRINTM(MERROR, "Key index #%d out of range\n", index); + ret = -EINVAL; + goto done; + } + + sec->param.encrypt_key.key_len = 0; + if (!(dwrq->flags & IW_ENCODE_NOKEY) && dwrq->length) { + if (dwrq->length > MAX_WEP_KEY_SIZE) { + PRINTM(MERROR, "Key length (%d) out of range\n", dwrq->length); + ret = -EINVAL; + goto done; + } + if (index < 0) + sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_DEFAULT; + else + sec->param.encrypt_key.key_index = index; + memcpy(sec->param.encrypt_key.key_material, extra, dwrq->length); + /* Set the length */ + if (dwrq->length > MIN_WEP_KEY_SIZE) + sec->param.encrypt_key.key_len = MAX_WEP_KEY_SIZE; + else + sec->param.encrypt_key.key_len = MIN_WEP_KEY_SIZE; + } else { + /* + * No key provided so it is either enable key, + * on or off + */ + if (dwrq->flags & IW_ENCODE_DISABLED) { + PRINTM(MINFO, "*** iwconfig mlanX key off ***\n"); + sec->param.encrypt_key.key_disable = MTRUE; + } else { + /* + * iwconfig mlanX key [n] + * iwconfig mlanX key on + * iwconfig mlanX key open + * iwconfig mlanX key restricted + * Do we want to just set the transmit key index ? + */ + if (index < 0) { + PRINTM(MINFO, "*** iwconfig mlanX key on ***\n"); + sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_DEFAULT; + } else + sec->param.encrypt_key.key_index = index; + sec->param.encrypt_key.is_current_wep_key = MTRUE; + } + } + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + if (dwrq->flags & (IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN)) { + switch (dwrq->flags & 0xf000) { + case IW_ENCODE_RESTRICTED: + /* iwconfig mlanX restricted key [1] */ + auth_mode = MLAN_AUTH_MODE_SHARED; + PRINTM(MINFO, "Auth mode restricted!\n"); + break; + case IW_ENCODE_OPEN: + /* iwconfig mlanX key [2] open */ + auth_mode = MLAN_AUTH_MODE_OPEN; + PRINTM(MINFO, "Auth mode open!\n"); + break; + case IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN: + default: + /* iwconfig mlanX key [2] open restricted */ + auth_mode = MLAN_AUTH_MODE_AUTO; + PRINTM(MINFO, "Auth mode auto!\n"); + break; + } + if (MLAN_STATUS_SUCCESS != + woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_mode)) + ret = -EFAULT; + } + done: + if (req) + kfree(req); + + LEAVE(); + return ret; +} + +/** + * @brief Get encryption key + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_get_encode(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + int ret = 0; + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_ds_sec_cfg *sec = NULL; + mlan_ioctl_req *req = NULL; + t_u32 auth_mode; + int index = (dwrq->flags & IW_ENCODE_INDEX); + + ENTER(); + if (index < 0 || index > 4) { + PRINTM(MERROR, "Key index #%d out of range\n", index); + ret = -EINVAL; + goto done; + } + if (MLAN_STATUS_SUCCESS != + woal_get_auth_mode(priv, MOAL_IOCTL_WAIT, &auth_mode)) { + ret = -EFAULT; + goto done; + } + dwrq->flags = 0; + /* + * Check encryption mode + */ + switch (auth_mode) { + case MLAN_AUTH_MODE_OPEN: + dwrq->flags = IW_ENCODE_OPEN; + break; + + case MLAN_AUTH_MODE_SHARED: + case MLAN_AUTH_MODE_NETWORKEAP: + dwrq->flags = IW_ENCODE_RESTRICTED; + break; + + case MLAN_AUTH_MODE_AUTO: + dwrq->flags = IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED; + break; + + default: + dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN; + break; + } + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + sec = (mlan_ds_sec_cfg *) req->pbuf; + sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY; + req->req_id = MLAN_IOCTL_SEC_CFG; + req->action = MLAN_ACT_GET; + + if (!index) + sec->param.encrypt_key.key_index = MLAN_KEY_INDEX_DEFAULT; + else + sec->param.encrypt_key.key_index = index - 1; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + memset(extra, 0, 16); + if (sec->param.encrypt_key.key_len) { + memcpy(extra, sec->param.encrypt_key.key_material, + sec->param.encrypt_key.key_len); + dwrq->length = sec->param.encrypt_key.key_len; + dwrq->flags |= (sec->param.encrypt_key.key_index + 1); + dwrq->flags &= ~IW_ENCODE_DISABLED; + } else if (sec->param.encrypt_key.key_disable) + dwrq->flags |= IW_ENCODE_DISABLED; + else + dwrq->flags &= ~IW_ENCODE_DISABLED; + + dwrq->flags |= IW_ENCODE_NOKEY; + done: + if (req) + kfree(req); + + LEAVE(); + return ret; +} + +/** + * @brief Set data rate + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_rate(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_rate_cfg_t rate_cfg; + + ENTER(); + + if (vwrq->value == -1) { + rate_cfg.is_rate_auto = 1; + } else { + rate_cfg.is_rate_auto = 0; + rate_cfg.rate_type = MLAN_RATE_VALUE; + rate_cfg.rate = vwrq->value / 500000; + } + if (MLAN_STATUS_SUCCESS != woal_set_get_data_rate(priv, + MLAN_ACT_SET, + &rate_cfg)) { + ret = -EFAULT; + } + + LEAVE(); + return ret; +} + +/** + * @brief Get data rate + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_get_rate(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_rate_cfg_t rate_cfg; + + ENTER(); + + if (MLAN_STATUS_SUCCESS != woal_set_get_data_rate(priv, + MLAN_ACT_GET, + &rate_cfg)) { + ret = -EFAULT; + goto done; + } + + if (rate_cfg.is_rate_auto) + vwrq->fixed = 0; + else + vwrq->fixed = 1; + vwrq->value = rate_cfg.rate * 500000; + done: + LEAVE(); + return ret; +} + +/** + * @brief Set RTS threshold + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_rts(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + moal_private *priv = (moal_private *) netdev_priv(dev); + int rthr = vwrq->value; + + ENTER(); + + if (vwrq->disabled) { + rthr = MLAN_RTS_MAX_VALUE; + } else { + if (rthr < MLAN_RTS_MIN_VALUE || rthr > MLAN_RTS_MAX_VALUE) { + ret = -EINVAL; + goto done; + } + } + + if (MLAN_STATUS_SUCCESS != + woal_set_get_rts(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, &rthr)) { + ret = -EFAULT; + goto done; + } + + done: + LEAVE(); + return ret; +} + +/** + * @brief Get RTS threshold + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_get_rts(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int rthr, ret = 0; + moal_private *priv = (moal_private *) netdev_priv(dev); + + ENTER(); + + if (MLAN_STATUS_SUCCESS != + woal_set_get_rts(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT, &rthr)) { + ret = -EFAULT; + goto done; + } + + vwrq->value = rthr; + vwrq->disabled = ((vwrq->value < MLAN_RTS_MIN_VALUE) + || (vwrq->value > MLAN_RTS_MAX_VALUE)); + vwrq->fixed = 1; + + done: + LEAVE(); + return ret; +} + +/** + * @brief Set Fragment threshold + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_frag(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + moal_private *priv = (moal_private *) netdev_priv(dev); + int fthr = vwrq->value; + + ENTER(); + + if (vwrq->disabled) { + fthr = MLAN_FRAG_MAX_VALUE; + } else { + if (fthr < MLAN_FRAG_MIN_VALUE || fthr > MLAN_FRAG_MAX_VALUE) { + ret = -EINVAL; + goto done; + } + } + + if (MLAN_STATUS_SUCCESS != + woal_set_get_frag(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, &fthr)) { + ret = -EFAULT; + goto done; + } + + done: + LEAVE(); + return ret; +} + +/** + * @brief Get Fragment threshold + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_get_frag(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0, fthr; + moal_private *priv = (moal_private *) netdev_priv(dev); + + ENTER(); + + if (MLAN_STATUS_SUCCESS != + woal_set_get_frag(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT, &fthr)) { + ret = -EFAULT; + goto done; + } + + vwrq->value = fthr; + vwrq->disabled = ((vwrq->value < MLAN_FRAG_MIN_VALUE) + || (vwrq->value > MLAN_FRAG_MAX_VALUE)); + vwrq->fixed = 1; + + done: + LEAVE(); + return ret; +} + +#if (WIRELESS_EXT >= 18) +/** + * @brief Get IE + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_get_gen_ie(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + int ret = 0; + moal_private *priv = (moal_private *) netdev_priv(dev); + int copy_size = 0, ie_len; + t_u8 ie[MAX_IE_SIZE]; + + ENTER(); + + if (MLAN_STATUS_SUCCESS != + woal_set_get_gen_ie(priv, MLAN_ACT_GET, ie, &ie_len)) { + ret = -EFAULT; + goto done; + } + + copy_size = MIN(ie_len, dwrq->length); + memcpy(extra, ie, copy_size); + dwrq->length = copy_size; + + done: + LEAVE(); + return ret; +} + +/** + * @brief Set IE + * + * Pass an opaque block of data, expected to be IEEE IEs, to the driver + * for eventual passthrough to the firmware in an associate/join + * (and potentially start) command. + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_gen_ie(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + int ret = 0; + moal_private *priv = (moal_private *) netdev_priv(dev); + int ie_len = dwrq->length; + const t_u8 wps_oui[] = { 0x00, 0x50, 0xf2, 0x04 }; + mlan_ds_wps_cfg *pwps = NULL; + mlan_ioctl_req *req = NULL; + + ENTER(); + + /* extra + 2 to skip element id and length */ + if (!memcmp((t_u8 *) (extra + 2), wps_oui, sizeof(wps_oui))) { + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wps_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + pwps = (mlan_ds_wps_cfg *) req->pbuf; + req->req_id = MLAN_IOCTL_WPS_CFG; + req->action = MLAN_ACT_SET; + pwps->sub_command = MLAN_OID_WPS_CFG_SESSION; + pwps->param.wps_session = MLAN_WPS_CFG_SESSION_START; + + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + } + + if (MLAN_STATUS_SUCCESS != + woal_set_get_gen_ie(priv, MLAN_ACT_SET, (t_u8 *) extra, &ie_len)) { + ret = -EFAULT; + goto done; + } + + done: + if (req) + kfree(req); + + LEAVE(); + return ret; +} + +/** + * @brief Extended version of encoding configuration + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_encode_ext(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; + moal_private *priv = (moal_private *) netdev_priv(dev); + int key_index; + t_u8 *pkey_material = NULL; + mlan_ioctl_req *req = NULL; + mlan_ds_sec_cfg *sec = NULL; + int ret = 0; + + ENTER(); + key_index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + if (key_index < 0 || key_index > 3) { + ret = -EINVAL; + goto done; + } + if (ext->key_len > (dwrq->length - sizeof(struct iw_encode_ext))) { + ret = -EINVAL; + goto done; + } + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + sec = (mlan_ds_sec_cfg *) req->pbuf; + sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY; + req->req_id = MLAN_IOCTL_SEC_CFG; + req->action = MLAN_ACT_SET; + pkey_material = (t_u8 *) (ext + 1); + sec->param.encrypt_key.key_len = ext->key_len; + memcpy(sec->param.encrypt_key.mac_addr, (u8 *) ext->addr.sa_data, ETH_ALEN); + /* Disable and Remove Key */ + if ((dwrq->flags & IW_ENCODE_DISABLED) && !ext->key_len) { + sec->param.encrypt_key.key_remove = MTRUE; + sec->param.encrypt_key.key_index = key_index; + sec->param.encrypt_key.key_flags = KEY_FLAG_REMOVE_KEY; + PRINTM(MIOCTL, + "Remove key key_index=%d, dwrq->flags=0x%x %02x:%02x:%02x:%02x:%02x:%02x\n", + key_index, dwrq->flags, sec->param.encrypt_key.mac_addr[0], + sec->param.encrypt_key.mac_addr[1], + sec->param.encrypt_key.mac_addr[2], + sec->param.encrypt_key.mac_addr[3], + sec->param.encrypt_key.mac_addr[4], + sec->param.encrypt_key.mac_addr[5]); + } else if (ext->key_len <= MAX_WEP_KEY_SIZE) { + /* Set WEP key */ + sec->param.encrypt_key.key_index = key_index; + sec->param.encrypt_key.key_flags = ext->ext_flags; + memcpy(sec->param.encrypt_key.key_material, pkey_material, + ext->key_len); + if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) + sec->param.encrypt_key.is_current_wep_key = MTRUE; + } else { + /* Set WPA key */ + sec->param.encrypt_key.key_index = key_index; + sec->param.encrypt_key.key_flags = ext->ext_flags; + if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { + memcpy(sec->param.encrypt_key.pn, (t_u8 *) ext->rx_seq, + SEQ_MAX_SIZE); + DBG_HEXDUMP(MCMD_D, "Rx PN", sec->param.encrypt_key.pn, + SEQ_MAX_SIZE); + } + if (ext->ext_flags & IW_ENCODE_EXT_TX_SEQ_VALID) { + memcpy(sec->param.encrypt_key.pn, (t_u8 *) ext->tx_seq, + SEQ_MAX_SIZE); + DBG_HEXDUMP(MCMD_D, "Tx PN", sec->param.encrypt_key.pn, + SEQ_MAX_SIZE); + } + memcpy(sec->param.encrypt_key.key_material, pkey_material, + ext->key_len); + PRINTM(MIOCTL, + "set wpa key key_index=%d, key_len=%d key_flags=0x%x %02x:%02x:%02x:%02x:%02x:%02x\n", + key_index, ext->key_len, sec->param.encrypt_key.key_flags, + sec->param.encrypt_key.mac_addr[0], + sec->param.encrypt_key.mac_addr[1], + sec->param.encrypt_key.mac_addr[2], + sec->param.encrypt_key.mac_addr[3], + sec->param.encrypt_key.mac_addr[4], + sec->param.encrypt_key.mac_addr[5]); + DBG_HEXDUMP(MCMD_D, "wpa key", pkey_material, ext->key_len); +#define IW_ENCODE_ALG_SMS4 0x20 + /* Set WAPI key */ + if (ext->alg == IW_ENCODE_ALG_SMS4) { + sec->param.encrypt_key.is_wapi_key = MTRUE; + memcpy(sec->param.encrypt_key.pn, (t_u8 *) ext->tx_seq, + SEQ_MAX_SIZE); + memcpy(&sec->param.encrypt_key.pn[SEQ_MAX_SIZE], + (t_u8 *) ext->rx_seq, SEQ_MAX_SIZE); + DBG_HEXDUMP(MCMD_D, "WAPI PN", sec->param.encrypt_key.pn, PN_SIZE); + } + } + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) + ret = -EFAULT; + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Extended version of encoding configuration + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return -EOPNOTSUPP + */ +static int +woal_get_encode_ext(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + ENTER(); + LEAVE(); + return -EOPNOTSUPP; +} + +/** + * @brief Request MLME operation + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return 0--success, otherwise fail + */ +static int +woal_set_mlme(struct net_device *dev, + struct iw_request_info *info, struct iw_point *dwrq, char *extra) +{ + struct iw_mlme *mlme = (struct iw_mlme *) extra; + moal_private *priv = (moal_private *) netdev_priv(dev); + int ret = 0; + + ENTER(); + if ((mlme->cmd == IW_MLME_DEAUTH) || (mlme->cmd == IW_MLME_DISASSOC)) { + + if (MLAN_STATUS_SUCCESS != + woal_disconnect(priv, MOAL_IOCTL_WAIT, (t_u8 *) mlme->addr.sa_data)) + ret = -EFAULT; + } + LEAVE(); + return ret; +} + +/** @brief Set authentication mode parameters + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_auth(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + moal_private *priv = (moal_private *) netdev_priv(dev); + t_u32 auth_mode = 0; + t_u32 encrypt_mode = 0; + ENTER(); + + switch (vwrq->flags & IW_AUTH_INDEX) { + case IW_AUTH_CIPHER_PAIRWISE: + case IW_AUTH_CIPHER_GROUP: + if (vwrq->value & IW_AUTH_CIPHER_NONE) + encrypt_mode = MLAN_ENCRYPTION_MODE_NONE; + else if (vwrq->value & IW_AUTH_CIPHER_WEP40) + encrypt_mode = MLAN_ENCRYPTION_MODE_WEP40; + else if (vwrq->value & IW_AUTH_CIPHER_WEP104) + encrypt_mode = MLAN_ENCRYPTION_MODE_WEP104; + else if (vwrq->value & IW_AUTH_CIPHER_TKIP) + encrypt_mode = MLAN_ENCRYPTION_MODE_TKIP; + else if (vwrq->value & IW_AUTH_CIPHER_CCMP) + encrypt_mode = MLAN_ENCRYPTION_MODE_CCMP; + if (MLAN_STATUS_SUCCESS != + woal_set_encrypt_mode(priv, MOAL_IOCTL_WAIT, encrypt_mode)) + ret = -EFAULT; + break; + case IW_AUTH_80211_AUTH_ALG: + switch (vwrq->value) { + case IW_AUTH_ALG_SHARED_KEY: + PRINTM(MINFO, "Auth mode shared key!\n"); + auth_mode = MLAN_AUTH_MODE_SHARED; + break; + case IW_AUTH_ALG_LEAP: + PRINTM(MINFO, "Auth mode LEAP!\n"); + auth_mode = MLAN_AUTH_MODE_NETWORKEAP; + break; + case IW_AUTH_ALG_OPEN_SYSTEM: + PRINTM(MINFO, "Auth mode open!\n"); + auth_mode = MLAN_AUTH_MODE_OPEN; + break; + case IW_AUTH_ALG_SHARED_KEY | IW_AUTH_ALG_OPEN_SYSTEM: + default: + PRINTM(MINFO, "Auth mode auto!\n"); + auth_mode = MLAN_AUTH_MODE_AUTO; + break; + } + if (MLAN_STATUS_SUCCESS != + woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_mode)) + ret = -EFAULT; + break; + case IW_AUTH_WPA_ENABLED: + if (MLAN_STATUS_SUCCESS != + woal_set_wpa_enable(priv, MOAL_IOCTL_WAIT, vwrq->value)) + ret = -EFAULT; + break; +#define IW_AUTH_WAPI_ENABLED 0x20 + case IW_AUTH_WAPI_ENABLED: + if (MLAN_STATUS_SUCCESS != + woal_set_wapi_enable(priv, MOAL_IOCTL_WAIT, vwrq->value)) + ret = -EFAULT; + break; + case IW_AUTH_WPA_VERSION: + /* set WPA_VERSION_DISABLED/VERSION_WPA/VERSION_WP2 */ + priv->wpa_version = vwrq->value; + break; + case IW_AUTH_KEY_MGMT: + /* set KEY_MGMT_802_1X/KEY_MGMT_PSK */ + priv->key_mgmt = vwrq->value; + break; + case IW_AUTH_TKIP_COUNTERMEASURES: + case IW_AUTH_DROP_UNENCRYPTED: + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + case IW_AUTH_ROAMING_CONTROL: + case IW_AUTH_PRIVACY_INVOKED: + break; + default: + ret = -EOPNOTSUPP; + break; + } + LEAVE(); + return ret; +} + +/** + * @brief Get authentication mode parameters + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_get_auth(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + moal_private *priv = (moal_private *) netdev_priv(dev); + t_u32 encrypt_mode = 0; + t_u32 auth_mode; + t_u32 wpa_enable; + ENTER(); + switch (vwrq->flags & IW_AUTH_INDEX) { + case IW_AUTH_CIPHER_PAIRWISE: + case IW_AUTH_CIPHER_GROUP: + if (MLAN_STATUS_SUCCESS != + woal_get_encrypt_mode(priv, MOAL_IOCTL_WAIT, &encrypt_mode)) + ret = -EFAULT; + else { + if (encrypt_mode == MLAN_ENCRYPTION_MODE_NONE) + vwrq->value = IW_AUTH_CIPHER_NONE; + else if (encrypt_mode == MLAN_ENCRYPTION_MODE_WEP40) + vwrq->value = IW_AUTH_CIPHER_WEP40; + else if (encrypt_mode == MLAN_ENCRYPTION_MODE_TKIP) + vwrq->value = IW_AUTH_CIPHER_TKIP; + else if (encrypt_mode == MLAN_ENCRYPTION_MODE_CCMP) + vwrq->value = IW_AUTH_CIPHER_CCMP; + else if (encrypt_mode == MLAN_ENCRYPTION_MODE_WEP104) + vwrq->value = IW_AUTH_CIPHER_WEP104; + } + break; + case IW_AUTH_80211_AUTH_ALG: + if (MLAN_STATUS_SUCCESS != + woal_get_auth_mode(priv, MOAL_IOCTL_WAIT, &auth_mode)) + ret = -EFAULT; + else { + if (auth_mode == MLAN_AUTH_MODE_SHARED) + vwrq->value = IW_AUTH_ALG_SHARED_KEY; + else if (auth_mode == MLAN_AUTH_MODE_NETWORKEAP) + vwrq->value = IW_AUTH_ALG_LEAP; + else + vwrq->value = IW_AUTH_ALG_OPEN_SYSTEM; + } + break; + case IW_AUTH_WPA_ENABLED: + if (MLAN_STATUS_SUCCESS != + woal_get_wpa_enable(priv, MOAL_IOCTL_WAIT, &wpa_enable)) + ret = -EFAULT; + else + vwrq->value = wpa_enable; + break; + case IW_AUTH_WPA_VERSION: + vwrq->value = priv->wpa_version; + break; + case IW_AUTH_KEY_MGMT: + vwrq->value = priv->key_mgmt; + break; + case IW_AUTH_TKIP_COUNTERMEASURES: + case IW_AUTH_DROP_UNENCRYPTED: + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + case IW_AUTH_ROAMING_CONTROL: + case IW_AUTH_PRIVACY_INVOKED: + default: + ret = -EOPNOTSUPP; + goto done; + } + + done: + LEAVE(); + return ret; +} + +/** + * @brief Set PMKSA Cache + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return -EOPNOTSUPP + */ +static int +woal_set_pmksa(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + ENTER(); + LEAVE(); + return -EOPNOTSUPP; +} + +#endif /* WE >= 18 */ + +/* Data rate listing + * MULTI_BANDS: + * abg a b b/g + * Infra G(12) A(8) B(4) G(12) + * Adhoc A+B(12) A(8) B(4) B(4) + * non-MULTI_BANDS: + b b/g + * Infra B(4) G(12) + * Adhoc B(4) B(4) + */ +/** + * @brief Get Range Info + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_get_range(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + int i; + moal_private *priv = (moal_private *) netdev_priv(dev); + struct iw_range *range = (struct iw_range *) extra; + moal_802_11_rates rates; + mlan_chan_list *pchan_list = NULL; + mlan_bss_info bss_info; + + ENTER(); + + if (!(pchan_list = kmalloc(sizeof(mlan_chan_list), GFP_KERNEL))) { + LEAVE(); + return -ENOMEM; + } + + dwrq->length = sizeof(struct iw_range); + memset(range, 0, sizeof(struct iw_range)); + + range->min_nwid = 0; + range->max_nwid = 0; + + memset(&rates, 0, sizeof(rates)); + woal_get_data_rates(priv, MOAL_IOCTL_WAIT, &rates); + range->num_bitrates = rates.num_of_rates; + + for (i = 0; i < MIN(range->num_bitrates, IW_MAX_BITRATES) && rates.rates[i]; + i++) { + range->bitrate[i] = (rates.rates[i] & 0x7f) * 500000; + } + range->num_bitrates = i; + PRINTM(MINFO, "IW_MAX_BITRATES=%d num_bitrates=%d\n", IW_MAX_BITRATES, + range->num_bitrates); + + range->num_frequency = 0; + + memset(pchan_list, 0, sizeof(mlan_chan_list)); + + woal_get_channel_list(priv, MOAL_IOCTL_WAIT, pchan_list); + + range->num_frequency = MIN(pchan_list->num_of_chan, IW_MAX_FREQUENCIES); + + for (i = 0; i < range->num_frequency; i++) { + range->freq[i].i = (long) pchan_list->cf[i].channel; + range->freq[i].m = (long) pchan_list->cf[i].freq * 100000; + range->freq[i].e = 1; + } + kfree(pchan_list); + + PRINTM(MINFO, "IW_MAX_FREQUENCIES=%d num_frequency=%d\n", + IW_MAX_FREQUENCIES, range->num_frequency); + + range->num_channels = range->num_frequency; + + woal_sort_channels(&range->freq[0], range->num_frequency); + + /* + * Set an indication of the max TCP throughput in bit/s that we can + * expect using this interface + */ + if (i > 2) + range->throughput = 5000 * 1000; + else + range->throughput = 1500 * 1000; + + range->min_rts = MLAN_RTS_MIN_VALUE; + range->max_rts = MLAN_RTS_MAX_VALUE; + range->min_frag = MLAN_FRAG_MIN_VALUE; + range->max_frag = MLAN_FRAG_MAX_VALUE; + + range->encoding_size[0] = 5; + range->encoding_size[1] = 13; + range->num_encoding_sizes = 2; + range->max_encoding_tokens = 4; + +/** Minimum power period */ +#define IW_POWER_PERIOD_MIN 1000000 /* 1 sec */ +/** Maximum power period */ +#define IW_POWER_PERIOD_MAX 120000000 /* 2 min */ +/** Minimum power timeout value */ +#define IW_POWER_TIMEOUT_MIN 1000 /* 1 ms */ +/** Maximim power timeout value */ +#define IW_POWER_TIMEOUT_MAX 1000000 /* 1 sec */ + + /* Power Management duration & timeout */ + range->min_pmp = IW_POWER_PERIOD_MIN; + range->max_pmp = IW_POWER_PERIOD_MAX; + range->min_pmt = IW_POWER_TIMEOUT_MIN; + range->max_pmt = IW_POWER_TIMEOUT_MAX; + range->pmp_flags = IW_POWER_PERIOD; + range->pmt_flags = IW_POWER_TIMEOUT; + range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R; + + /* + * Minimum version we recommend + */ + range->we_version_source = 15; + + /* + * Version we are compiled with + */ + range->we_version_compiled = WIRELESS_EXT; + + range->retry_capa = IW_RETRY_LIMIT; + range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + + range->min_retry = MLAN_TX_RETRY_MIN; + range->max_retry = MLAN_TX_RETRY_MAX; + + /* + * Set the qual, level and noise range values + */ + /* + * need to put the right values here + */ +/** Maximum quality percentage */ +#define IW_MAX_QUAL_PERCENT 5 +/** Average quality percentage */ +#define IW_AVG_QUAL_PERCENT 3 + range->max_qual.qual = IW_MAX_QUAL_PERCENT; + range->max_qual.level = 0; + range->max_qual.noise = 0; + + range->avg_qual.qual = IW_AVG_QUAL_PERCENT; + range->avg_qual.level = 0; + range->avg_qual.noise = 0; + + range->sensitivity = 0; + + /* + * Setup the supported power level ranges + */ + memset(range->txpower, 0, sizeof(range->txpower)); + + memset(&bss_info, 0, sizeof(bss_info)); + + woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info); + + range->txpower[0] = bss_info.min_power_level; + range->txpower[1] = bss_info.max_power_level; + range->num_txpower = 2; + range->txpower_capa = IW_TXPOW_DBM | IW_TXPOW_RANGE; + + LEAVE(); + return 0; +} + +#ifdef MEF_CFG_RX_FILTER +/** + * @brief Enable/disable Rx broadcast/multicast filter in non-HS mode + * + * @param priv A pointer to moal_private structure + * @param enable MTRUE/MFALSE: enable/disable + * + * @return 0 -- success, otherwise fail + */ +static int +woal_set_rxfilter(moal_private * priv, BOOLEAN enable) +{ + int ret = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_misc_cfg *misc = NULL; + mlan_ds_misc_mef_cfg *mef_cfg = NULL; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + misc = (mlan_ds_misc_cfg *) req->pbuf; + mef_cfg = &misc->param.mef_cfg; + req->req_id = MLAN_IOCTL_MISC_CFG; + misc->sub_command = MLAN_OID_MISC_MEF_CFG; + req->action = MLAN_ACT_SET; + + mef_cfg->sub_id = (enable ? MEF_CFG_RX_FILTER_ENABLE : MEF_CFG_DISABLE); + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} +#endif + +/** + * @brief Set priv command + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return 0 --success, otherwise fail + */ +static int +woal_set_priv(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + int ret = 0; + moal_private *priv = (moal_private *) netdev_priv(dev); + char *buf = NULL; + int power_mode = 0; + int band = 0; + char *pband = NULL; + mlan_bss_info bss_info; + mlan_ds_get_signal signal; + mlan_rate_cfg_t rate; + char *pdata; + t_u8 country_code[COUNTRY_CODE_LEN]; + int len = 0; + ENTER(); + if (!(buf = kmalloc(dwrq->length + 1, GFP_KERNEL))) { + ret = -ENOMEM; + goto done; + } + memset(buf, 0, dwrq->length + 1); + if (copy_from_user(buf, dwrq->pointer, dwrq->length)) { + ret = -EFAULT; + goto done; + } + PRINTM(MIOCTL, "SIOCSIWPRIV requst = %s\n", buf); + if (strncmp(buf, "RSSILOW-THRESHOLD", strlen("RSSILOW-THRESHOLD")) == 0) { + pdata = buf + strlen("RSSILOW-THRESHOLD") + 1; + if (MLAN_STATUS_SUCCESS != woal_set_rssi_low_threshold(priv, pdata)) { + ret = -EFAULT; + goto done; + } + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "RSSI", strlen("RSSI")) == 0) { + if (MLAN_STATUS_SUCCESS != woal_get_bss_info(priv, + MOAL_IOCTL_WAIT, + &bss_info)) { + ret = -EFAULT; + goto done; + } + if (bss_info.media_connected) { + if (MLAN_STATUS_SUCCESS != + woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) { + ret = -EFAULT; + goto done; + } + len = + sprintf(buf, "%s rssi %d\n", bss_info.ssid.ssid, + signal.bcn_rssi_avg) + 1; + } else { + len = sprintf(buf, "OK\n") + 1; + } + } else if (strncmp(buf, "LINKSPEED", strlen("LINKSPEED")) == 0) { + if (MLAN_STATUS_SUCCESS != + woal_set_get_data_rate(priv, MLAN_ACT_GET, &rate)) { + ret = -EFAULT; + goto done; + } + PRINTM(MIOCTL, "tx rate=%d\n", (int) rate.rate); + len = + sprintf(buf, "LinkSpeed %d\n", + (int) (rate.rate * 500000 / 1000000)) + 1; + } else if (strncmp(buf, "MACADDR", strlen("MACADDR")) == 0) { + len = + sprintf(buf, "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n", + priv->current_addr[0], priv->current_addr[1], + priv->current_addr[2], priv->current_addr[3], + priv->current_addr[4], priv->current_addr[5]) + 1; + } else if (strncmp(buf, "GETPOWER", strlen("GETPOWER")) == 0) { + if (MLAN_STATUS_SUCCESS != woal_get_powermode(priv, &power_mode)) { + ret = -EFAULT; + goto done; + } + len = sprintf(buf, "powermode = %d\n", power_mode) + 1; + } else if (strncmp(buf, "SCAN-ACTIVE", strlen("SCAN-ACTIVE")) == 0) { + if (MLAN_STATUS_SUCCESS != + woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE)) { + ret = -EFAULT; + goto done; + } + priv->scan_type = MLAN_SCAN_TYPE_ACTIVE; + PRINTM(MIOCTL, "Set Active Scan\n"); + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "SCAN-PASSIVE", strlen("SCAN-PASSIVE")) == 0) { + if (MLAN_STATUS_SUCCESS != + woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE)) { + ret = -EFAULT; + goto done; + } + priv->scan_type = MLAN_SCAN_TYPE_PASSIVE; + PRINTM(MIOCTL, "Set Passive Scan\n"); + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "POWERMODE", strlen("POWERMODE")) == 0) { + pdata = buf + strlen("POWERMODE") + 1; + if (MLAN_STATUS_SUCCESS != woal_set_powermode(priv, pdata)) { + ret = -EFAULT; + goto done; + } + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "COUNTRY", strlen("COUNTRY")) == 0) { + memset(country_code, 0, sizeof(country_code)); + memcpy(country_code, buf + strlen("COUNTRY") + 1, + strlen(buf) - strlen("COUNTRY") - 1); + PRINTM(MIOCTL, "Set COUNTRY %s\n", country_code); + if (MLAN_STATUS_SUCCESS != woal_set_region_code(priv, country_code)) { + ret = -EFAULT; + goto done; + } + len = sprintf(buf, "OK\n") + 1; + } else if (memcmp(buf, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE) == 0) { + PRINTM(MIOCTL, "Set Combo Scan\n"); + if (MLAN_STATUS_SUCCESS != woal_set_combo_scan(priv, buf, dwrq->length)) { + ret = -EFAULT; + goto done; + } + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "GETBAND", strlen("GETBAND")) == 0) { + if (MLAN_STATUS_SUCCESS != woal_get_band(priv, &band)) { + ret = -EFAULT; + goto done; + } + len = sprintf(buf, "Band %d\n", band) + 1; + } else if (strncmp(buf, "SETBAND", strlen("SETBAND")) == 0) { + pband = buf + strlen("SETBAND") + 1; + if (MLAN_STATUS_SUCCESS != woal_set_band(priv, pband)) { + ret = -EFAULT; + goto done; + } + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "START", strlen("START")) == 0) { + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "STOP", strlen("STOP")) == 0) { + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "SETSUSPENDOPT", strlen("SETSUSPENDOPT")) == 0) { + /* it will be done by GUI */ + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0) { + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "BTCOEXSCAN-START", strlen("BTCOEXSCAN-START")) == + 0) { + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "BTCOEXSCAN-STOP", strlen("BTCOEXSCAN-STOP")) == 0) { + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "BTCOEXSCAN-START", strlen("BTCOEXSCAN-START")) == + 0) { + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "BTCOEXSCAN-STOP", strlen("BTCOEXSCAN-STOP")) == 0) { + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "BGSCAN-START", strlen("BGSCAN-START")) == 0) { + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "BGSCAN-CONFIG", strlen("BGSCAN-CONFIG")) == 0) { + if (MLAN_STATUS_SUCCESS != woal_set_bg_scan(priv, buf, dwrq->length)) { + ret = -EFAULT; + goto done; + } + priv->bg_scan_start = MTRUE; + priv->bg_scan_reported = MFALSE; + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "BGSCAN-STOP", strlen("BGSCAN-STOP")) == 0) { + if (MLAN_STATUS_SUCCESS != woal_stop_bg_scan(priv)) { + ret = -EFAULT; + goto done; + } + priv->bg_scan_start = MFALSE; + priv->bg_scan_reported = MFALSE; + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "RXFILTER-START", strlen("RXFILTER-START")) == 0) { +#ifdef MEF_CFG_RX_FILTER + if ((ret = woal_set_rxfilter(priv, MTRUE))) { + goto done; + } +#endif + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "RXFILTER-STOP", strlen("RXFILTER-STOP")) == 0) { +#ifdef MEF_CFG_RX_FILTER + if ((ret = woal_set_rxfilter(priv, MFALSE))) { + goto done; + } +#endif + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "RXFILTER-ADD", strlen("RXFILTER-ADD")) == 0) { + pdata = buf + strlen("RXFILTER-ADD") + 1; + if (MLAN_STATUS_SUCCESS != woal_add_rxfilter(priv, pdata)) { + ret = -EFAULT; + goto done; + } + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "RXFILTER-REMOVE", strlen("RXFILTER-REMOVE")) == 0) { + pdata = buf + strlen("RXFILTER-REMOVE") + 1; + if (MLAN_STATUS_SUCCESS != woal_remove_rxfilter(priv, pdata)) { + ret = -EFAULT; + goto done; + } + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "QOSINFO", strlen("QOSINFO")) == 0) { + pdata = buf + strlen("QOSINFO") + 1; + if (MLAN_STATUS_SUCCESS != woal_set_qos_cfg(priv, pdata)) { + ret = -EFAULT; + goto done; + } + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "SLEEPPD", strlen("SLEEPPD")) == 0) { + pdata = buf + strlen("SLEEPPD") + 1; + if (MLAN_STATUS_SUCCESS != woal_set_sleeppd(priv, pdata)) { + ret = -EFAULT; + goto done; + } + len = sprintf(buf, "OK\n") + 1; + } else { + PRINTM(MIOCTL, "Unknow PRIVATE command: %s, ignored\n", buf); + ret = -EFAULT; + goto done; + } + PRINTM(MIOCTL, "PRIV Command return: %s, length=%d\n", buf, len); + dwrq->length = (t_u16) len; + if (copy_to_user(dwrq->pointer, buf, dwrq->length)) { + ret = -EFAULT; + } + done: + if (buf) + kfree(buf); + LEAVE(); + return ret; +} + +/** + * @brief Scan Network + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param vwrq A pointer to iw_param structure + * @param extra A pointer to extra data buf + * + * @return 0--success, otherwise fail + */ +static int +woal_set_scan(struct net_device *dev, struct iw_request_info *info, + struct iw_param *vwrq, char *extra) +{ + int ret = 0; + moal_private *priv = (moal_private *) netdev_priv(dev); + moal_handle *handle = priv->phandle; +#if WIRELESS_EXT >= 18 + struct iw_scan_req *req; + struct iw_point *dwrq = (struct iw_point *) vwrq; +#endif + mlan_802_11_ssid req_ssid; + + ENTER(); + if (handle->scan_pending_on_block == MTRUE) { + PRINTM(MINFO, "scan already in processing...\n"); + LEAVE(); + return ret; + } +#ifdef REASSOCIATION + if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) { + PRINTM(MERROR, "Acquire semaphore error, woal_set_scan\n"); + LEAVE(); + return -EBUSY; + } +#endif /* REASSOCIATION */ + priv->report_scan_result = MTRUE; + + memset(&req_ssid, 0x00, sizeof(mlan_802_11_ssid)); + +#if WIRELESS_EXT >= 18 + if ((dwrq->flags & IW_SCAN_THIS_ESSID) && + (dwrq->length == sizeof(struct iw_scan_req))) { + req = (struct iw_scan_req *) extra; + + if (req->essid_len <= MLAN_MAX_SSID_LENGTH) { + + req_ssid.ssid_len = req->essid_len; + memcpy(req_ssid.ssid, (t_u8 *) req->essid, req->essid_len); + if (MLAN_STATUS_SUCCESS != + woal_request_scan(priv, MOAL_NO_WAIT, &req_ssid)) { + ret = -EFAULT; + goto done; + } + } + } else { +#endif + if (MLAN_STATUS_SUCCESS != woal_request_scan(priv, MOAL_NO_WAIT, NULL)) { + ret = -EFAULT; + goto done; + } +#if WIRELESS_EXT >= 18 + } +#endif + + if (priv->phandle->surprise_removed) { + ret = -EFAULT; + goto done; + } + + done: +#ifdef REASSOCIATION + MOAL_REL_SEMAPHORE(&handle->reassoc_sem); +#endif + + LEAVE(); + return ret; +} + +/** + * @brief Set essid + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return 0--success, otherwise fail + */ +static int +woal_set_essid(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_802_11_ssid req_ssid; + mlan_ssid_bssid ssid_bssid; +#ifdef REASSOCIATION + moal_handle *handle = priv->phandle; + mlan_bss_info bss_info; +#endif + int ret = 0; + t_u32 mode = 0; + + ENTER(); + +#ifdef REASSOCIATION + /* Cancel re-association */ + priv->reassoc_required = MFALSE; + + if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) { + PRINTM(MERROR, "Acquire semaphore error, woal_set_essid\n"); + LEAVE(); + return -EBUSY; + } +#endif /* REASSOCIATION */ + + /* Check the size of the string */ + if (dwrq->length > IW_ESSID_MAX_SIZE + 1) { + ret = -E2BIG; + goto setessid_ret; + } + if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE) + woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE); + memset(&req_ssid, 0, sizeof(mlan_802_11_ssid)); + memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid)); + +#if WIRELESS_EXT > 20 + req_ssid.ssid_len = dwrq->length; +#else + req_ssid.ssid_len = dwrq->length - 1; +#endif + + /* + * Check if we asked for `any' or 'particular' + */ + if (!dwrq->flags) { + + if (!req_ssid.ssid_len) { + memset(&priv->prev_ssid_bssid.ssid, 0x00, sizeof(mlan_802_11_ssid)); + memset(&priv->prev_ssid_bssid.bssid, 0x00, MLAN_MAC_ADDR_LENGTH); + goto setessid_ret; + } + + /* Do normal SSID scanning */ + if (MLAN_STATUS_SUCCESS != + woal_request_scan(priv, MOAL_IOCTL_WAIT, NULL)) { + ret = -EFAULT; + goto setessid_ret; + } + } else { + /* Set the SSID */ + memcpy(req_ssid.ssid, extra, + MIN(req_ssid.ssid_len, MLAN_MAX_SSID_LENGTH)); + if (!req_ssid.ssid_len || (MFALSE == woal_ssid_valid(&req_ssid))) { + PRINTM(MERROR, "Invalid SSID - aborting set_essid\n"); + ret = -EINVAL; + goto setessid_ret; + } + + PRINTM(MINFO, "Requested new SSID = %s\n", (char *) req_ssid.ssid); + memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(mlan_802_11_ssid)); + if (dwrq->flags != 0xFFFF) { + if (MLAN_STATUS_SUCCESS != woal_find_essid(priv, &ssid_bssid)) { + /* Do specific SSID scanning */ + if (MLAN_STATUS_SUCCESS != + woal_request_scan(priv, MOAL_IOCTL_WAIT, &req_ssid)) { + ret = -EFAULT; + goto setessid_ret; + } + } + } + + } + + /* disconnect before try to associate */ + woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL); + mode = woal_get_mode(priv, MOAL_IOCTL_WAIT); + + if (mode != IW_MODE_ADHOC) { + if (MLAN_STATUS_SUCCESS != + woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) { + ret = -EFAULT; + goto setessid_ret; + } + } else if (MLAN_STATUS_SUCCESS != + woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) + /* Adhoc start, Check the channel command */ + woal_11h_channel_check_ioctl(priv); + + /* Connect to BSS by ESSID */ + memset(&ssid_bssid.bssid, 0, MLAN_MAC_ADDR_LENGTH); + + if (MLAN_STATUS_SUCCESS != woal_bss_start(priv, + MOAL_IOCTL_WAIT, &ssid_bssid)) { + ret = -EFAULT; + goto setessid_ret; + } +#ifdef REASSOCIATION + memset(&bss_info, 0, sizeof(bss_info)); + if (MLAN_STATUS_SUCCESS != woal_get_bss_info(priv, + MOAL_IOCTL_WAIT, &bss_info)) { + ret = -EFAULT; + goto setessid_ret; + } + memcpy(&priv->prev_ssid_bssid.ssid, &bss_info.ssid, + sizeof(mlan_802_11_ssid)); + memcpy(&priv->prev_ssid_bssid.bssid, &bss_info.bssid, MLAN_MAC_ADDR_LENGTH); +#endif /* REASSOCIATION */ + + setessid_ret: + if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE) + woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE); +#ifdef REASSOCIATION + MOAL_REL_SEMAPHORE(&handle->reassoc_sem); +#endif + + LEAVE(); + return ret; +} + +/** + * @brief Get current essid + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return 0--success, otherwise fail + */ +static int +woal_get_essid(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + mlan_bss_info bss_info; + int ret = 0; + + ENTER(); + + memset(&bss_info, 0, sizeof(bss_info)); + + if (MLAN_STATUS_SUCCESS != + woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) { + ret = -EFAULT; + goto done; + } + + if (bss_info.media_connected) { + dwrq->length = MIN(dwrq->length, bss_info.ssid.ssid_len); + memcpy(extra, bss_info.ssid.ssid, dwrq->length); + } else + dwrq->length = 0; + + if (bss_info.scan_table_idx) + dwrq->flags = (bss_info.scan_table_idx + 1) & IW_ENCODE_INDEX; + else + dwrq->flags = 1; + + done: + LEAVE(); + return ret; +} + +/** + * @brief Retrieve the scan table entries via wireless tools IOCTL call + * + * @param dev A pointer to net_device structure + * @param info A pointer to iw_request_info structure + * @param dwrq A pointer to iw_point structure + * @param extra A pointer to extra data buf + * + * @return 0--success, otherwise fail + */ +static int +woal_get_scan(struct net_device *dev, struct iw_request_info *info, + struct iw_point *dwrq, char *extra) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + int ret = 0; + char *current_ev = extra; + char *end_buf = extra + IW_SCAN_MAX_DATA; + char *current_val; /* For rates */ + struct iw_event iwe; /* Temporary buffer */ + unsigned int i; + unsigned int j; + mlan_scan_resp scan_resp; + mlan_bss_info bss_info; + BSSDescriptor_t *scan_table; + mlan_ds_get_signal rssi; + t_u16 buf_size = 16 + 256 * 2; + char *buf = NULL; + char *ptr; +#if WIRELESS_EXT >= 18 + t_u8 *praw_data; +#endif + int beacon_size; + t_u8 *pbeacon; + IEEEtypes_ElementId_e element_id; + t_u8 element_len; + + ENTER(); + + if (priv->phandle->scan_pending_on_block == MTRUE) { + LEAVE(); + return -EAGAIN; + } + + if (!(buf = kmalloc((buf_size), GFP_KERNEL))) { + PRINTM(MERROR, "Cannot allocate buffer!\n"); + ret = -EFAULT; + goto done; + } + + memset(&bss_info, 0, sizeof(bss_info)); + if (MLAN_STATUS_SUCCESS != + woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) { + ret = -EFAULT; + goto done; + } + memset(&scan_resp, 0, sizeof(scan_resp)); + if (MLAN_STATUS_SUCCESS != woal_get_scan_table(priv, + MOAL_IOCTL_WAIT, + &scan_resp)) { + ret = -EFAULT; + goto done; + } + scan_table = (BSSDescriptor_t *) scan_resp.pscan_table; + if (dwrq->length) + end_buf = extra + dwrq->length; + if (priv->media_connected == MTRUE) { + PRINTM(MINFO, "Current Ssid: %-32s\n", bss_info.ssid.ssid); + } + PRINTM(MINFO, "Scan: Get: NumInScanTable = %d\n", + (int) scan_resp.num_in_scan_table); + +#if WIRELESS_EXT > 13 + /* The old API using SIOCGIWAPLIST had a hard limit of IW_MAX_AP. The new + API using SIOCGIWSCAN is only limited by buffer size WE-14 -> WE-16 the + buffer is limited to IW_SCAN_MAX_DATA bytes which is 4096. */ + for (i = 0; i < scan_resp.num_in_scan_table; i++) { + if ((current_ev + MAX_SCAN_CELL_SIZE) >= end_buf) { + PRINTM(MINFO, "i=%d break out: current_ev=%p end_buf=%p " + "MAX_SCAN_CELL_SIZE=%d\n", + i, current_ev, end_buf, (t_u32) MAX_SCAN_CELL_SIZE); + ret = -E2BIG; + break; + } + if (!scan_table[i].freq) { + PRINTM(MERROR, "Invalid channel number %d\n", + (int) scan_table[i].channel); + continue; + } + PRINTM(MINFO, "i=%d Ssid: %-32s\n", i, scan_table[i].ssid.ssid); + + /* check ssid is valid or not, ex. hidden ssid will be filter out */ + if (woal_ssid_valid(&scan_table[i].ssid) == MFALSE) { + continue; + } + + /* First entry *MUST* be the AP MAC address */ + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, &scan_table[i].mac_address, ETH_ALEN); + + iwe.len = IW_EV_ADDR_LEN; + current_ev = + IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, iwe.len); + + /* Add the ESSID */ + iwe.u.data.length = scan_table[i].ssid.ssid_len; + + if (iwe.u.data.length > 32) { + iwe.u.data.length = 32; + } + + iwe.cmd = SIOCGIWESSID; + iwe.u.essid.flags = (i + 1) & IW_ENCODE_INDEX; + iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; + current_ev = + IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, + (t_s8 *) scan_table[i].ssid.ssid); + + /* Add mode */ + iwe.cmd = SIOCGIWMODE; + if (scan_table[i].bss_mode == MLAN_BSS_MODE_IBSS) + iwe.u.mode = IW_MODE_ADHOC; + else if (scan_table[i].bss_mode == MLAN_BSS_MODE_INFRA) + iwe.u.mode = IW_MODE_MASTER; + else + iwe.u.mode = IW_MODE_AUTO; + + iwe.len = IW_EV_UINT_LEN; + current_ev = + IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, iwe.len); + + /* Frequency */ + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = (long) scan_table[i].freq * 100000; + iwe.u.freq.e = 1; + iwe.u.freq.flags = IW_FREQ_FIXED; + iwe.len = IW_EV_FREQ_LEN; + current_ev = + IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, iwe.len); + + memset(&iwe, 0, sizeof(iwe)); + /* Add quality statistics */ + iwe.cmd = IWEVQUAL; + iwe.u.qual.level = SCAN_RSSI(scan_table[i].rssi); + if (!bss_info.bcn_nf_last) { + iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE; + } else { + iwe.u.qual.noise = bss_info.bcn_nf_last; + } + if ((bss_info.bss_mode == MLAN_BSS_MODE_IBSS) && + !woal_ssid_cmp(&bss_info.ssid, &scan_table[i].ssid) + && bss_info.adhoc_state == ADHOC_STARTED) { + memset(&rssi, 0, sizeof(mlan_ds_get_signal)); + if (MLAN_STATUS_SUCCESS != + woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &rssi)) { + ret = -EFAULT; + break; + } + iwe.u.qual.level = rssi.data_rssi_avg; + } + iwe.u.qual.qual = + woal_rssi_to_quality((t_s16) (iwe.u.qual.level - 0x100)); + iwe.len = IW_EV_QUAL_LEN; + current_ev = + IWE_STREAM_ADD_EVENT(info, current_ev, end_buf, &iwe, iwe.len); + + /* Add encryption capability */ + iwe.cmd = SIOCGIWENCODE; + if (scan_table[i].privacy) { + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + } else { + iwe.u.data.flags = IW_ENCODE_DISABLED; + } + iwe.u.data.length = 0; + iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; + current_ev = + IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, NULL); + + current_val = current_ev + IW_EV_LCP_LEN; + + iwe.cmd = SIOCGIWRATE; + + iwe.u.bitrate.fixed = 0; + iwe.u.bitrate.disabled = 0; + iwe.u.bitrate.value = 0; + + /* Bit rate given in 500 kb/s units (+ 0x80) */ + for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) { + if (!scan_table[i].supported_rates[j]) { + break; + } + + iwe.u.bitrate.value = + (scan_table[i].supported_rates[j] & 0x7f) * 500000; + iwe.len = IW_EV_PARAM_LEN; + current_val = + IWE_STREAM_ADD_VALUE(info, current_ev, current_val, end_buf, + &iwe, iwe.len); + + } + if ((bss_info.bss_mode == MLAN_BSS_MODE_IBSS) && + !woal_ssid_cmp(&bss_info.ssid, &scan_table[i].ssid) + && bss_info.adhoc_state == ADHOC_STARTED) { + iwe.u.bitrate.value = 22 * 500000; + iwe.len = IW_EV_PARAM_LEN; + current_val = + IWE_STREAM_ADD_VALUE(info, current_ev, current_val, end_buf, + &iwe, iwe.len); + } + + /* Check if an event is added */ + if ((unsigned int) (current_val - current_ev) >= IW_EV_PARAM_LEN) + current_ev = current_val; + + /* Beacon Interval */ + memset(&iwe, 0, sizeof(iwe)); + memset(buf, 0, buf_size); + ptr = buf; + ptr += sprintf(ptr, "Beacon interval=%d", scan_table[i].beacon_period); + + iwe.u.data.length = strlen(buf); + iwe.cmd = IWEVCUSTOM; + iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; + current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, buf); + current_val = current_ev + IW_EV_LCP_LEN + strlen(buf); + + /* Parse and send the IEs */ + pbeacon = scan_table[i].pbeacon_buf; + beacon_size = scan_table[i].beacon_buf_size; + + /* Skip time stamp, beacon interval and capability */ + if (pbeacon) { + pbeacon += sizeof(scan_table[i].beacon_period) + + sizeof(scan_table[i].time_stamp) + + sizeof(scan_table[i].cap_info); + beacon_size -= sizeof(scan_table[i].beacon_period) + + sizeof(scan_table[i].time_stamp) + + sizeof(scan_table[i].cap_info); + + while ((unsigned int) beacon_size >= sizeof(IEEEtypes_Header_t)) { + element_id = (IEEEtypes_ElementId_e) (*(t_u8 *) pbeacon); + element_len = *((t_u8 *) pbeacon + 1); + if ((unsigned int) beacon_size < + (unsigned int) element_len + sizeof(IEEEtypes_Header_t)) { + PRINTM(MERROR, + "Get scan: Error in processing IE, " + "bytes left < IE length\n"); + break; + } + + switch (element_id) { +#if WIRELESS_EXT >= 18 + case VENDOR_SPECIFIC_221: + case RSN_IE: + case WAPI_IE: + praw_data = (t_u8 *) pbeacon; + memset(&iwe, 0, sizeof(iwe)); + memset(buf, 0, buf_size); + ptr = buf; + memcpy(buf, praw_data, + element_len + sizeof(IEEEtypes_Header_t)); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = + element_len + sizeof(IEEEtypes_Header_t); + iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; + current_ev = + IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, + buf); + current_val = current_ev + IW_EV_LCP_LEN + strlen(buf); + break; +#endif + default: + break; + } + pbeacon += element_len + sizeof(IEEEtypes_Header_t); + beacon_size -= element_len + sizeof(IEEEtypes_Header_t); + } + } +#if WIRELESS_EXT > 14 + memset(&iwe, 0, sizeof(iwe)); + memset(buf, 0, buf_size); + ptr = buf; + ptr += sprintf(ptr, "band="); + memset(&iwe, 0, sizeof(iwe)); + if (scan_table[i].bss_band == BAND_A) + ptr += sprintf(ptr, "a"); + else + ptr += sprintf(ptr, "bg"); + iwe.u.data.length = strlen(buf); + PRINTM(MINFO, "iwe.u.data.length %d\n", iwe.u.data.length); + PRINTM(MINFO, "BUF: %s \n", buf); + iwe.cmd = IWEVCUSTOM; + iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; + current_ev = IWE_STREAM_ADD_POINT(info, current_ev, end_buf, &iwe, buf); + current_val = current_ev + IW_EV_LCP_LEN + strlen(buf); +#endif + current_val = current_ev + IW_EV_LCP_LEN; + + /* + * Check if we added any event + */ + if ((unsigned int) (current_val - current_ev) > IW_EV_LCP_LEN) + current_ev = current_val; + } + + dwrq->length = (current_ev - extra); + dwrq->flags = 0; +#endif + + done: + if (buf) + kfree(buf); + LEAVE(); + return ret; +} + +/** + * iwconfig settable callbacks + */ +static const iw_handler woal_handler[] = { + (iw_handler) woal_config_commit, /* SIOCSIWCOMMIT */ + (iw_handler) woal_get_name, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) woal_set_freq, /* SIOCSIWFREQ */ + (iw_handler) woal_get_freq, /* SIOCGIWFREQ */ + (iw_handler) woal_set_bss_mode, /* SIOCSIWMODE */ + (iw_handler) woal_get_bss_mode, /* SIOCGIWMODE */ + (iw_handler) woal_set_sens, /* SIOCSIWSENS */ + (iw_handler) woal_get_sens, /* SIOCGIWSENS */ + (iw_handler) NULL, /* SIOCSIWRANGE */ + (iw_handler) woal_get_range, /* SIOCGIWRANGE */ + (iw_handler) woal_set_priv, /* SIOCSIWPRIV */ + (iw_handler) NULL, /* SIOCGIWPRIV */ + (iw_handler) NULL, /* SIOCSIWSTATS */ + (iw_handler) NULL, /* SIOCGIWSTATS */ +#if WIRELESS_EXT > 15 + iw_handler_set_spy, /* SIOCSIWSPY */ + iw_handler_get_spy, /* SIOCGIWSPY */ + iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ + iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ +#else /* WIRELESS_EXT > 15 */ +#ifdef WIRELESS_SPY + (iw_handler) NULL, /* SIOCSIWSPY */ + (iw_handler) NULL, /* SIOCGIWSPY */ +#else /* WIRELESS_SPY */ + (iw_handler) NULL, /* SIOCSIWSPY */ + (iw_handler) NULL, /* SIOCGIWSPY */ +#endif /* WIRELESS_SPY */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ +#endif /* WIRELESS_EXT > 15 */ + (iw_handler) woal_set_wap, /* SIOCSIWAP */ + (iw_handler) woal_get_wap, /* SIOCGIWAP */ +#if WIRELESS_EXT >= 18 + (iw_handler) woal_set_mlme, /* SIOCSIWMLME */ +#else + (iw_handler) NULL, /* -- hole -- */ +#endif + /* (iw_handler) wlan_get_aplist, *//* SIOCGIWAPLIST */ + NULL, /* SIOCGIWAPLIST */ +#if WIRELESS_EXT > 13 + (iw_handler) woal_set_scan, /* SIOCSIWSCAN */ + (iw_handler) woal_get_scan, /* SIOCGIWSCAN */ +#else /* WIRELESS_EXT > 13 */ + (iw_handler) NULL, /* SIOCSIWSCAN */ + (iw_handler) NULL, /* SIOCGIWSCAN */ +#endif /* WIRELESS_EXT > 13 */ + (iw_handler) woal_set_essid, /* SIOCSIWESSID */ + (iw_handler) woal_get_essid, /* SIOCGIWESSID */ + (iw_handler) woal_set_nick, /* SIOCSIWNICKN */ + (iw_handler) woal_get_nick, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) woal_set_rate, /* SIOCSIWRATE */ + (iw_handler) woal_get_rate, /* SIOCGIWRATE */ + (iw_handler) woal_set_rts, /* SIOCSIWRTS */ + (iw_handler) woal_get_rts, /* SIOCGIWRTS */ + (iw_handler) woal_set_frag, /* SIOCSIWFRAG */ + (iw_handler) woal_get_frag, /* SIOCGIWFRAG */ + (iw_handler) woal_set_txpow, /* SIOCSIWTXPOW */ + (iw_handler) woal_get_txpow, /* SIOCGIWTXPOW */ + (iw_handler) woal_set_retry, /* SIOCSIWRETRY */ + (iw_handler) woal_get_retry, /* SIOCGIWRETRY */ + (iw_handler) woal_set_encode, /* SIOCSIWENCODE */ + (iw_handler) woal_get_encode, /* SIOCGIWENCODE */ + (iw_handler) woal_set_power, /* SIOCSIWPOWER */ + (iw_handler) woal_get_power, /* SIOCGIWPOWER */ +#if (WIRELESS_EXT >= 18) + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) woal_set_gen_ie, /* SIOCSIWGENIE */ + (iw_handler) woal_get_gen_ie, /* SIOCGIWGENIE */ + (iw_handler) woal_set_auth, /* SIOCSIWAUTH */ + (iw_handler) woal_get_auth, /* SIOCGIWAUTH */ + (iw_handler) woal_set_encode_ext, /* SIOCSIWENCODEEXT */ + (iw_handler) woal_get_encode_ext, /* SIOCGIWENCODEEXT */ + (iw_handler) woal_set_pmksa, /* SIOCSIWPMKSA */ +#endif /* WIRELESSS_EXT >= 18 */ +}; + +/** + * iwpriv settable callbacks + */ +static const iw_handler woal_private_handler[] = { + NULL, /* SIOCIWFIRSTPRIV */ +}; +#endif /* STA_SUPPORT */ + +/******************************************************** + Global Functions +********************************************************/ + +#if WIRELESS_EXT > 14 + +/** + * @brief This function sends customized event to application. + * + * @param priv A pointer to moal_private structure + * @param str A pointer to event string + * + * @return N/A + */ +void +woal_send_iwevcustom_event(moal_private * priv, t_s8 * str) +{ + union iwreq_data iwrq; + char buf[IW_CUSTOM_MAX]; + + ENTER(); + + memset(&iwrq, 0, sizeof(union iwreq_data)); + memset(buf, 0, sizeof(buf)); + + snprintf(buf, sizeof(buf) - 1, "%s", str); + + iwrq.data.pointer = buf; + iwrq.data.length = strlen(buf) + 1; + + /* Send Event to upper layer */ + wireless_send_event(priv->netdev, IWEVCUSTOM, &iwrq, buf); + PRINTM(MINFO, "Wireless event %s is sent to application\n", str); + + LEAVE(); + return; +} +#endif + +#if WIRELESS_EXT >= 18 +/** + * @brief This function sends mic error event to application. + * + * @param priv A pointer to moal_private structure + * @param event MIC MERROR EVENT. + * + * @return N/A + */ +void +woal_send_mic_error_event(moal_private * priv, t_u32 event) +{ + union iwreq_data iwrq; + struct iw_michaelmicfailure mic; + + ENTER(); + + memset(&iwrq, 0, sizeof(iwrq)); + memset(&mic, 0, sizeof(mic)); + if (event == MLAN_EVENT_ID_FW_MIC_ERR_UNI) + mic.flags = IW_MICFAILURE_PAIRWISE; + else + mic.flags = IW_MICFAILURE_GROUP; + iwrq.data.pointer = &mic; + iwrq.data.length = sizeof(mic); + + wireless_send_event(priv->netdev, IWEVMICHAELMICFAILURE, &iwrq, + (char *) &mic); + + LEAVE(); + return; +} +#endif + +#ifdef STA_SUPPORT +/** + * @brief Set Radio On/OFF + * + * @param priv A pointer to moal_private structure + * @param option Radio Option + * + * @return 0 --success, otherwise fail + */ +int +woal_set_radio(moal_private * priv, t_u8 option) +{ + int ret = 0; + mlan_ds_radio_cfg *radio = NULL; + mlan_ioctl_req *req = NULL; + ENTER(); + if ((option != 0) && (option != 1)) { + ret = -EINVAL; + goto done; + } + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + radio = (mlan_ds_radio_cfg *) req->pbuf; + radio->sub_command = MLAN_OID_RADIO_CTRL; + req->req_id = MLAN_IOCTL_RADIO_CFG; + req->action = MLAN_ACT_SET; + radio->param.radio_on_off = option; + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** wlan_handler_def */ +struct iw_handler_def woal_handler_def = { + num_standard:sizeof(woal_handler) / sizeof(iw_handler), + num_private:sizeof(woal_private_handler) / sizeof(iw_handler), + num_private_args:sizeof(woal_private_args) / sizeof(struct iw_priv_args), + standard:(iw_handler *) woal_handler, + private:(iw_handler *) woal_private_handler, + private_args:(struct iw_priv_args *) woal_private_args, +#if WIRELESS_EXT > 20 + get_wireless_stats:woal_get_wireless_stats, +#endif +}; + +/** + * @brief Get wireless statistics + * + * @param dev A pointer to net_device structure + * + * @return A pointer to iw_statistics buf + */ +struct iw_statistics * +woal_get_wireless_stats(struct net_device *dev) +{ + moal_private *priv = (moal_private *) netdev_priv(dev); + t_u16 wait_option = MOAL_NO_WAIT; + + ENTER(); + + /* + * Since schedule() is not allowed from an atomic context + * such as when dev_base_lock for netdevices is acquired + * for reading/writing in kernel before this call, HostCmd + * is issued in non-blocking way in such contexts and + * blocking in other cases. + */ + if (write_can_lock(&dev_base_lock) + && (!in_atomic() || current->exit_state)) + wait_option = MOAL_WSTATS_WAIT; + + priv->w_stats.status = woal_get_mode(priv, wait_option); + priv->w_stats.discard.retries = priv->stats.tx_errors; + priv->w_stats.qual.qual = 0; + + /* Send RSSI command to get beacon RSSI/NF, valid only if associated */ + if (priv->media_connected == MTRUE) { + woal_get_signal_info(priv, wait_option, NULL); + priv->w_stats.qual.qual = woal_rssi_to_quality((t_s16) + (priv->w_stats.qual. + level - 0x100)); + } +#if WIRELESS_EXT > 18 + priv->w_stats.qual.updated |= (IW_QUAL_ALL_UPDATED | IW_QUAL_DBM); +#else + priv->w_stats.qual.updated |= 7; +#endif + if (!priv->w_stats.qual.noise && priv->media_connected == MTRUE) + priv->w_stats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE; + + PRINTM(MINFO, "Link Quality = %#x\n", priv->w_stats.qual.qual); + PRINTM(MINFO, "Signal Level = %#x\n", priv->w_stats.qual.level); + PRINTM(MINFO, "Noise = %#x\n", priv->w_stats.qual.noise); + priv->w_stats.discard.code = 0; + woal_get_stats_info(priv, wait_option, NULL); + + LEAVE(); + return &priv->w_stats; +} +#endif /* STA_SUPPORT */ diff --git a/drivers/net/wireless/sd8797/mlinux/moal_wext.h b/drivers/net/wireless/sd8797/mlinux/moal_wext.h new file mode 100644 index 000000000000..91f918e1b130 --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/moal_wext.h @@ -0,0 +1,116 @@ +/** @file moal_wext.h + * + * @brief This file contains definition for wireless extension IOCTL call. + * + * Copyright (C) 2008-2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + * + */ + +/******************************************************** +Change log: + 10/21/2008: initial version +********************************************************/ + +#ifndef _WOAL_WEXT_H_ +#define _WOAL_WEXT_H_ + +/** Custom event : AdHoc link sensed */ +#define CUS_EVT_ADHOC_LINK_SENSED "EVENT=ADHOC_LINK_SENSED" +/** Custom event : AdHoc link lost */ +#define CUS_EVT_ADHOC_LINK_LOST "EVENT=ADHOC_LINK_LOST" +/** Custom event : MIC failure, unicast */ +#define CUS_EVT_MLME_MIC_ERR_UNI "MLME-MICHAELMICFAILURE.indication unicast " +/** Custom event : MIC failure, multicast */ +#define CUS_EVT_MLME_MIC_ERR_MUL "MLME-MICHAELMICFAILURE.indication multicast " +/** Custom event : Beacon RSSI low */ +#define CUS_EVT_BEACON_RSSI_LOW "EVENT=BEACON_RSSI_LOW" +/** Custom event : Beacon SNR low */ +#define CUS_EVT_BEACON_SNR_LOW "EVENT=BEACON_SNR_LOW" +/** Custom event : Beacon RSSI high */ +#define CUS_EVT_BEACON_RSSI_HIGH "EVENT=BEACON_RSSI_HIGH" +/** Custom event : Beacon SNR high */ +#define CUS_EVT_BEACON_SNR_HIGH "EVENT=BEACON_SNR_HIGH" +/** Custom event : Max fail */ +#define CUS_EVT_MAX_FAIL "EVENT=MAX_FAIL" +#define CUS_EVT_BG_SCAN "EVENT=BG_SCAN_REPORT" +/** Custom event : Data RSSI low */ +#define CUS_EVT_DATA_RSSI_LOW "EVENT=DATA_RSSI_LOW" +/** Custom event : Data SNR low */ +#define CUS_EVT_DATA_SNR_LOW "EVENT=DATA_SNR_LOW" +/** Custom event : Data RSSI high */ +#define CUS_EVT_DATA_RSSI_HIGH "EVENT=DATA_RSSI_HIGH" +/** Custom event : Data SNR high */ +#define CUS_EVT_DATA_SNR_HIGH "EVENT=DATA_SNR_HIGH" +/** Custom event : Link Quality */ +#define CUS_EVT_LINK_QUALITY "EVENT=LINK_QUALITY" +/** Custom event : Port Release */ +#define CUS_EVT_PORT_RELEASE "EVENT=PORT_RELEASE" +/** Custom event : Pre-Beacon Lost */ +#define CUS_EVT_PRE_BEACON_LOST "EVENT=PRE_BEACON_LOST" + +/** Custom event : Deep Sleep awake */ +#define CUS_EVT_DEEP_SLEEP_AWAKE "EVENT=DS_AWAKE" + +/** Custom event : Host Sleep activated */ +#define CUS_EVT_HS_ACTIVATED "HS_ACTIVATED " +/** Custom event : Host Sleep deactivated */ +#define CUS_EVT_HS_DEACTIVATED "HS_DEACTIVATED " +/** Custom event : Host Sleep wakeup */ +#define CUS_EVT_HS_WAKEUP "HS_WAKEUP" + +/** Custom event : WEP ICV error */ +#define CUS_EVT_WEP_ICV_ERR "EVENT=WEP_ICV_ERR" + +/** Custom event : Channel Switch Announcment */ +#define CUS_EVT_CHANNEL_SWITCH_ANN "EVENT=CHANNEL_SWITCH_ANN" + +/** Custom event : BW changed */ +#define CUS_EVT_BW_CHANGED "EVENT=BW_CHANGED" +/** Custom event : OBSS scan parameter */ +#define CUS_EVT_OBSS_SCAN_PARAM "EVENT=OBSS_SCAN_PARAM" +/** Custom indiciation message sent to the application layer for WMM changes */ +#define WMM_CONFIG_CHANGE_INDICATION "WMM_CONFIG_CHANGE.indication" + +#ifdef UAP_SUPPORT +#ifdef UAP_WEXT +/** Custom event : STA connected */ +#define CUS_EVT_STA_CONNECTED "EVENT=STA_CONNECTED" +/** Custom event : STA disconnected */ +#define CUS_EVT_STA_DISCONNECTED "EVENT=STA_DISCONNECTED" +#endif +#endif +/** NF value for default scan */ +#define MRVDRV_NF_DEFAULT_SCAN_VALUE (-96) + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) +/** Add event */ +#define IWE_STREAM_ADD_EVENT(i, c, e, w, l) iwe_stream_add_event((i), (c), (e), (w), (l)) +/** Add point */ +#define IWE_STREAM_ADD_POINT(i, c, e, w, p) iwe_stream_add_point((i), (c), (e), (w), (p)) +/** Add value */ +#define IWE_STREAM_ADD_VALUE(i, c, v, e, w, l) iwe_stream_add_value((i), (c), (v), (e), (w), (l)) +#else +/** Add event */ +#define IWE_STREAM_ADD_EVENT(i, c, e, w, l) iwe_stream_add_event((c), (e), (w), (l)) +/** Add point */ +#define IWE_STREAM_ADD_POINT(i, c, e, w, p) iwe_stream_add_point((c), (e), (w), (p)) +/** Add value */ +#define IWE_STREAM_ADD_VALUE(i, c, v, e, w, l) iwe_stream_add_value((c), (v), (e), (w), (l)) +#endif + +extern struct iw_handler_def woal_handler_def; +struct iw_statistics *woal_get_wireless_stats(struct net_device *dev); +#endif /* _WOAL_WEXT_H_ */ -- cgit v1.2.3 From 22387a93ebc57773f4530d84b59ecb978b74a449 Mon Sep 17 00:00:00 2001 From: Narayan Reddy Date: Thu, 26 Apr 2012 12:10:32 +0530 Subject: net: wireless: sd8797: Add Kconfig to marvel sd8797 add Konfig to marvel 8797 and some tailing space corrections. Bug 954218 Change-Id: I2885f2a74dea14ffeeb5dad65e03e217c77c5013 Signed-off-by: Narayan Reddy Reviewed-on: http://git-master/r/98436 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Bharat Nihalani --- drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c | 8 +- .../net/wireless/sd8797/mlinux/moal_eth_ioctl.c | 2 +- drivers/net/wireless/sd8797/mlinux/moal_ioctl.c | 336 ++++++++++----------- drivers/net/wireless/sd8797/mlinux/moal_main.c | 198 ++++++------ drivers/net/wireless/sd8797/mlinux/moal_main.h | 58 ++-- drivers/net/wireless/sd8797/mlinux/moal_priv.c | 180 +++++------ drivers/net/wireless/sd8797/mlinux/moal_proc.c | 24 +- drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c | 44 +-- drivers/net/wireless/sd8797/mlinux/moal_shim.c | 140 ++++----- .../net/wireless/sd8797/mlinux/moal_sta_cfg80211.c | 12 +- drivers/net/wireless/sd8797/mlinux/moal_uap.c | 116 +++---- drivers/net/wireless/sd8797/mlinux/moal_uap.h | 2 +- .../net/wireless/sd8797/mlinux/moal_uap_cfg80211.c | 18 +- drivers/net/wireless/sd8797/mlinux/moal_uap_priv.c | 4 +- drivers/net/wireless/sd8797/mlinux/moal_uap_wext.c | 48 +-- drivers/net/wireless/sd8797/mlinux/moal_wext.c | 96 +++--- 16 files changed, 643 insertions(+), 643 deletions(-) (limited to 'drivers/net/wireless/sd8797/mlinux') diff --git a/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c b/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c index 942fae4e991d..1b04db6b4da0 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c @@ -163,7 +163,7 @@ woal_get_wiphy_priv(struct wiphy *wiphy) return (void *) (*(unsigned long *) wiphy_priv(wiphy)); } -/** +/** * @brief Set/Enable encryption key * * @param priv A pointer to moal_private structure @@ -172,7 +172,7 @@ woal_get_wiphy_priv(struct wiphy *wiphy) * @param key A pointer to key * @param key_len Key length * @param seq A pointer to sequence - * @param seq_len Sequence length + * @param seq_len Sequence length * @param key_index Key index * @param addr Mac for which key is to be set * @param disable Key disabled or not @@ -729,7 +729,7 @@ woal_cfg80211_change_virtual_intf(struct wiphy *wiphy, && (priv->wdev->iftype == NL80211_IFTYPE_AP || priv->wdev->iftype == NL80211_IFTYPE_P2P_GO || priv->wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) { - /* if we support wifi direct && priv->bss_type == wifi_direct, and + /* if we support wifi direct && priv->bss_type == wifi_direct, and currently the interface type is AP or GO or client, that means wpa_supplicant deinit() wifi direct interface, so we should deinit bss_role and wifi direct mode, for other bss_type, we @@ -1236,7 +1236,7 @@ woal_cfg80211_mgmt_tx(struct wiphy *wiphy, atomic_inc(&priv->phandle->tx_pending); queue_work(priv->phandle->workqueue, &priv->phandle->main_work); - /* delay 20ms to guarantee the packet has been already tx'ed becuase if + /* delay 20ms to guarantee the packet has been already tx'ed becuase if we call cfg80211_mgmt_tx_status() immediately, then wpa_supplicant will call cancel_remain_on_channel(), which may affect the mgmt frame tx */ diff --git a/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c b/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c index 984400cd532f..4e9ef8850b53 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c @@ -166,7 +166,7 @@ woal_set_ap_wps_p2p_ie(moal_private * priv, t_u8 * ie, size_t len) } /* Android cmd format: "SET_AP_WPS_P2P_IE 1" -- beacon IE - "SET_AP_WPS_P2P_IE 2" -- proberesp IE "SET_AP_WPS_P2P_IE 4" -- assocresp + "SET_AP_WPS_P2P_IE 2" -- proberesp IE "SET_AP_WPS_P2P_IE 4" -- assocresp IE */ if (*pos == '1') { PRINTM(MIOCTL, "Ignore set beacon ie\n"); diff --git a/drivers/net/wireless/sd8797/mlinux/moal_ioctl.c b/drivers/net/wireless/sd8797/mlinux/moal_ioctl.c index 7928d37ad015..efe6e7ddcea1 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_ioctl.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_ioctl.c @@ -102,7 +102,7 @@ extern int cfg80211_wext; Local Functions ********************************************************/ #ifdef STA_SUPPORT -/** +/** * @brief This function converts region string to region code * * @param region_string Region string @@ -129,11 +129,11 @@ region_string_2_region_code(char *region_string) } #endif -/** +/** * @brief Copy multicast table - * + * * @param mlist A pointer to mlan_multicast_list structure - * @param dev A pointer to net_device structure + * @param dev A pointer to net_device structure * * @return Number of multicast addresses */ @@ -161,11 +161,11 @@ woal_copy_mcast_addr(mlan_multicast_list * mlist, struct net_device *dev) return i; } -/** - * @brief Fill in wait queue - * +/** + * @brief Fill in wait queue + * * @param priv A pointer to moal_private structure - * @param wait A pointer to wait_queue structure + * @param wait A pointer to wait_queue structure * @param wait_option Wait option * * @return N/A @@ -199,11 +199,11 @@ woal_fill_wait_queue(moal_private * priv, wait_queue * wait, t_u8 wait_option) return; } -/** +/** * @brief Wait mlan ioctl complete - * + * * @param priv A pointer to moal_private structure - * @param req A pointer to mlan_ioctl_req structure + * @param req A pointer to mlan_ioctl_req structure * @param wait_option Wait option * * @return N/A @@ -357,9 +357,9 @@ woal_cac_period_block_cmd(moal_private * priv, pmlan_ioctl_req req) Global Functions ********************************************************/ -/** +/** * @brief Send ioctl request to MLAN - * + * * @param priv A pointer to moal_private structure * @param req A pointer to mlan_ioctl_req buffer * @param wait_option Wait option (MOAL_WAIT or MOAL_NO_WAIT) @@ -422,7 +422,7 @@ woal_request_ioctl(moal_private * priv, mlan_ioctl_req * req, t_u8 wait_option) if (sub_command == MLAN_OID_BSS_START) { mlan_ds_bss *bss; bss = (mlan_ds_bss *) req->pbuf; - /* + /* * Bss delay start after channel report received, * not block the driver by delay executing. This is * because a BSS_START cmd is always executed right @@ -434,7 +434,7 @@ woal_request_ioctl(moal_private * priv, mlan_ioctl_req * req, t_u8 wait_option) priv->phandle->delay_bss_start = MTRUE; memcpy(&priv->phandle->delay_ssid_bssid, &bss->param.ssid_bssid, sizeof(mlan_ssid_bssid)); - /* TODO: return success to allow the half below of routines of + /* TODO: return success to allow the half below of routines of which calling BSS start to execute */ status = MLAN_STATUS_SUCCESS; goto done; @@ -498,9 +498,9 @@ woal_request_ioctl(moal_private * priv, mlan_ioctl_req * req, t_u8 wait_option) return status; } -/** +/** * @brief Send set MAC address request to MLAN - * + * * @param priv A pointer to moal_private structure * * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail @@ -549,11 +549,11 @@ woal_request_set_mac_address(moal_private * priv) return status; } -/** +/** * @brief Send multicast list request to MLAN - * + * * @param priv A pointer to moal_private structure - * @param dev A pointer to net_device structure + * @param dev A pointer to net_device structure * * @return N/A */ @@ -604,9 +604,9 @@ woal_request_set_multicast_list(moal_private * priv, struct net_device *dev) return; } -/** +/** * @brief Send deauth command to MLAN - * + * * @param priv A pointer to moal_private structure * @param wait_option Wait option * @param mac MAC address to deauthenticate @@ -650,11 +650,11 @@ woal_disconnect(moal_private * priv, t_u8 wait_option, t_u8 * mac) return status; } -/** +/** * @brief Send bss_start command to MLAN - * + * * @param priv A pointer to moal_private structure - * @param wait_option Wait option + * @param wait_option Wait option * @param ssid_bssid A point to mlan_ssid_bssid structure * * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail @@ -697,14 +697,14 @@ woal_bss_start(moal_private * priv, t_u8 wait_option, return status; } -/** +/** * @brief Get BSS info * * @param priv A pointer to moal_private structure * @param wait_option Wait option * @param bss_info A pointer to mlan_bss_info structure * - * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail */ mlan_status woal_get_bss_info(moal_private * priv, t_u8 wait_option, @@ -744,7 +744,7 @@ woal_get_bss_info(moal_private * priv, t_u8 wait_option, } #ifdef STA_SUPPORT -/** +/** * @brief Set/Get retry count * * @param priv A pointer to moal_private structure @@ -806,7 +806,7 @@ woal_set_get_retry(moal_private * priv, t_u32 action, return ret; } -/** +/** * @brief Set/Get RTS threshold * * @param priv A pointer to moal_private structure @@ -866,7 +866,7 @@ woal_set_get_rts(moal_private * priv, t_u32 action, return ret; } -/** +/** * @brief Set/Get Fragment threshold * * @param priv A pointer to moal_private structure @@ -926,7 +926,7 @@ woal_set_get_frag(moal_private * priv, t_u32 action, return ret; } -/** +/** * @brief Set/Get generic IE * * @param priv A pointer to moal_private structure @@ -992,7 +992,7 @@ woal_set_get_gen_ie(moal_private * priv, t_u32 action, t_u8 * ie, int *ie_len) return ret; } -/** +/** * @brief Set/Get TX power * * @param priv A pointer to moal_private structure @@ -1035,7 +1035,7 @@ woal_set_get_tx_power(moal_private * priv, return ret; } -/** +/** * @brief Set/Get IEEE power management * * @param priv A pointer to moal_private structure @@ -1094,7 +1094,7 @@ woal_set_get_power_mgmt(moal_private * priv, *disabled = pm_cfg->param.ps_mode; #ifdef STA_CFG80211 - /* If set is invoked from other than iw i.e iwconfig, wiphy IEEE power save + /* If set is invoked from other than iw i.e iwconfig, wiphy IEEE power save mode should be updated */ if (IS_STA_CFG80211(cfg80211_wext) && (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && (action == MLAN_ACT_SET)) { @@ -1115,10 +1115,10 @@ woal_set_get_power_mgmt(moal_private * priv, /** * @brief Set region code - * + * * @param priv A pointer to moal_private structure * @param region A pointer to region string - * + * * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail */ mlan_status @@ -1148,14 +1148,14 @@ woal_set_region_code(moal_private * priv, char *region) return ret; } -/** +/** * @brief Set/Get data rate * * @param priv A pointer to moal_private structure * @param action Action set or get * @param datarate A pointer to mlan_rate_cfg_t structure * - * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail */ mlan_status woal_set_get_data_rate(moal_private * priv, @@ -1197,14 +1197,14 @@ woal_set_get_data_rate(moal_private * priv, } #endif -/** +/** * @brief Send get FW info request to MLAN - * + * * @param priv A pointer to moal_private structure - * @param wait_option Wait option + * @param wait_option Wait option * @param fw_info FW information * - * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail */ mlan_status woal_request_get_fw_info(moal_private * priv, t_u8 wait_option, @@ -1256,14 +1256,14 @@ woal_request_get_fw_info(moal_private * priv, t_u8 wait_option, } #ifdef PROC_DEBUG -/** +/** * @brief Get debug info * * @param priv A pointer to moal_private structure * @param wait_option Wait option * @param debug_info A pointer to mlan_debug_info structure * - * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail */ mlan_status woal_get_debug_info(moal_private * priv, t_u8 wait_option, @@ -1303,14 +1303,14 @@ woal_get_debug_info(moal_private * priv, t_u8 wait_option, return status; } -/** +/** * @brief Set debug info * * @param priv A pointer to moal_private structure * @param wait_option Wait option * @param debug_info A pointer to mlan_debug_info structure * - * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail */ mlan_status woal_set_debug_info(moal_private * priv, t_u8 wait_option, @@ -1354,9 +1354,9 @@ woal_set_debug_info(moal_private * priv, t_u8 wait_option, #endif /* PROC_DEBUG */ #if defined(STA_WEXT) || defined(UAP_WEXT) -/** +/** * @brief host command ioctl function - * + * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure * @return 0 --success, otherwise fail @@ -1434,9 +1434,9 @@ woal_host_command(moal_private * priv, struct iwreq *wrq) #endif #if defined(WIFI_DIRECT_SUPPORT) || defined(UAP_SUPPORT) -/** +/** * @brief host command ioctl function - * + * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail @@ -1537,9 +1537,9 @@ woal_hostcmd_ioctl(struct net_device *dev, struct ifreq *req) } #endif -/** +/** * @brief CUSTOM_IE ioctl handler - * + * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail @@ -1620,9 +1620,9 @@ woal_custom_ie_ioctl(struct net_device *dev, struct ifreq *req) return ret; } -/** +/** * @brief send raw data packet ioctl function - * + * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail @@ -1695,9 +1695,9 @@ woal_send_host_packet(struct net_device *dev, struct ifreq *req) } #if defined(UAP_WEXT) -/** +/** * @brief Set/Get CUSTOM_IE ioctl handler - * + * * @param mask Mask to set or clear from caller * @param ie IE buffer to set for beacon * @param ie_len Length of the IE @@ -1750,9 +1750,9 @@ woal_set_get_custom_ie(moal_private * priv, t_u16 mask, t_u8 * ie, int ie_len) } #endif /* defined(HOST_TXRX_MGMT_FRAME) && defined(UAP_WEXT) */ -/** +/** * @brief ioctl function get BSS type - * + * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail @@ -1781,10 +1781,10 @@ woal_get_bss_type(struct net_device *dev, struct ifreq *req) #if defined(STA_WEXT) || defined(UAP_WEXT) /** * @brief Set/Get BSS role - * + * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure - * + * * @return 0 --success, otherwise fail */ int @@ -1918,7 +1918,7 @@ woal_set_get_bss_role(moal_private * priv, struct iwreq *wrq) #endif #endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */ -/** +/** * @brief Get Host Sleep parameters * * @param priv A pointer to moal_private structure @@ -1926,7 +1926,7 @@ woal_set_get_bss_role(moal_private * priv, struct iwreq *wrq) * @param wait_option Wait option (MOAL_WAIT or MOAL_NO_WAIT) * @param hscfg A pointer to mlan_ds_hs_cfg structure * - * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail */ mlan_status woal_set_get_hs_params(moal_private * priv, t_u16 action, t_u8 wait_option, @@ -1974,7 +1974,7 @@ woal_set_get_hs_params(moal_private * priv, t_u16 action, t_u8 wait_option, * @param wait_option wait option * * @return MLAN_STATUS_SUCCESS, MLAN_STATUS_PENDING, - * or MLAN_STATUS_FAILURE + * or MLAN_STATUS_FAILURE */ mlan_status woal_cancel_hs(moal_private * priv, t_u8 wait_option) @@ -1994,7 +1994,7 @@ woal_cancel_hs(moal_private * priv, t_u8 wait_option) } /** @brief This function enables the host sleep - * + * * @param priv A Pointer to the moal_private structure * @return MTRUE or MFALSE */ @@ -2075,9 +2075,9 @@ woal_enable_hs(moal_private * priv) return hs_actived; } -/** - * @brief This function send soft_reset command to firmware - * +/** + * @brief This function send soft_reset command to firmware + * * @param handle A pointer to moal_handle structure * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING on success, otherwise failure code */ @@ -2108,14 +2108,14 @@ woal_request_soft_reset(moal_handle * handle) return ret; } -/** +/** * @brief Set wapi enable * * @param priv A pointer to moal_private structure * @param wait_option Wait option * @param enable MTRUE or MFALSE * - * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail */ mlan_status woal_set_wapi_enable(moal_private * priv, t_u8 wait_option, t_u32 enable) @@ -2149,9 +2149,9 @@ woal_set_wapi_enable(moal_private * priv, t_u8 wait_option, t_u32 enable) return status; } -/** - * @brief Get version - * +/** + * @brief Get version + * * @param handle A pointer to moal_handle structure * @param version A pointer to version buffer * @param max_len max length of version buffer @@ -2218,7 +2218,7 @@ woal_get_driver_version(moal_private * priv, struct ifreq *req) * @param priv A pointer to moal_private structure * @param ireq A pointer to ifreq structure * - * @return 0 --success, otherwise fail + * @return 0 --success, otherwise fail */ int woal_get_driver_verext(moal_private * priv, struct ifreq *ireq) @@ -2293,7 +2293,7 @@ woal_get_driver_verext(moal_private * priv, struct ifreq *ireq) * @param priv A pointer to moal_private structure * @param drvdbg Driver debug level * - * @return 0 --success, otherwise fail + * @return 0 --success, otherwise fail */ int woal_set_drvdbg(moal_private * priv, t_u32 drvdbg) @@ -2334,7 +2334,7 @@ woal_set_drvdbg(moal_private * priv, t_u32 drvdbg) * @param pmgmt_subtype_mask A Pointer to mgmt frame subtype mask * @param wait_option wait option (MOAL_WAIT or MOAL_NO_WAIT) * - * @return 0 --success, otherwise fail + * @return 0 --success, otherwise fail */ int woal_reg_rx_mgmt_ind(moal_private * priv, t_u16 action, @@ -2374,14 +2374,14 @@ woal_reg_rx_mgmt_ind(moal_private * priv, t_u16 action, return ret; } -/** +/** * @brief Set/Get Transmit beamforming configuration * * @param priv A pointer to moal_private structure * @param action Action: set or get * @param tx_bf_cfg A pointer to tx_bf_cfg structure * - * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail */ mlan_status woal_set_get_tx_bf_cfg(moal_private * priv, t_u16 action, @@ -2428,9 +2428,9 @@ woal_set_get_tx_bf_cfg(moal_private * priv, t_u16 action, return ret; } -/** - * @brief Handle ioctl resp - * +/** + * @brief Handle ioctl resp + * * @param priv Pointer to moal_private structure * @param req Pointer to mlan_ioctl_req structure * @@ -2479,13 +2479,13 @@ woal_process_ioctl_resp(moal_private * priv, mlan_ioctl_req * req) return; } -/** +/** * @brief Get PM info * * @param priv A pointer to moal_private structure * @param pm_info A pointer to mlan_ds_ps_info structure * - * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail */ mlan_status woal_get_pm_info(moal_private * priv, mlan_ds_ps_info * pm_info) @@ -2582,7 +2582,7 @@ woal_set_deep_sleep(moal_private * priv, t_u8 wait_option, BOOLEAN bdeep_sleep, return ret; } -/** +/** * @brief Cancel CAC period block * * @param priv A pointer to moal_private structure @@ -2655,14 +2655,14 @@ woal_11h_channel_check_ioctl(moal_private * priv) } #if defined(WIFI_DIRECT_SUPPORT) -/** - * @brief set/get wifi direct mode +/** + * @brief set/get wifi direct mode * * @param priv A pointer to moal_private structure * @param action set or get * @param mode A pointer to wifi direct mode * - * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail */ mlan_status woal_cfg80211_wifi_direct_mode_cfg(moal_private * priv, t_u16 action, @@ -2697,14 +2697,14 @@ woal_cfg80211_wifi_direct_mode_cfg(moal_private * priv, t_u16 action, return ret; } -/** - * @brief set remain channel +/** + * @brief set remain channel * * @param priv A pointer to moal_private structure - * @param wait_option Wait option + * @param wait_option Wait option * @param pchan A pointer to mlan_ds_remain_chan structure * - * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail */ mlan_status woal_set_remain_channel_ioctl(moal_private * priv, t_u8 wait_option, @@ -2740,14 +2740,14 @@ woal_set_remain_channel_ioctl(moal_private * priv, t_u8 wait_option, #endif /* WIFI_DIRECT_SUPPORT */ #ifdef STA_SUPPORT -/** +/** * @brief Get RSSI info * * @param priv A pointer to moal_private structure * @param wait_option Wait option * @param signal A pointer tp mlan_ds_get_signal structure * - * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail */ mlan_status woal_get_signal_info(moal_private * priv, t_u8 wait_option, @@ -2794,7 +2794,7 @@ woal_get_signal_info(moal_private * priv, t_u8 wait_option, return status; } -/** +/** * @brief Get scan table * * @param priv A pointer to moal_private structure @@ -2843,14 +2843,14 @@ woal_get_scan_table(moal_private * priv, t_u8 wait_option, return status; } -/** +/** * @brief Request a scan * * @param priv A pointer to moal_private structure - * @param wait_option Wait option + * @param wait_option Wait option * @param req_ssid A pointer to mlan_802_11_ssid structure * - * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail */ mlan_status woal_request_scan(moal_private * priv, @@ -2916,11 +2916,11 @@ woal_request_scan(moal_private * priv, return ret; } -/** +/** * @brief Change Adhoc Channel - * + * * @param priv A pointer to moal_private structure - * @param channel The channel to be set. + * @param channel The channel to be set. * * @return MLAN_STATUS_SUCCESS--success, MLAN_STATUS_FAILURE--fail */ @@ -3011,14 +3011,14 @@ woal_change_adhoc_chan(moal_private * priv, int channel) return ret; } -/** +/** * @brief Find the best network to associate * * @param priv A pointer to moal_private structure - * @param wait_option Wait option + * @param wait_option Wait option * @param ssid_bssid A pointer to mlan_ssid_bssid structure * - * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail */ mlan_status woal_find_best_network(moal_private * priv, t_u8 wait_option, @@ -3069,14 +3069,14 @@ woal_find_best_network(moal_private * priv, t_u8 wait_option, return ret; } -/** +/** * @brief Get authentication mode * * @param priv A pointer to moal_private structure * @param wait_option Wait option * @param auth_mode A pointer to authentication mode * - * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail */ mlan_status woal_get_auth_mode(moal_private * priv, t_u8 wait_option, t_u32 * auth_mode) @@ -3112,14 +3112,14 @@ woal_get_auth_mode(moal_private * priv, t_u8 wait_option, t_u32 * auth_mode) return status; } -/** +/** * @brief Get encrypt mode * * @param priv A pointer to moal_private structure * @param wait_option Wait option * @param encrypt_mode A pointer to encrypt mode * - * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail */ mlan_status woal_get_encrypt_mode(moal_private * priv, t_u8 wait_option, @@ -3157,14 +3157,14 @@ woal_get_encrypt_mode(moal_private * priv, t_u8 wait_option, return status; } -/** +/** * @brief Get WPA enable * * @param priv A pointer to moal_private structure * @param wait_option Wait option * @param enable A pointer to wpa enable status * - * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail */ mlan_status woal_get_wpa_enable(moal_private * priv, t_u8 wait_option, t_u32 * enable) @@ -3201,14 +3201,14 @@ woal_get_wpa_enable(moal_private * priv, t_u8 wait_option, t_u32 * enable) return status; } -/** +/** * @brief Set authentication mode * * @param priv A pointer to moal_private structure * @param wait_option Wait option * @param auth_mode Authentication mode * - * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail */ mlan_status woal_set_auth_mode(moal_private * priv, t_u8 wait_option, t_u32 auth_mode) @@ -3242,14 +3242,14 @@ woal_set_auth_mode(moal_private * priv, t_u8 wait_option, t_u32 auth_mode) return status; } -/** +/** * @brief Set encrypt mode * * @param priv A pointer to moal_private structure * @param wait_option Wait option * @param encrypt_mode Encryption mode * - * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail */ mlan_status woal_set_encrypt_mode(moal_private * priv, t_u8 wait_option, t_u32 encrypt_mode) @@ -3283,14 +3283,14 @@ woal_set_encrypt_mode(moal_private * priv, t_u8 wait_option, t_u32 encrypt_mode) return status; } -/** +/** * @brief Set wpa enable * * @param priv A pointer to moal_private structure * @param wait_option Wait option * @param enable MTRUE or MFALSE * - * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail */ mlan_status woal_set_wpa_enable(moal_private * priv, t_u8 wait_option, t_u32 enable) @@ -3324,13 +3324,13 @@ woal_set_wpa_enable(moal_private * priv, t_u8 wait_option, t_u32 enable) return status; } -/** - * @brief enable wep key - * +/** + * @brief enable wep key + * * @param priv A pointer to moal_private structure * @param wait_option Wait option * - * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail */ mlan_status woal_enable_wep_key(moal_private * priv, t_u8 wait_option) @@ -3366,14 +3366,14 @@ woal_enable_wep_key(moal_private * priv, t_u8 wait_option) return status; } -/** +/** * @brief Request user scan * * @param priv A pointer to moal_private structure - * @param wait_option Wait option + * @param wait_option Wait option * @param scan_cfg A pointer to wlan_user_scan_config structure * - * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail */ mlan_status woal_request_userscan(moal_private * priv, @@ -3427,14 +3427,14 @@ woal_request_userscan(moal_private * priv, return ret; } -/** - * @brief set scan time +/** + * @brief set scan time * * @param priv A pointer to moal_private structure * @param passive_scan_time passive scan time * @param specific_scan_time specific scan time * - * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail */ static mlan_status woal_set_scan_time(moal_private * priv, t_u16 passive_scan_time, @@ -3467,13 +3467,13 @@ woal_set_scan_time(moal_private * priv, t_u16 passive_scan_time, return ret; } -/** +/** * @brief request scan * * @param priv A pointer to moal_private structure * @param scan_cfg A pointer to wlan_user_scan_cfg structure * - * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail */ mlan_status woal_do_scan(moal_private * priv, wlan_user_scan_cfg * scan_cfg) @@ -3539,14 +3539,14 @@ woal_find_essid(moal_private * priv, mlan_ssid_bssid * ssid_bssid) return ret; } -/** +/** * @brief Request user scan * * @param priv A pointer to moal_private structure - * @param wait_option Wait option + * @param wait_option Wait option * @param scan_cfg A pointer to wlan_bgscan_cfg structure * - * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail */ mlan_status woal_request_bgscan(moal_private * priv, @@ -3588,14 +3588,14 @@ woal_request_bgscan(moal_private * priv, return ret; } -/** +/** * @brief set bgscan config * * @param priv A pointer to moal_private structure * @param buf A pointer to scan command buf * @param length buf length * - * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail */ mlan_status woal_set_bg_scan(moal_private * priv, char *buf, int length) @@ -3678,12 +3678,12 @@ woal_set_bg_scan(moal_private * priv, char *buf, int length) return ret; } -/** +/** * @brief stop bg scan * * @param priv A pointer to moal_private structure * - * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail */ mlan_status woal_stop_bg_scan(moal_private * priv) @@ -3699,12 +3699,12 @@ woal_stop_bg_scan(moal_private * priv) LEAVE(); } -/** +/** * @brief set bgscan config * * @param handle A pointer to moal_handle structure * - * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail */ void woal_reconfig_bgscan(moal_handle * handle) @@ -3724,13 +3724,13 @@ woal_reconfig_bgscan(moal_handle * handle) } } -/** - * @brief set rssi low threshold +/** + * @brief set rssi low threshold * * @param priv A pointer to moal_private structure * @param scan_type MLAN_SCAN_TYPE_ACTIVE/MLAN_SCAN_TYPE_PASSIVE * - * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail */ mlan_status woal_set_rssi_low_threshold(moal_private * priv, char *rssi) @@ -3771,13 +3771,13 @@ woal_set_rssi_low_threshold(moal_private * priv, char *rssi) return ret; } -/** - * @brief Get power mode - * +/** + * @brief Get power mode + * * @param priv A pointer to moal_private structure * @param powermode A pointer to powermode buf - * - * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail */ mlan_status woal_get_powermode(moal_private * priv, int *powermode) @@ -3803,13 +3803,13 @@ woal_get_powermode(moal_private * priv, int *powermode) return ret; } -/** - * @brief set scan type +/** + * @brief set scan type * * @param priv A pointer to moal_private structure * @param scan_type MLAN_SCAN_TYPE_ACTIVE/MLAN_SCAN_TYPE_PASSIVE * - * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail */ mlan_status woal_set_scan_type(moal_private * priv, t_u32 scan_type) @@ -3841,13 +3841,13 @@ woal_set_scan_type(moal_private * priv, t_u32 scan_type) return ret; } -/** +/** * @brief set power mode * * @param priv A pointer to moal_private structure * @param powermode A pointer to powermode string. * - * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail */ mlan_status woal_set_powermode(moal_private * priv, char *powermode) @@ -3878,14 +3878,14 @@ woal_set_powermode(moal_private * priv, char *powermode) return ret; } -/** +/** * @brief set combo scan * * @param priv A pointer to moal_private structure * @param buf A pointer to scan command buf * @param length buf length * - * @return 0 -- success, otherwise fail + * @return 0 -- success, otherwise fail */ int woal_set_combo_scan(moal_private * priv, char *buf, int length) @@ -3999,13 +3999,13 @@ woal_set_combo_scan(moal_private * priv, char *buf, int length) return ret; } -/** - * @brief Get band - * +/** + * @brief Get band + * * @param priv A pointer to moal_private structure * @param band A pointer to band buf - * - * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail */ mlan_status woal_get_band(moal_private * priv, int *band) @@ -4046,13 +4046,13 @@ woal_get_band(moal_private * priv, int *band) return ret; } -/** +/** * @brief set band * * @param priv A pointer to moal_private structure * @param pband A pointer to band string. * - * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail */ mlan_status woal_set_band(moal_private * priv, char *pband) @@ -4138,20 +4138,20 @@ woal_set_band(moal_private * priv, char *pband) return ret; } -/** +/** * @brief Add RX Filter * * @param priv A pointer to moal_private structure * @param rxfilter A pointer to rxfilter string. * - * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail */ mlan_status woal_add_rxfilter(moal_private * priv, char *rxfilter) { mlan_status ret = MLAN_STATUS_SUCCESS; ENTER(); - /* Android command: "DRIVER RXFILTER-ADD 0" "DRIVER RXFILTER-ADD 1" "DRIVER + /* Android command: "DRIVER RXFILTER-ADD 0" "DRIVER RXFILTER-ADD 1" "DRIVER RXFILTER-ADD 3" */ if (*rxfilter == '0') { PRINTM(MIOCTL, "Add IPV4 multicast filter\n"); @@ -4175,13 +4175,13 @@ woal_add_rxfilter(moal_private * priv, char *rxfilter) return ret; } -/** +/** * @brief Remove RX Filter * * @param priv A pointer to moal_private structure * @param rxfilter A pointer to rxfilter string. * - * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail */ mlan_status woal_remove_rxfilter(moal_private * priv, char *rxfilter) @@ -4212,11 +4212,11 @@ woal_remove_rxfilter(moal_private * priv, char *rxfilter) /** * @brief Set QoS configuration - * + * * @param priv A pointer to moal_private structure * @param qos_cfg A pointer to QoS configuration structure - * - * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail */ mlan_status woal_set_qos_cfg(moal_private * priv, char *qos_cfg) @@ -4253,11 +4253,11 @@ woal_set_qos_cfg(moal_private * priv, char *qos_cfg) /** * @brief Set sleep period - * + * * @param priv A pointer to moal_private structure * @param psleeppd A pointer to sleep period configuration structure - * - * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail */ int woal_set_sleeppd(moal_private * priv, char *psleeppd) diff --git a/drivers/net/wireless/sd8797/mlinux/moal_main.c b/drivers/net/wireless/sd8797/mlinux/moal_main.c index 820c1267cc78..47c3252483a4 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_main.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_main.c @@ -182,7 +182,7 @@ int drv_mode = DRV_MODE_UAP; /** Semaphore for add/remove card */ struct semaphore AddRemoveCardSem; /** - * the maximum number of adapter supported + * the maximum number of adapter supported **/ #define MAX_MLAN_ADAPTER 2 /** @@ -359,9 +359,9 @@ woal_update_drv_tbl(moal_handle * handle, int drv_mode_local) return ret; } -/** +/** * @brief This function initializes software - * + * * @param handle A pointer to moal_handle structure * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE @@ -498,9 +498,9 @@ woal_init_sw(moal_handle * handle) return ret; } -/** +/** * @brief This function frees the structure of moal_handle - * + * * @param handle A pointer to moal_handle structure * * @return N/A @@ -545,7 +545,7 @@ woal_free_moal_handle(moal_handle * handle) /** * @brief WOAL get one line data from ASCII format data - * + * * @param data Source data * @param size Source data length * @param line_pos Destination data @@ -582,7 +582,7 @@ parse_cfg_get_line(t_u8 * data, t_size size, t_u8 * line_pos) return strlen(line_pos); } -/** +/** * @brief Process register access request * @param type_string String format Register type * @param offset_string String format Register offset @@ -650,7 +650,7 @@ woal_process_regrdwr(moal_handle * handle, t_u8 * type_string, /** * @brief WOAL parse ASCII format data to MAC address - * + * * @param handle MOAL handle * @param data Source data * @param size data length @@ -791,7 +791,7 @@ woal_process_init_cfg(moal_handle * handle, t_u8 * data, t_size size) /** * @brief WOAL set user defined init data and param - * + * * @param handle MOAL handle structure * @return MLAN_STATUS_SUCCESS--success, otherwise--fail */ @@ -828,9 +828,9 @@ woal_set_user_init_data(moal_handle * handle) return ret; } -/** +/** * @brief Add interfaces DPC - * + * * @param handle A pointer to moal_handle structure * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE @@ -880,9 +880,9 @@ woal_add_card_dpc(moal_handle * handle) return ret; } -/** +/** * @brief Download and Initialize firmware DPC - * + * * @param handle A pointer to moal_handle structure * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE @@ -961,9 +961,9 @@ woal_init_fw_dpc(moal_handle * handle) return ret; } -/** +/** * @brief Request firmware DPC - * + * * @param handle A pointer to moal_handle structure * @param firmware A pointer to firmware image * @@ -1005,10 +1005,10 @@ woal_request_fw_dpc(moal_handle * handle, const struct firmware *firmware) return ret; } -/** +/** * @brief Request firmware callback * This function is invoked by request_firmware_nowait system call - * + * * @param firmware A pointer to firmware image * @param context A pointer to moal_handle structure * @@ -1027,9 +1027,9 @@ woal_request_fw_callback(const struct firmware *firmware, void *context) return; } -/** +/** * @brief Download firmware using helper - * + * * @param handle A pointer to moal_handle structure * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE @@ -1104,9 +1104,9 @@ woal_request_fw(moal_handle * handle) return ret; } -/** +/** * @brief This function initializes firmware - * + * * @param handle A pointer to moal_handle structure * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE @@ -1129,11 +1129,11 @@ woal_init_fw(moal_handle * handle) return ret; } -/** +/** * @brief This function will fill in the mlan_buffer - * + * * @param pmbuf A pointer to mlan_buffer - * @param skb A pointer to struct sk_buff + * @param skb A pointer to struct sk_buff * * @return N/A */ @@ -1169,7 +1169,7 @@ woal_fill_mlan_buffer(moal_private * priv, skb->priority = tid; /* Record the current time the packet was queued; used to determine the - amount of time the packet was queued in the driver before it was sent to + amount of time the packet was queued in the driver before it was sent to the firmware. The delay is then sent along with the packet to the firmware for aggregate delay calculation for stats and MSDU lifetime expiry. */ @@ -1222,13 +1222,13 @@ const struct net_device_ops woal_netdev_ops = { #endif /** - * @brief This function initializes the private structure - * and dev structure for station mode - * + * @brief This function initializes the private structure + * and dev structure for station mode + * * @param dev A pointer to net_device structure * @param priv A pointer to moal_private structure * - * @return MLAN_STATUS_SUCCESS + * @return MLAN_STATUS_SUCCESS */ static mlan_status woal_init_sta_dev(struct net_device *dev, moal_private * priv) @@ -1299,9 +1299,9 @@ const struct net_device_ops woal_uap_netdev_ops = { #endif /** - * @brief This function initializes the private structure - * and dev structure for uap mode - * + * @brief This function initializes the private structure + * and dev structure for uap mode + * * @param dev A pointer to net_device structure * @param priv A pointer to moal_private structure * @@ -1358,8 +1358,8 @@ woal_init_uap_dev(struct net_device *dev, moal_private * priv) /** * @brief This function adds a new interface. It will - * allocate, initialize and register the device. - * + * allocate, initialize and register the device. + * * @param handle A pointer to moal_handle structure * @param bss_index BSS index number * @param bss_type BSS type @@ -1532,9 +1532,9 @@ woal_add_interface(moal_handle * handle, t_u8 bss_index, t_u8 bss_type) return NULL; } -/** +/** * @brief This function removes an interface. - * + * * @param handle A pointer to the moal_handle structure * @param bss_index BSS index number * @@ -1605,9 +1605,9 @@ woal_remove_interface(moal_handle * handle, t_u8 bss_index) return; } -/** +/** * @brief Send FW shutdown command to MLAN - * + * * @param priv A pointer to moal_private structure * @param wait_option Wait option * @@ -1647,7 +1647,7 @@ woal_shutdown_fw(moal_private * priv, t_u8 wait_option) return status; } -/** +/** * @brief Return hex value of a give character * * @param chr Character to be converted @@ -1673,7 +1673,7 @@ woal_hexval(char chr) /** * @brief This function cancel all works in the queue * and destroy the main workqueue. - * + * * @param handle A pointer to moal_handle * * @return N/A @@ -1811,7 +1811,7 @@ wifi_add_dev(void) /** * @brief Removes an wifi device - * + * * @return N/A */ static void @@ -1829,9 +1829,9 @@ wifi_del_dev(void) Global Functions ********************************************************/ -/** +/** * @brief This function opens the network device - * + * * @param dev A pointer to net_device structure * * @return 0 --success, otherwise fail @@ -1870,9 +1870,9 @@ woal_open(struct net_device *dev) return 0; } -/** +/** * @brief This function closes the network device - * + * * @param dev A pointer to net_device structure * * @return 0 @@ -1892,9 +1892,9 @@ woal_close(struct net_device *dev) return 0; } -/** +/** * @brief This function sets the MAC address to firmware. - * + * * @param dev A pointer to mlan_private structure * @param addr MAC address to set * @@ -2024,10 +2024,10 @@ woal_mlan_debug_info(moal_private * priv) LEAVE(); } -/** +/** * @brief This function handles the timeout of packet * transmission - * + * * @param dev A pointer to net_device structure * * @return N/A @@ -2052,9 +2052,9 @@ woal_tx_timeout(struct net_device *dev) LEAVE(); } -/** +/** * @brief This function returns the network statistics - * + * * @param dev A pointer to net_device structure * * @return A pointer to net_device_stats structure @@ -2067,9 +2067,9 @@ woal_get_stats(struct net_device *dev) } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) -/** +/** * @brief This function handles wmm queue select - * + * * @param dev A pointer to net_device structure * @param skb A pointer to sk_buff structure * @@ -2108,9 +2108,9 @@ woal_select_queue(struct net_device * dev, struct sk_buff * skb) } #endif -/** +/** * @brief This function handles packet transmission - * + * * @param skb A pointer to sk_buff structure * @param dev A pointer to net_device structure * @@ -2189,14 +2189,14 @@ woal_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } -/** +/** * @brief Convert ascii string to Hex integer - * + * * @param d A pointer to integer buf - * @param s A pointer to ascii string + * @param s A pointer to ascii string * @param dlen The byte number of ascii string in hex * - * @return Number of integer + * @return Number of integer */ int woal_ascii2hex(t_u8 * d, char *s, t_u32 dlen) @@ -2285,7 +2285,7 @@ woal_atox(char *a) return i; } -/** +/** * @brief Extension of strsep lib command. This function will also take care * escape character * @@ -2309,7 +2309,7 @@ woal_strsep(char **s, char delim, char esc) for (sb = *s; *sb != '\0'; ++sb) { if (*sb == esc && *(sb + 1) == esc) { - /* + /* * We get a esc + esc seq then keep the one esc * and chop off the other esc character */ @@ -2317,7 +2317,7 @@ woal_strsep(char **s, char delim, char esc) continue; } if (*sb == esc && *(sb + 1) == delim) { - /* + /* * We get a delim + esc seq then keep the delim * and chop off the esc character */ @@ -2342,8 +2342,8 @@ woal_strsep(char **s, char delim, char esc) /** * @brief Convert mac address from string to t_u8 buffer. * - * @param mac_addr The buffer to store the mac address in. - * @param buf The source of mac address which is a string. + * @param mac_addr The buffer to store the mac address in. + * @param buf The source of mac address which is a string. * * @return N/A */ @@ -2365,9 +2365,9 @@ woal_mac2u8(t_u8 * mac_addr, char *buf) } #ifdef STA_SUPPORT -/** +/** * @brief This function sets multicast addresses to firmware - * + * * @param dev A pointer to net_device structure * * @return N/A @@ -2385,9 +2385,9 @@ woal_set_multicast_list(struct net_device *dev) /** * @brief This function initializes the private structure * and set default value to the member of moal_private. - * + * * @param priv A pointer to moal_private structure - * @param wait_option Wait option + * @param wait_option Wait option * * @return N/A */ @@ -2440,7 +2440,7 @@ woal_init_priv(moal_private * priv, t_u8 wait_option) } /** - * @brief Reset all interfaces if all_intf flag is TRUE, + * @brief Reset all interfaces if all_intf flag is TRUE, * otherwise specified interface only * * @param priv A pointer to moal_private structure @@ -2448,7 +2448,7 @@ woal_init_priv(moal_private * priv, t_u8 wait_option) * @param all_intf TRUE : all interfaces * FALSE : current interface only * - * @return MLAN_STATUS_SUCCESS --success, otherwise fail + * @return MLAN_STATUS_SUCCESS --success, otherwise fail */ int woal_reset_intf(moal_private * priv, t_u8 wait_option, int all_intf) @@ -2553,9 +2553,9 @@ woal_reset_intf(moal_private * priv, t_u8 wait_option, int all_intf) return ret; } -/** - * @brief This function return the point to structure moal_private - * +/** + * @brief This function return the point to structure moal_private + * * @param handle Pointer to structure moal_handle * @param bss_index BSS index number * @@ -2582,9 +2582,9 @@ woal_bss_index_to_priv(moal_handle * handle, t_u8 bss_index) return NULL; } -/** +/** * @brief This function alloc mlan_buffer. - * @param handle A pointer to moal_handle structure + * @param handle A pointer to moal_handle structure * @param size buffer size to allocate * * @return mlan_buffer pointer or NULL @@ -2615,7 +2615,7 @@ woal_alloc_mlan_buffer(moal_handle * handle, int size) return pmbuf; } -/** +/** * @brief This function alloc mlan_ioctl_req. * * @param size buffer size to allocate @@ -2648,9 +2648,9 @@ woal_alloc_mlan_ioctl_req(int size) return req; } -/** +/** * @brief This function frees mlan_buffer. - * @param handle A pointer to moal_handle structure + * @param handle A pointer to moal_handle structure * @param pmbuf Pointer to mlan_buffer * * @return N/A @@ -2674,9 +2674,9 @@ woal_free_mlan_buffer(moal_handle * handle, pmlan_buffer pmbuf) #ifdef STA_WEXT #endif -/** +/** * @brief This function handles events generated by firmware - * + * * @param priv A pointer to moal_private structure * @param payload A pointer to payload buffer * @param len Length of the payload @@ -2941,10 +2941,10 @@ woal_reassociation_thread(void *data) return MLAN_STATUS_SUCCESS; } -/** +/** * @brief This function triggers re-association by waking up * re-assoc thread. - * + * * @param context A pointer to context * @return N/A */ @@ -2967,9 +2967,9 @@ woal_reassoc_timer_func(void *context) #endif /* REASSOCIATION */ #ifdef STA_SUPPORT -/** +/** * @brief Sends disconnect event - * + * * @param priv A pointer to moal_private struct * @return N/A */ @@ -2998,7 +2998,7 @@ woal_send_disconnect_to_system(moal_private * priv) /** * @brief This function reads and displays SDIO registers for debugging - * + * * @param phandle A pointer to moal_handle * * @return N/A @@ -3071,7 +3071,7 @@ woal_sdio_reg_dbg(moal_handle * phandle) /** * @brief This function displays extra MOAL debug information - * + * * @param priv A pointer to moal_private * @param handle A pointer to moal_handle * @param flag Indicates whether register read can be done directly @@ -3149,7 +3149,7 @@ woal_moal_debug_info(moal_private * priv, moal_handle * handle, u8 flag) /** * @brief This workqueue function handles main_process - * + * * @param work A pointer to work_struct * * @return N/A @@ -3186,9 +3186,9 @@ woal_main_work_queue(struct work_struct * work) /** * @brief Handles interrupt - * + * * @param handle A pointer to moal_handle struct - * + * * @return N/A */ void @@ -3212,8 +3212,8 @@ woal_interrupt(moal_handle * handle) /** * @brief This function adds the card. it will probe the - * card, allocate the mlan_private and initialize the device. - * + * card, allocate the mlan_private and initialize the device. + * * @param card A pointer to card * * @return A pointer to moal_handle structure @@ -3387,9 +3387,9 @@ woal_add_card(void *card) return NULL; } -/** +/** * @brief This function removes the card. - * + * * @param card A pointer to card * * @return MLAN_STATUS_SUCCESS @@ -3491,9 +3491,9 @@ woal_remove_card(void *card) return MLAN_STATUS_SUCCESS; } -/** +/** * @brief This function switch the drv_mode - * + * * @param handle A pointer to moal_handle structure * @param mode new drv_mode to switch. * @@ -3579,9 +3579,9 @@ woal_switch_drv_mode(moal_handle * handle, t_u32 mode) return status; } -/** +/** * @brief This function initializes module. - * + * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ static int @@ -3608,9 +3608,9 @@ woal_init_module(void) return ret; } -/** +/** * @brief This function cleans module - * + * * @return N/A */ static void diff --git a/drivers/net/wireless/sd8797/mlinux/moal_main.h b/drivers/net/wireless/sd8797/mlinux/moal_main.h index 0a753dabe488..cd1fdd8244c1 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_main.h +++ b/drivers/net/wireless/sd8797/mlinux/moal_main.h @@ -177,9 +177,9 @@ typedef struct _moal_drv_timer t_u32 timer_is_canceled; } moal_drv_timer, *pmoal_drv_timer; -/** +/** * @brief Timer handler - * + * * @param fcontext Timer context * * @return N/A @@ -199,9 +199,9 @@ woal_timer_handler(unsigned long fcontext) } } -/** +/** * @brief Initialize timer - * + * * @param timer Timer structure * @param TimerFunction Timer function * @param FunctionContext Timer function context @@ -226,9 +226,9 @@ woal_initialize_timer(pmoal_drv_timer timer, timer->timer_is_periodic = MFALSE; } -/** +/** * @brief Modify timer - * + * * @param timer Timer structure * @param MillisecondPeriod Time period in millisecond * @@ -242,9 +242,9 @@ woal_mod_timer(pmoal_drv_timer timer, t_u32 MillisecondPeriod) timer->timer_is_canceled = MFALSE; } -/** +/** * @brief Cancel timer - * + * * @param timer Timer structure * * @return N/A @@ -277,9 +277,9 @@ typedef struct _moal_thread void *handle; } moal_thread; -/** +/** * @brief Activate thread - * + * * @param thr Thread structure * @return N/A */ @@ -293,9 +293,9 @@ woal_activate_thread(moal_thread * thr) thr->pid = current->pid; } -/** +/** * @brief De-activate thread - * + * * @param thr Thread structure * @return N/A */ @@ -306,7 +306,7 @@ woal_deactivate_thread(moal_thread * thr) thr->pid = 0; } -/** +/** * @brief Create and run the thread * * @param threadfunc Thread function @@ -345,9 +345,9 @@ woal_create_thread(int (*threadfunc) (void *), moal_thread * thr, char *name) #define MLAN_DELAYED_CONTAINER_OF(_ptr, _type, _m) container_of(_ptr, _type, _m.work) #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) */ -/** +/** * @brief Schedule timeout - * + * * @param millisec Timeout duration in milli second * * @return N/A @@ -487,10 +487,10 @@ in4_pton(const char *src, int srclen, u8 * dst, int delim, const char **end) #define MRVDRV_DEFAULT_WATCHDOG_TIMEOUT (5 * HZ) #ifdef UAP_SUPPORT -/** Default watchdog timeout - Increase the value to avoid kernel Tx timeout message in case +/** Default watchdog timeout + Increase the value to avoid kernel Tx timeout message in case station in PS mode or left. - The default value of PS station ageout timer is 40 seconds. + The default value of PS station ageout timer is 40 seconds. Hence, the watchdog timer is set to a value higher than it. */ #define MRVDRV_DEFAULT_UAP_WATCHDOG_TIMEOUT (41 * HZ) @@ -929,9 +929,9 @@ struct _moal_handle #endif }; -/** - * @brief set trans_start for each TX queue. - * +/** + * @brief set trans_start for each TX queue. + * * @param dev A pointer to net_device structure * * @return N/A @@ -948,9 +948,9 @@ woal_set_trans_start(struct net_device *dev) dev->trans_start = jiffies; } -/** +/** * @brief Start queue - * + * * @param dev A pointer to net_device structure * * @return N/A @@ -965,9 +965,9 @@ woal_start_queue(struct net_device *dev) #endif } -/** +/** * @brief Stop queue - * + * * @param dev A pointer to net_device structure * * @return N/A @@ -990,9 +990,9 @@ woal_stop_queue(struct net_device *dev) #endif } -/** +/** * @brief wake queue - * + * * @param dev A pointer to net_device structure * * @return N/A @@ -1143,10 +1143,10 @@ hexdump(char *prompt, t_u8 * buf, int len) #define woal_cpu_to_le64(x) x #endif -/** +/** * @brief This function returns first available priv * based on the BSS role - * + * * @param handle A pointer to moal_handle * @param bss_role BSS role or MLAN_BSS_ROLE_ANY * diff --git a/drivers/net/wireless/sd8797/mlinux/moal_priv.c b/drivers/net/wireless/sd8797/mlinux/moal_priv.c index dc5cd82b7f44..e3e4b844e11b 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_priv.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_priv.c @@ -63,15 +63,15 @@ extern int cfg80211_wext; Local Functions ********************************************************/ -/** +/** * @brief Copy Rates - * + * * @param dest A pointer to destination buffer * @param pos The position for copy * @param src A pointer to source buffer * @param len Length of the source buffer * - * @return Number of rates copied + * @return Number of rates copied */ static inline int woal_copy_rates(t_u8 * dest, int pos, t_u8 * src, int len) @@ -91,7 +91,7 @@ woal_copy_rates(t_u8 * dest, int pos, t_u8 * src, int len) * * @param priv A pointer to moal_private structure * - * @return 0/MLAN_STATUS_SUCCESS --success, otherwise fail + * @return 0/MLAN_STATUS_SUCCESS --success, otherwise fail */ static int woal_warm_reset(moal_private * priv) @@ -1525,7 +1525,7 @@ woal_band_cfg(moal_private * priv, struct iwreq *wrq) } /** - * @brief Read/Write adapter registers value + * @brief Read/Write adapter registers value * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure @@ -1596,7 +1596,7 @@ woal_reg_read_write(moal_private * priv, struct iwreq *wrq) } /** - * @brief Read the EEPROM contents of the card + * @brief Read the EEPROM contents of the card * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure @@ -1665,7 +1665,7 @@ woal_read_eeprom(moal_private * priv, struct iwreq *wrq) } /** - * @brief Read/Write device memory value + * @brief Read/Write device memory value * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure @@ -1855,10 +1855,10 @@ woal_deauth(moal_private * priv, struct iwreq *wrq) /** * @brief Set/Get TX power configurations - * + * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure - * + * * @return 0 --success, otherwise fail */ static int @@ -1981,10 +1981,10 @@ woal_tx_power_cfg(moal_private * priv, struct iwreq *wrq) /** * @brief Get Tx/Rx data rates - * + * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure - * + * * @return 0 --success, otherwise fail */ static int @@ -2027,10 +2027,10 @@ woal_get_txrx_rate(moal_private * priv, struct iwreq *wrq) /** * @brief Turn on/off the sdio clock - * + * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure - * + * * @return 0/MLAN_STATUS_SUCCESS --success, otherwise fail */ static int @@ -2082,10 +2082,10 @@ woal_sdio_clock_ioctl(moal_private * priv, struct iwreq *wrq) /** * @brief Set/Get beacon interval - * + * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure - * + * * @return 0 --success, otherwise fail */ static int @@ -2147,10 +2147,10 @@ woal_beacon_interval(moal_private * priv, struct iwreq *wrq) /** * @brief Set/Get ATIM window - * + * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure - * + * * @return 0 --success, otherwise fail */ static int @@ -2210,10 +2210,10 @@ woal_atim_window(moal_private * priv, struct iwreq *wrq) /** * @brief Set/Get TX data rate - * + * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure - * + * * @return 0 --success, otherwise fail */ static int @@ -2284,10 +2284,10 @@ woal_set_get_txrate(moal_private * priv, struct iwreq *wrq) /** * @brief Set/Get region code - * + * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure - * + * * @return 0 --success, otherwise fail */ static int @@ -2344,10 +2344,10 @@ woal_set_get_regioncode(moal_private * priv, struct iwreq *wrq) /** * @brief Set/Get radio - * + * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure - * + * * @return 0 --success, otherwise fail */ static int @@ -2387,7 +2387,7 @@ woal_set_get_radio(moal_private * priv, struct iwreq *wrq) } #ifdef DEBUG_LEVEL1 -/** +/** * @brief Get/Set the bit mask of driver debug message control * * @param priv A pointer to moal_private structure @@ -2464,10 +2464,10 @@ woal_drv_dbg(moal_private * priv, struct iwreq *wrq) /** * @brief Set/Get QoS configuration - * + * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure - * + * * @return 0 --success, otherwise fail */ static int @@ -2518,10 +2518,10 @@ woal_set_get_qos_cfg(moal_private * priv, struct iwreq *wrq) /** * @brief Set/Get WWS mode - * + * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure - * + * * @return 0 --success, otherwise fail */ static int @@ -2576,10 +2576,10 @@ woal_wws_cfg(moal_private * priv, struct iwreq *wrq) /** * @brief Set/Get sleep period - * + * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure - * + * * @return 0 --success, otherwise fail */ static int @@ -2645,7 +2645,7 @@ woal_sleep_pd(moal_private * priv, struct iwreq *wrq) * @param priv A pointer to moal_private structure * @param req A pointer to ifreq structure * - * @return 0 --success, otherwise fail + * @return 0 --success, otherwise fail */ static int woal_sleep_params_ioctl(moal_private * priv, struct iwreq *wrq) @@ -2749,9 +2749,9 @@ woal_sleep_params_ioctl(moal_private * priv, struct iwreq *wrq) return ret; } -/** +/** * @brief Set/get user provisioned local power constraint - * + * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure * @return 0 --success, otherwise fail @@ -2808,7 +2808,7 @@ woal_set_get_11h_local_pwr_constraint(moal_private * priv, struct iwreq *wrq) return ret; } -/** +/** * @brief Set/get HT stream configurations * * @param priv A pointer to moal_private structure @@ -2870,7 +2870,7 @@ woal_ht_stream_cfg_ioctl(moal_private * priv, struct iwreq *wrq) return ret; } -/** +/** * @brief Set/get MAC control configuration * * @param priv A pointer to moal_private structure @@ -2928,7 +2928,7 @@ woal_mac_control_ioctl(moal_private * priv, struct iwreq *wrq) return ret; } -/** +/** * @brief Get thermal reading * * @param priv A pointer to moal_private structure @@ -2984,10 +2984,10 @@ woal_thermal_ioctl(moal_private * priv, struct iwreq *wrq) #if defined(REASSOCIATION) /** * @brief Set/Get reassociation settings - * + * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure - * + * * @return 0 --success, otherwise fail */ static int @@ -3433,10 +3433,10 @@ woal_passphrase(moal_private * priv, struct iwreq *wrq) /** * @brief Get esupp mode - * + * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure - * + * * @return 0 --success, otherwise fail */ static int @@ -3480,7 +3480,7 @@ woal_get_esupp_mode(moal_private * priv, struct iwreq *wrq) /** AES key length */ #define AES_KEY_LEN 16 /** - * @brief Adhoc AES control + * @brief Adhoc AES control * * @param priv A pointer to moal_private structure * @param wrq A pointer to user data @@ -3634,9 +3634,9 @@ woal_adhoc_aes_ioctl(moal_private * priv, struct iwreq *wrq) return ret; } -/** +/** * @brief arpfilter ioctl function - * + * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure * @return 0 --success, otherwise fail @@ -3681,9 +3681,9 @@ woal_arp_filter(moal_private * priv, struct iwreq *wrq) return ret; } -/** +/** * @brief Set/get IP address - * + * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure * @return 0 --success, otherwise fail @@ -3769,13 +3769,13 @@ woal_set_get_ip_addr(moal_private * priv, struct iwreq *wrq) return ret; } -/** +/** * @brief Set/Get Transmit beamforming capabilities * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure * - * @return 0 -- success, otherwise fail + * @return 0 -- success, otherwise fail */ static int woal_tx_bf_cap_ioctl(moal_private * priv, struct iwreq *wrq) @@ -3847,13 +3847,13 @@ woal_tx_bf_cap_ioctl(moal_private * priv, struct iwreq *wrq) #define BF_CFG_ACT_GET 0 #define BF_CFG_ACT_SET 1 -/** +/** * @brief Set/Get Transmit beamforming configuration * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure * - * @return 0 -- success, otherwise fail + * @return 0 -- success, otherwise fail */ static int woal_tx_bf_cfg_ioctl(moal_private * priv, struct iwreq *wrq) @@ -3993,7 +3993,7 @@ woal_tx_bf_cfg_ioctl(moal_private * priv, struct iwreq *wrq) } break; case TX_BF_FOR_PEER_ENBL: - /* Handle only SET operation here First arg = 2 BfAction Second arg + /* Handle only SET operation here First arg = 2 BfAction Second arg = 18 MAC "00:50:43:20:BF:64;" Third arg = 2 enable/disable bf Fourth arg = 2 enable/disable sounding Fifth arg = 1 FB Type */ if (char_count != 25 && char_count != 1) { @@ -4264,8 +4264,8 @@ wlan_scan_create_brief_table_entry(t_u8 ** ppbuffer, LEAVE(); } -/** - * @brief Create a wlan_ioctl_get_scan_table_entry for a given BSS +/** + * @brief Create a wlan_ioctl_get_scan_table_entry for a given BSS * Descriptor for inclusion in the ioctl response to the user space * application. * @@ -4273,7 +4273,7 @@ wlan_scan_create_brief_table_entry(t_u8 ** ppbuffer, * @param pbss_desc Pointer to a BSS entry in the scan table to form * scan response from for delivery to the application layer * @param ppbuffer Output parameter: Buffer used to output scan return struct - * @param pspace_left Output parameter: Number of bytes available in the + * @param pspace_left Output parameter: Number of bytes available in the * response buffer. * * @return MLAN_STATUS_SUCCESS, or < 0 with IOCTL error code @@ -4353,7 +4353,7 @@ wlan_get_scan_table_ret_entry(BSSDescriptor_t * pbss_desc, tmp_rsp_entry.fixed_fields.network_tsf = pbss_desc->network_tsf; tmp_rsp_entry.bss_info_length = variable_size; - /* + /* * Copy fixed fields to user space */ if (copy_to_user(pcurrent, &tmp_rsp_entry, fixed_size)) { @@ -4365,7 +4365,7 @@ wlan_get_scan_table_ret_entry(BSSDescriptor_t * pbss_desc, pcurrent += fixed_size; if (pbss_desc->pbeacon_buf) { - /* + /* * Copy variable length elements to user space */ if (copy_to_user(pcurrent, pbss_desc->pbeacon_buf, @@ -4462,19 +4462,19 @@ moal_ret_get_scan_table_ioctl(struct iwreq *wrq, wrq->u.data.length = ret_len; - /* Return ret_code (EFAULT or E2BIG) in the case where no scan results were + /* Return ret_code (EFAULT or E2BIG) in the case where no scan results were successfully encoded. */ LEAVE(); return (num_scans_done ? MLAN_STATUS_SUCCESS : ret_code); } -/** +/** * @brief Get scan table ioctl * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure * - * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail */ static mlan_status woal_get_scan_table_ioctl(moal_private * priv, struct iwreq *wrq) @@ -4524,13 +4524,13 @@ woal_get_scan_table_ioctl(moal_private * priv, struct iwreq *wrq) return status; } -/** +/** * @brief Set user scan * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure * - * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail */ static mlan_status woal_set_user_scan_ioctl(moal_private * priv, struct iwreq *wrq) @@ -4592,9 +4592,9 @@ woal_set_user_scan_ioctl(moal_private * priv, struct iwreq *wrq) return status; } -/** +/** * @brief Cmd52 read/write register - * + * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure * @return MLAN_STATUS_SUCCESS --success, otherwise fail @@ -4681,9 +4681,9 @@ woal_cmd52rdwr_ioctl(moal_private * priv, struct iwreq *wrq) return ret; } -/** +/** * @brief Cmd53 read/write register - * + * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure * @return MLAN_STATUS_SUCCESS --success, otherwise fail @@ -4789,10 +4789,10 @@ woal_cmd53rdwr_ioctl(moal_private * priv, struct iwreq *wrq) #if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR) /** * @brief Set SDIO Multi-point aggregation control parameters - * + * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure - * + * * @return 0/MLAN_STATUS_PENDING --success, otherwise fail */ static int @@ -4822,7 +4822,7 @@ woal_do_sdio_mpa_ctrl(moal_private * priv, struct iwreq *wrq) misc->sub_command = MLAN_OID_MISC_SDIO_MPA_CTRL; req->req_id = MLAN_IOCTL_MISC_CFG; - /* Get the values first, then modify these values if user had modified them + /* Get the values first, then modify these values if user had modified them */ req->action = MLAN_ACT_GET; @@ -4901,10 +4901,10 @@ woal_do_sdio_mpa_ctrl(moal_private * priv, struct iwreq *wrq) /** * @brief Set/Get scan configuration parameters - * + * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure - * + * * @return 0 --success, otherwise fail */ static int @@ -4989,10 +4989,10 @@ woal_set_get_scan_cfg(moal_private * priv, struct iwreq *wrq) /** * @brief Set/Get PS configuration parameters - * + * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure - * + * * @return 0 --success, otherwise fail */ static int @@ -5844,13 +5844,13 @@ woal_dfs_testing(moal_private * priv, struct iwreq *wrq) } #endif /* DFS_SUPPORT && DFS_TESTING_SUPPORT */ -/** +/** * @brief Set/Get Mgmt Frame passthru mask * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure * - * @return 0 -- success, otherwise fail + * @return 0 -- success, otherwise fail */ static int woal_mgmt_frame_passthru_ctrl(moal_private * priv, struct iwreq *wrq) @@ -5913,10 +5913,10 @@ woal_mgmt_frame_passthru_ctrl(moal_private * priv, struct iwreq *wrq) /** * @brief Set/Get Tx/Rx antenna - * + * * @param priv A pointer to moal_private structure * @param wrq A pointer to iwreq structure - * + * * @return 0 --success, otherwise fail */ static int @@ -6235,7 +6235,7 @@ woal_wext_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd) break; case WOAL_SETNONE_GETTWELVE_CHAR: - /* + /* * We've not used IW_PRIV_TYPE_FIXED so sub-ioctl number is * in flags of iwreq structure, otherwise it will be in * mode member of iwreq structure. @@ -6338,11 +6338,11 @@ woal_wext_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd) return ret; } -/** +/** * @brief Get mode * * @param priv A pointer to moal_private structure - * @param wait_option Wait option (MOAL_WAIT or MOAL_NO_WAIT) + * @param wait_option Wait option (MOAL_WAIT or MOAL_NO_WAIT) * * @return Wireless mode */ @@ -6391,14 +6391,14 @@ woal_get_mode(moal_private * priv, t_u8 wait_option) return mode; } -/** +/** * @brief Get statistics information * * @param priv A pointer to moal_private structure * @param wait_option Wait option * @param stats A pointer to mlan_ds_get_stats structure * - * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail */ mlan_status woal_get_stats_info(moal_private * priv, t_u8 wait_option, @@ -6439,14 +6439,14 @@ woal_get_stats_info(moal_private * priv, t_u8 wait_option, return status; } -/** +/** * @brief Get data rates * * @param priv A pointer to moal_private structure * @param wait_option Wait option * @param m_rates A pointer to moal_802_11_rates structure * - * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail */ mlan_status woal_get_data_rates(moal_private * priv, t_u8 wait_option, @@ -6486,14 +6486,14 @@ woal_get_data_rates(moal_private * priv, t_u8 wait_option, return status; } -/** +/** * @brief Get channel list * * @param priv A pointer to moal_private structure * @param wait_option Wait option * @param chan_list A pointer to mlan_chan_list structure * - * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail */ mlan_status woal_get_channel_list(moal_private * priv, t_u8 wait_option, @@ -6532,9 +6532,9 @@ woal_get_channel_list(moal_private * priv, t_u8 wait_option, return status; } -/** - * @brief Handle get info resp - * +/** + * @brief Handle get info resp + * * @param priv Pointer to moal_private structure * @param info Pointer to mlan_ds_get_info structure * @@ -6562,9 +6562,9 @@ woal_ioctl_get_info_resp(moal_private * priv, mlan_ds_get_info * info) LEAVE(); } -/** - * @brief Handle get BSS resp - * +/** + * @brief Handle get BSS resp + * * @param priv Pointer to moal_private structure * @param bss Pointer to mlan_ds_bss structure * diff --git a/drivers/net/wireless/sd8797/mlinux/moal_proc.c b/drivers/net/wireless/sd8797/mlinux/moal_proc.c index cd292351f827..e98803c2e3fb 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_proc.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_proc.c @@ -63,13 +63,13 @@ extern int drv_mode; /******************************************************** Local Functions ********************************************************/ -/** +/** * @brief Proc read function for info * * @param page Pointer to buffer * @param start Read data starting position * @param offset Offset - * @param count Counter + * @param count Counter * @param eof End of file flag * @param data Data to output * @@ -164,8 +164,8 @@ woal_info_proc_read(char *page, char **start, off_t offset, p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan); p += sprintf(p, "region_code = \"%02x\"\n", (t_u8) info.region_code); - /* - * Put out the multicast list + /* + * Put out the multicast list */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) for (i = 0; i < netdev->mc_count; i++) { @@ -298,7 +298,7 @@ parse_cmd52_string(const char __user * buffer, size_t len, int *func, int *reg, return ret; } -/** +/** * @brief config proc write function * * @param f file pointer @@ -364,13 +364,13 @@ woal_config_write(struct file *f, const char *buf, unsigned long cnt, return (int) cnt; } -/** +/** * @brief config proc read function * * @param page pointer to buffer * @param s read data starting position * @param off offset - * @param cnt counter + * @param cnt counter * @param eof end of file flag * @param data data to output * @return number of output data @@ -399,7 +399,7 @@ woal_config_read(char *page, char **s, off_t off, int cnt, int *eof, void *data) /******************************************************** Global Functions ********************************************************/ -/** +/** * @brief Convert string to number * * @param s Pointer to numbered string @@ -437,7 +437,7 @@ woal_string_to_number(char *s) return (r * pn); } -/** +/** * @brief Create the top level proc directory * * @param handle Pointer to woal_handle @@ -512,7 +512,7 @@ woal_proc_init(moal_handle * handle) LEAVE(); } -/** +/** * @brief Remove the top level proc directory * * @param handle pointer moal_handle @@ -551,7 +551,7 @@ woal_proc_exit(moal_handle * handle) LEAVE(); } -/** +/** * @brief Create proc file for interface * * @param priv pointer moal_private @@ -609,7 +609,7 @@ woal_create_proc_entry(moal_private * priv) LEAVE(); } -/** +/** * @brief Remove proc file * * @param priv Pointer moal_private diff --git a/drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c b/drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c index 94d2a1eef004..96e3e971936f 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c @@ -99,7 +99,7 @@ static struct sdio_driver wlan_sdio = { Local Functions ********************************************************/ /** @brief This function dump the sdio register - * + * * @param handle A Pointer to the moal_handle structure * @return N/A */ @@ -138,9 +138,9 @@ woal_dump_sdio_reg(moal_handle * handle) Global Functions ********************************************************/ -/** +/** * @brief This function handles the interrupt. - * + * * @param func A pointer to the sdio_func structure * @return N/A */ @@ -169,7 +169,7 @@ woal_sdio_interrupt(struct sdio_func *func) } /** @brief This function handles client driver probe. - * + * * @param func A pointer to sdio_func structure. * @param id A pointer to sdio_device_id structure. * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE/error code @@ -229,7 +229,7 @@ woal_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id) } /** @brief This function handles client driver remove. - * + * * @param func A pointer to sdio_func structure. * @return N/A */ @@ -257,7 +257,7 @@ woal_sdio_remove(struct sdio_func *func) #ifdef MMC_PM_KEEP_POWER #ifdef MMC_PM_FUNC_SUSPENDED /** @brief This function tells lower driver that WLAN is suspended - * + * * @param handle A Pointer to the moal_handle structure * @return N/A */ @@ -274,7 +274,7 @@ woal_wlan_is_suspended(moal_handle * handle) #endif /** @brief This function handles client driver suspend - * + * * @param dev A pointer to device structure * @return MLAN_STATUS_SUCCESS or error code */ @@ -363,7 +363,7 @@ woal_sdio_suspend(struct device *dev) } /** @brief This function handles client driver resume - * + * * @param dev A pointer to device structure * @return MLAN_STATUS_SUCCESS */ @@ -414,7 +414,7 @@ woal_sdio_resume(struct device *dev) #endif #endif /* SDIO_SUSPEND_RESUME */ -/** +/** * @brief This function writes data into card register * * @param handle A Pointer to the moal_handle structure @@ -432,7 +432,7 @@ woal_write_reg(moal_handle * handle, t_u32 reg, t_u32 data) return ret; } -/** +/** * @brief This function reads data from card register * * @param handle A Pointer to the moal_handle structure @@ -530,9 +530,9 @@ woal_read_data_sync(moal_handle * handle, mlan_buffer * pmbuf, t_u32 port, return ret; } -/** +/** * @brief This function registers the IF module in bus driver - * + * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status @@ -553,9 +553,9 @@ woal_bus_register(void) return ret; } -/** +/** * @brief This function de-registers the IF module in bus driver - * + * * @return N/A */ void @@ -569,9 +569,9 @@ woal_bus_unregister(void) LEAVE(); } -/** +/** * @brief This function de-registers the device - * + * * @param handle A pointer to moal_handle structure * @return N/A */ @@ -594,9 +594,9 @@ woal_unregister_dev(moal_handle * handle) LEAVE(); } -/** +/** * @brief This function registers the device - * + * * @param handle A pointer to moal_handle structure * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ @@ -644,9 +644,9 @@ woal_register_dev(moal_handle * handle) return MLAN_STATUS_FAILURE; } -/** +/** * @brief This function set bus clock on/off - * + * * @param handle A pointer to moal_handle structure * @param option TRUE--on , FALSE--off * @return MLAN_STATUS_SUCCESS @@ -674,9 +674,9 @@ woal_sdio_set_bus_clock(moal_handle * handle, t_u8 option) return MLAN_STATUS_SUCCESS; } -/** +/** * @brief This function updates card reg based on the Cmd52 value in dev structure - * + * * @param handle A pointer to moal_handle structure * @param func A pointer to store func variable * @param reg A pointer to store reg variable diff --git a/drivers/net/wireless/sd8797/mlinux/moal_shim.c b/drivers/net/wireless/sd8797/mlinux/moal_shim.c index 51f192a160f9..e33a6e38067a 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_shim.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_shim.c @@ -58,9 +58,9 @@ extern int cfg80211_wext; Global Functions ********************************************************/ -/** - * @brief Alloc a buffer - * +/** + * @brief Alloc a buffer + * * @param pmoal_handle Pointer to the MOAL context * @param size The size of the buffer to be allocated * @param flag The type of the buffer to be allocated @@ -88,9 +88,9 @@ moal_malloc(IN t_void * pmoal_handle, return MLAN_STATUS_SUCCESS; } -/** - * @brief Free a buffer - * +/** + * @brief Free a buffer + * * @param pmoal_handle Pointer to the MOAL context * @param pbuf Pointer to the buffer to be freed * @@ -108,9 +108,9 @@ moal_mfree(IN t_void * pmoal_handle, IN t_u8 * pbuf) return MLAN_STATUS_SUCCESS; } -/** - * @brief Fill memory with constant byte - * +/** + * @brief Fill memory with constant byte + * * @param pmoal_handle Pointer to the MOAL context * @param pmem Pointer to the memory area * @param byte A constant byte @@ -130,9 +130,9 @@ moal_memset(IN t_void * pmoal_handle, return p; } -/** +/** * @brief Copy memory from one area to another - * + * * @param pmoal_handle Pointer to the MOAL context * @param pdest Pointer to the dest memory * @param psrc Pointer to the src memory @@ -152,9 +152,9 @@ moal_memcpy(IN t_void * pmoal_handle, return p; } -/** +/** * @brief Move memory from one area to another - * + * * @param pmoal_handle Pointer to the MOAL context * @param pdest Pointer to the dest memory * @param psrc Pointer to the src memory @@ -174,9 +174,9 @@ moal_memmove(IN t_void * pmoal_handle, return p; } -/** +/** * @brief Compare two memory areas - * + * * @param pmoal_handle Pointer to the MOAL context * @param pmem1 Pointer to the first memory * @param pmem2 Pointer to the second memory @@ -195,9 +195,9 @@ moal_memcmp(IN t_void * pmoal_handle, return result; } -/** +/** * @brief Delay function - * + * * @param pmoal_handle Pointer to the MOAL context * @param delay delay in micro-second * @@ -212,14 +212,14 @@ moal_udelay(IN t_void * pmoal_handle, IN t_u32 delay) udelay(delay % 1000); } -/** +/** * @brief Retrieves the current system time - * + * * @param pmoal_handle Pointer to the MOAL context * @param psec Pointer to buf for the seconds of system time * @param pusec Pointer to buf the micro seconds of system time * - * @return MLAN_STATUS_SUCCESS + * @return MLAN_STATUS_SUCCESS */ mlan_status moal_get_system_time(IN t_void * pmoal_handle, @@ -234,15 +234,15 @@ moal_get_system_time(IN t_void * pmoal_handle, return MLAN_STATUS_SUCCESS; } -/** +/** * @brief Initializes the timer - * + * * @param pmoal_handle Pointer to the MOAL context * @param pptimer Pointer to the timer * @param callback Pointer to callback function * @param pcontext Pointer to context * - * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status moal_init_timer(IN t_void * pmoal_handle, @@ -261,13 +261,13 @@ moal_init_timer(IN t_void * pmoal_handle, return MLAN_STATUS_SUCCESS; } -/** +/** * @brief Free the timer - * + * * @param pmoal_handle Pointer to the MOAL context * @param ptimer Pointer to the timer * - * @return MLAN_STATUS_SUCCESS + * @return MLAN_STATUS_SUCCESS */ mlan_status moal_free_timer(IN t_void * pmoal_handle, IN t_void * ptimer) @@ -285,9 +285,9 @@ moal_free_timer(IN t_void * pmoal_handle, IN t_void * ptimer) return MLAN_STATUS_SUCCESS; } -/** +/** * @brief Start the timer - * + * * @param pmoal_handle Pointer to the MOAL context * @param ptimer Pointer to the timer * @param periodic Periodic timer @@ -308,9 +308,9 @@ moal_start_timer(IN t_void * pmoal_handle, return MLAN_STATUS_SUCCESS; } -/** +/** * @brief Stop the timer - * + * * @param pmoal_handle Pointer to the MOAL context * @param ptimer Pointer to the timer * @@ -326,13 +326,13 @@ moal_stop_timer(IN t_void * pmoal_handle, IN t_void * ptimer) return MLAN_STATUS_SUCCESS; } -/** +/** * @brief Initializes the lock - * + * * @param pmoal_handle Pointer to the MOAL context * @param pplock Pointer to the lock * - * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE + * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ mlan_status moal_init_lock(IN t_void * pmoal_handle, OUT t_void ** pplock) @@ -350,9 +350,9 @@ moal_init_lock(IN t_void * pmoal_handle, OUT t_void ** pplock) return MLAN_STATUS_SUCCESS; } -/** +/** * @brief Free the lock - * + * * @param pmoal_handle Pointer to the MOAL context * @param plock Lock * @@ -372,9 +372,9 @@ moal_free_lock(IN t_void * pmoal_handle, IN t_void * plock) return MLAN_STATUS_SUCCESS; } -/** +/** * @brief Request a spin lock - * + * * @param pmoal_handle Pointer to the MOAL context * @param plock Pointer to the lock * @@ -395,9 +395,9 @@ moal_spin_lock(IN t_void * pmoal_handle, IN t_void * plock) } } -/** +/** * @brief Request a spin_unlock - * + * * @param pmoal_handle Pointer to the MOAL context * @param plock Pointer to the lock * @@ -417,7 +417,7 @@ moal_spin_unlock(IN t_void * pmoal_handle, IN t_void * plock) } } -/** +/** * @brief This function reads one block of firmware data from MOAL * * @param pmoal_handle Pointer to the MOAL context @@ -444,13 +444,13 @@ moal_get_fw_data(IN t_void * pmoal_handle, return MLAN_STATUS_SUCCESS; } -/** +/** * @brief This function is called when MLAN completes the initialization firmware. - * + * * @param pmoal_handle Pointer to the MOAL context * @param status The status code for mlan_init_fw request * - * @return MLAN_STATUS_SUCCESS + * @return MLAN_STATUS_SUCCESS */ mlan_status moal_init_fw_complete(IN t_void * pmoal_handle, IN mlan_status status) @@ -465,13 +465,13 @@ moal_init_fw_complete(IN t_void * pmoal_handle, IN mlan_status status) return MLAN_STATUS_SUCCESS; } -/** +/** * @brief This function is called when MLAN shutdown firmware is completed. - * + * * @param pmoal_handle Pointer to the MOAL context * @param status The status code for mlan_shutdown request * - * @return MLAN_STATUS_SUCCESS + * @return MLAN_STATUS_SUCCESS */ mlan_status moal_shutdown_fw_complete(IN t_void * pmoal_handle, IN mlan_status status) @@ -485,14 +485,14 @@ moal_shutdown_fw_complete(IN t_void * pmoal_handle, IN mlan_status status) return MLAN_STATUS_SUCCESS; } -/** +/** * @brief This function is called when an MLAN IOCTL is completed. - * + * * @param pmoal_handle Pointer to the MOAL context - * @param pioctl_req pointer to structure mlan_ioctl_req + * @param pioctl_req pointer to structure mlan_ioctl_req * @param status The status code for mlan_ioctl request * - * @return MLAN_STATUS_SUCCESS + * @return MLAN_STATUS_SUCCESS */ mlan_status moal_ioctl_complete(IN t_void * pmoal_handle, @@ -538,12 +538,12 @@ moal_ioctl_complete(IN t_void * pmoal_handle, return MLAN_STATUS_SUCCESS; } -/** +/** * @brief This function allocates mlan_buffer. - * + * * @param pmoal_handle Pointer to the MOAL context - * @param size allocation size requested - * @param pmbuf pointer to pointer to the allocated buffer + * @param size allocation size requested + * @param pmbuf pointer to pointer to the allocated buffer * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ @@ -557,9 +557,9 @@ moal_alloc_mlan_buffer(IN t_void * pmoal_handle, return MLAN_STATUS_SUCCESS; } -/** +/** * @brief This function frees mlan_buffer. - * + * * @param pmoal_handle Pointer to the MOAL context * @param pmbuf pointer to buffer to be freed * @@ -574,14 +574,14 @@ moal_free_mlan_buffer(IN t_void * pmoal_handle, IN pmlan_buffer pmbuf) return MLAN_STATUS_SUCCESS; } -/** +/** * @brief This function is called when MLAN complete send data packet. - * + * * @param pmoal_handle Pointer to the MOAL context * @param pmbuf Pointer to the mlan buffer structure * @param status The status code for mlan_send_packet request * - * @return MLAN_STATUS_SUCCESS + * @return MLAN_STATUS_SUCCESS */ mlan_status moal_send_packet_complete(IN t_void * pmoal_handle, @@ -636,7 +636,7 @@ moal_send_packet_complete(IN t_void * pmoal_handle, return MLAN_STATUS_SUCCESS; } -/** +/** * @brief This function write a command/data packet to card. * This function blocks the call until it finishes * @@ -655,7 +655,7 @@ moal_write_data_sync(IN t_void * pmoal_handle, timeout); } -/** +/** * @brief This function read data packet/event/command from card. * This function blocks the call until it finish * @@ -674,7 +674,7 @@ moal_read_data_sync(IN t_void * pmoal_handle, timeout); } -/** +/** * @brief This function writes data into card register. * * @param pmoal_handle Pointer to the MOAL context @@ -689,7 +689,7 @@ moal_write_reg(IN t_void * pmoal_handle, IN t_u32 reg, IN t_u32 data) return woal_write_reg((moal_handle *) pmoal_handle, reg, data); } -/** +/** * @brief This function reads data from card register. * * @param pmoal_handle Pointer to the MOAL context @@ -704,7 +704,7 @@ moal_read_reg(IN t_void * pmoal_handle, IN t_u32 reg, OUT t_u32 * data) return woal_read_reg((moal_handle *) pmoal_handle, reg, data); } -/** +/** * @brief This function uploads the packet to the network stack * * @param pmoal_handle Pointer to the MOAL context @@ -758,13 +758,13 @@ moal_recv_packet(IN t_void * pmoal_handle, IN pmlan_buffer pmbuf) return status; } -/** +/** * @brief This function handles event receive * * @param pmoal_handle Pointer to the MOAL context * @param pmevent Pointer to the mlan event structure * - * @return MLAN_STATUS_SUCCESS + * @return MLAN_STATUS_SUCCESS */ mlan_status moal_recv_event(IN t_void * pmoal_handle, IN pmlan_event pmevent) @@ -1368,14 +1368,14 @@ moal_recv_event(IN t_void * pmoal_handle, IN pmlan_event pmevent) return MLAN_STATUS_SUCCESS; } -/** +/** * @brief This function prints the debug message in mlan * * @param pmoal_handle Pointer to the MOAL context * @param level debug level * @param pformat point to string format buf * - * @return N/A + * @return N/A */ t_void moal_print(IN t_void * pmoal_handle, IN t_u32 level, IN t_s8 * pformat, IN ...) @@ -1426,7 +1426,7 @@ moal_print(IN t_void * pmoal_handle, IN t_u32 level, IN t_s8 * pformat, IN ...) * @param bss_index BSS index * @param level debug level * - * @return N/A + * @return N/A */ t_void moal_print_netintf(IN t_void * pmoal_handle, IN t_u32 bss_index, IN t_u32 level) @@ -1442,7 +1442,7 @@ moal_print_netintf(IN t_void * pmoal_handle, IN t_u32 bss_index, IN t_u32 level) #endif /* DEBUG_LEVEL1 */ } -/** +/** * @brief This function asserts the existence of the passed argument * * @param pmoal_handle A pointer to moal_private structure diff --git a/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c b/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c index dfb4aefcbb33..d6768a3bd647 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c @@ -438,7 +438,7 @@ woal_wps_cfg(moal_private * priv, int enable) } /** - * @brief configure ASSOC IE + * @brief configure ASSOC IE * * @param priv A pointer to moal private structure * @param ie A pointer to ie data @@ -739,14 +739,14 @@ woal_set_rf_channel(struct wiphy *wiphy, return ret; } -/** +/** * @brief Set ewpa mode * * @param priv A pointer to moal_private structure * @param wait_option Wait option * @param ssid_bssid A pointer to mlan_ssid_bssid structure * - * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail */ mlan_status woal_set_ewpa_mode(moal_private * priv, t_u8 wait_option, @@ -1295,7 +1295,7 @@ woal_cfg80211_assoc(struct wiphy *wiphy, void *sme) /* "privacy" is set only for ad-hoc mode */ if (privacy) { - /* + /* * Keep MLAN_ENCRYPTION_MODE_WEP40 for now so that * the firmware can find a matching network from the * scan. cfg80211 does not give us the encryption @@ -1627,7 +1627,7 @@ woal_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, if (priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT && (priv->wdev->iftype == NL80211_IFTYPE_STATION || priv->wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) { - /* if bsstype == wifi direct, and iftype == station or p2p client, that + /* if bsstype == wifi direct, and iftype == station or p2p client, that means wpa_supplicant wants to enable wifi direct functionality, so we should init p2p client. Note that due to kernel iftype check, ICS wpa_supplicant could not updaet iftype to init p2p client, so @@ -2012,7 +2012,7 @@ woal_cfg80211_setup_sta_ht_cap(struct ieee80211_sta_ht_cap *ht_info, * * @param wiphy A pointer to wiphy structure * @param wait_option Wait option - * @param cancel cancel remain on channel flag + * @param cancel cancel remain on channel flag * @param status A pointer to status, success, in process or reject * @param chan A pointer to ieee80211_channel structure * @param channel_type channel_type, diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap.c b/drivers/net/wireless/sd8797/mlinux/moal_uap.c index 7dac877abe00..fb8e2a7d6571 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_uap.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_uap.c @@ -44,9 +44,9 @@ Change log: /******************************************************** Local Functions ********************************************************/ -/** +/** * @brief uap addba parameter handler - * + * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail @@ -123,9 +123,9 @@ woal_uap_addba_param(struct net_device *dev, struct ifreq *req) return ret; } -/** - * @brief uap aggr priority tbl - * +/** + * @brief uap aggr priority tbl + * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail @@ -198,9 +198,9 @@ woal_uap_aggr_priotbl(struct net_device *dev, struct ifreq *req) return ret; } -/** - * @brief uap addba reject tbl - * +/** + * @brief uap addba reject tbl + * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail @@ -271,9 +271,9 @@ woal_uap_addba_reject(struct net_device *dev, struct ifreq *req) return ret; } -/** +/** * @brief uap get_fw_info handler - * + * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail @@ -319,9 +319,9 @@ woal_uap_get_fw_info(struct net_device *dev, struct ifreq *req) return ret; } -/** - * @brief configure deep sleep - * +/** + * @brief configure deep sleep + * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail @@ -396,9 +396,9 @@ woal_uap_deep_sleep(struct net_device *dev, struct ifreq *req) return ret; } -/** +/** * @brief configure tx_pause settings - * + * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail @@ -468,9 +468,9 @@ woal_uap_txdatapause(struct net_device *dev, struct ifreq *req) return ret; } -/** +/** * @brief uap sdcmd52rw ioctl handler - * + * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail @@ -840,7 +840,7 @@ woal_uap_dfs_testing(struct net_device *dev, struct ifreq *req) /** * @brief Configure TX beamforming support - * + * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail @@ -903,9 +903,9 @@ woal_uap_tx_bf_cfg(struct net_device *dev, struct ifreq *req) return ret; } -/** +/** * @brief uap hs_cfg ioctl handler - * + * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail @@ -1033,9 +1033,9 @@ woal_uap_hs_set_para(struct net_device *dev, struct ifreq *req) return ret; } -/** +/** * @brief uap mgmt_frame_control ioctl handler - * + * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail @@ -1096,10 +1096,10 @@ woal_uap_mgmt_frame_control(struct net_device *dev, struct ifreq *req) /** * @brief Set/Get tx rate - * + * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure - * + * * @return 0 --success, otherwise fail */ static int @@ -1184,10 +1184,10 @@ woal_uap_tx_rate_cfg(struct net_device *dev, struct ifreq *req) /** * @brief Set/Get RF antenna mode - * + * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure - * + * * @return 0 --success, otherwise fail */ static int @@ -1250,9 +1250,9 @@ woal_uap_antenna_cfg(struct net_device *dev, struct ifreq *req) return ret; } -/** +/** * @brief uap ioctl handler - * + * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail @@ -1335,9 +1335,9 @@ woal_uap_ioctl(struct net_device *dev, struct ifreq *req) return ret; } -/** +/** * @brief uap station deauth ioctl handler - * + * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail @@ -1402,10 +1402,10 @@ woal_uap_sta_deauth_ioctl(struct net_device *dev, struct ifreq *req) /** * @brief Set/Get radio - * + * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure - * + * * @return 0 --success, otherwise fail */ static int @@ -1467,9 +1467,9 @@ woal_uap_radio_ctl(struct net_device *dev, struct ifreq *req) return ret; } -/** +/** * @brief uap bss control ioctl handler - * + * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail @@ -1501,9 +1501,9 @@ woal_uap_bss_ctrl_ioctl(struct net_device *dev, struct ifreq *req) return ret; } -/** +/** * @brief uap power mode ioctl handler - * + * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail @@ -1596,9 +1596,9 @@ woal_uap_power_mode_ioctl(struct net_device *dev, struct ifreq *req) return ret; } -/** +/** * @brief uap BSS config ioctl handler - * + * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail @@ -1683,9 +1683,9 @@ woal_uap_bss_cfg_ioctl(struct net_device *dev, struct ifreq *req) return ret; } -/** +/** * @brief uap get station list handler - * + * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail @@ -1742,9 +1742,9 @@ woal_uap_get_sta_list_ioctl(struct net_device *dev, struct ifreq *req) return ret; } -/** +/** * @brief uAP set WAPI key ioctl - * + * * @param priv A pointer to moal_private structure * @param msg A pointer to wapi_msg structure * @@ -1796,9 +1796,9 @@ woal_uap_set_wapi_key_ioctl(moal_private * priv, wapi_msg * msg) return ret; } -/** +/** * @brief Enable/Disable wapi in firmware - * + * * @param priv A pointer to moal_private structure * @param enable MTRUE/MFALSE * @@ -1858,9 +1858,9 @@ woal_enable_wapi(moal_private * priv, t_u8 enable) return status; } -/** +/** * @brief uAP set WAPI flag ioctl - * + * * @param priv A pointer to moal_private structure * @param msg A pointer to wapi_msg structure * @@ -1927,9 +1927,9 @@ woal_uap_set_wapi_flag_ioctl(moal_private * priv, wapi_msg * msg) return ret; } -/** +/** * @brief set wapi ioctl function - * + * * @param dev A pointer to net_device structure * @param req A pointer to ifreq structure * @return 0 --success, otherwise fail @@ -2351,7 +2351,7 @@ woal_uap_set_ap_cfg(moal_private * priv, t_u8 * data, int len) /** * @brief uap BSS control ioctl handler - * + * * @param priv A pointer to moal_private structure * @param wait_option Wait option * @param data BSS control type @@ -2422,9 +2422,9 @@ woal_uap_bss_ctrl(moal_private * priv, t_u8 wait_option, int data) return ret; } -/** +/** * @brief This function sets multicast addresses to firmware - * + * * @param dev A pointer to net_device structure * @return N/A */ @@ -2501,9 +2501,9 @@ woal_uap_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd) return ret; } -/** - * @brief Get version - * +/** + * @brief Get version + * * @param priv A pointer to moal_private structure * @param version A pointer to version buffer * @param max_len max length of version buffer @@ -2545,14 +2545,14 @@ woal_uap_get_version(moal_private * priv, char *version, int max_len) return; } -/** - * @brief Get uap statistics - * +/** + * @brief Get uap statistics + * * @param priv A pointer to moal_private structure * @param wait_option Wait option * @param ustats A pointer to mlan_ds_uap_stats structure * - * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail */ mlan_status woal_uap_get_stats(moal_private * priv, t_u8 wait_option, diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap.h b/drivers/net/wireless/sd8797/mlinux/moal_uap.h index a30d0ceec87f..2667db84b8de 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_uap.h +++ b/drivers/net/wireless/sd8797/mlinux/moal_uap.h @@ -197,7 +197,7 @@ typedef struct _ds_hs_cfg /** Bit0: non-unicast data * Bit1: unicast data * Bit2: mac events - * Bit3: magic packet + * Bit3: magic packet */ t_u32 conditions; /** GPIO */ diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.c b/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.c index e83d4de4d282..7f7528216282 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.c @@ -402,8 +402,8 @@ woal_parse_ie_tlv(const t_u8 * ie, int len, t_u8 id) * @param assocresp_ies_data Assoc resp ie * @param assocresp_index The index for assoc resp when auto index * @param probereq_ies_data Probe req ie - * @param probereq_index The index for probe req when auto index * - * + * @param probereq_index The index for probe req when auto index * + * * @return 0 -- success, otherwise fail */ static int @@ -530,10 +530,10 @@ woal_cfg80211_custom_ie(moal_private * priv, return ret; } -/** +/** * @brief This function returns priv * based on mgmt ie index - * + * * @param handle A pointer to moal_handle * @param index mgmt ie index * @@ -564,9 +564,9 @@ woal_get_priv_by_mgmt_index(moal_handle * handle, t_u16 index) * @param assocresp_ies A pointer to probe resp ies * @param assocresp_ies_len Assoc resp ies length * @param probereq_ies A pointer to probe req ies - * @param probereq_ies_len Probe req ies length * + * @param probereq_ies_len Probe req ies length * * @param mask Mgmt frame mask - * + * * @return 0 -- success, otherwise fail */ int @@ -803,7 +803,7 @@ woal_cfg80211_mgmt_frame_ie(moal_private * priv, * @brief initialize AP or GO bss config * * @param priv A pointer to moal private structure - * @param params A pointer to beacon_parameters structure + * @param params A pointer to beacon_parameters structure * @return 0 -- success, otherwise fail */ static int @@ -1322,7 +1322,7 @@ woal_uap_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, * * @param wiphy A pointer to wiphy structure * @param dev A pointer to net_device structure - * @param params A pointer to beacon_parameters structure + * @param params A pointer to beacon_parameters structure * @return 0 -- success, otherwise fail */ int @@ -1394,7 +1394,7 @@ woal_cfg80211_add_beacon(struct wiphy *wiphy, * * @param wiphy A pointer to wiphy structure * @param dev A pointer to net_device structure - * @param params A pointer to beacon_parameters structure + * @param params A pointer to beacon_parameters structure * @return 0 -- success, otherwise fail */ int diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap_priv.c b/drivers/net/wireless/sd8797/mlinux/moal_uap_priv.c index dd06e03ecb1e..21f71cc4fe54 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_uap_priv.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_uap_priv.c @@ -150,9 +150,9 @@ woal_uap_do_priv_ioctl(struct net_device *dev, struct ifreq *req, int cmd) return ret; } -/** +/** * @brief Handle get info resp - * + * * @param priv Pointer to moal_private structure * @param info Pointer to mlan_ds_get_info structure * diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap_wext.c b/drivers/net/wireless/sd8797/mlinux/moal_uap_wext.c index 0426a28339cb..eb1d048cafd6 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_uap_wext.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_uap_wext.c @@ -137,7 +137,7 @@ woal_sort_channels(struct iw_freq *freq, int num) } /** - * @brief Get frequency for channel in given band + * @brief Get frequency for channel in given band * * @param channel channel * @param band band @@ -260,7 +260,7 @@ woal_set_wap(struct net_device *dev, struct iw_request_info *info, (t_u8) awrq->sa_data[2], (t_u8) awrq->sa_data[3], (t_u8) awrq->sa_data[4], (t_u8) awrq->sa_data[5]); - /* + /* * Using this ioctl to start/stop the BSS, return if bss * is already started/stopped. */ @@ -555,7 +555,7 @@ woal_set_encode(struct net_device *dev, struct iw_request_info *info, /* Set current key index as default */ pkey->is_default = MTRUE; } else { - /* + /* * No key provided so it is either enable key, * on or off */ @@ -563,10 +563,10 @@ woal_set_encode(struct net_device *dev, struct iw_request_info *info, PRINTM(MINFO, "*** iwconfig mlanX key off ***\n"); sys_cfg->protocol = PROTOCOL_NO_SECURITY; } else { - /* + /* * iwconfig mlanX key [n] - * iwconfig mlanX key on - * Do we want to just set the transmit key index ? + * iwconfig mlanX key on + * Do we want to just set the transmit key index ? */ if (key_index < 0) { PRINTM(MINFO, "*** iwconfig mlanX key on ***\n"); @@ -659,8 +659,8 @@ woal_get_encode(struct net_device *dev, struct iw_request_info *info, } dwrq->flags = 0; - /* - * Check encryption mode + /* + * Check encryption mode */ switch (ap_cfg.auth_mode) { case MLAN_AUTH_MODE_OPEN: @@ -739,8 +739,8 @@ woal_get_gen_ie(struct net_device *dev, struct iw_request_info *info, /** * @brief Set IE * - * Pass an opaque block of data, expected to be IEEE IEs, to the driver - * for eventual passthrough to the firmware in an associate/join + * Pass an opaque block of data, expected to be IEEE IEs, to the driver + * for eventual passthrough to the firmware in an associate/join * (and potentially start) command. * * @param dev A pointer to net_device structure @@ -853,8 +853,8 @@ woal_set_gen_ie(struct net_device *dev, struct iw_request_info *info, return ret; } -/** - * @brief Extended version of encoding configuration +/** + * @brief Extended version of encoding configuration * * @param dev A pointer to net_device structure * @param info A pointer to iw_request_info structure @@ -984,8 +984,8 @@ woal_set_encode_ext(struct net_device *dev, return ret; } -/** - * @brief Extended version of encoding configuration +/** + * @brief Extended version of encoding configuration * * @param dev A pointer to net_device structure * @param info A pointer to iw_request_info structure @@ -1004,8 +1004,8 @@ woal_get_encode_ext(struct net_device *dev, return -EOPNOTSUPP; } -/** - * @brief Request MLME operation +/** + * @brief Request MLME operation * * @param dev A pointer to net_device structure * @param info A pointer to iw_request_info structure @@ -1427,7 +1427,7 @@ woal_get_range(struct net_device *dev, struct iw_request_info *info, woal_sort_channels(&range->freq[0], range->num_frequency); - /* + /* * Set an indication of the max TCP throughput in bit/s that we can * expect using this interface */ @@ -1464,12 +1464,12 @@ woal_get_range(struct net_device *dev, struct iw_request_info *info, range->pmt_flags = IW_POWER_TIMEOUT; range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R; - /* + /* * Minimum version we recommend */ range->we_version_source = 15; - /* + /* * Version we are compiled with */ range->we_version_compiled = WIRELESS_EXT; @@ -1500,7 +1500,7 @@ woal_get_range(struct net_device *dev, struct iw_request_info *info, } /** - * @brief Set priv command + * @brief Set priv command * * @param dev A pointer to net_device structure * @param info A pointer to iw_request_info structure @@ -1580,9 +1580,9 @@ woal_set_essid(struct net_device *dev, struct iw_request_info *info, return ret; } -/** - * @brief Get current essid - * +/** + * @brief Get current essid + * * @param dev A pointer to net_device structure * @param info A pointer to iw_request_info structure * @param dwrq A pointer to iw_point structure @@ -1744,7 +1744,7 @@ woal_get_uap_wireless_stats(struct net_device *dev) ENTER(); - /* + /* * Since schedule() is not allowed from an atomic context * such as when dev_base_lock for netdevices is acquired * for reading/writing in kernel before this call, HostCmd diff --git a/drivers/net/wireless/sd8797/mlinux/moal_wext.c b/drivers/net/wireless/sd8797/mlinux/moal_wext.c index 9b5ce1333ee8..8595892090fb 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_wext.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_wext.c @@ -173,7 +173,7 @@ woal_set_nick(struct net_device *dev, struct iw_request_info *info, { moal_private *priv = (moal_private *) netdev_priv(dev); ENTER(); - /* + /* * Check the size of the string */ if (dwrq->length > 16) { @@ -202,16 +202,16 @@ woal_get_nick(struct net_device *dev, struct iw_request_info *info, { moal_private *priv = (moal_private *) netdev_priv(dev); ENTER(); - /* + /* * Get the Nick Name saved */ strncpy(extra, (char *) priv->nick_name, 16); extra[16] = '\0'; - /* + /* * If none, we may want to get the one that was set */ - /* + /* * Push it out ! */ dwrq->length = strlen(extra) + 1; @@ -285,8 +285,8 @@ woal_set_freq(struct net_device *dev, struct iw_request_info *info, goto done; } bss = (mlan_ds_bss *) req->pbuf; - /* - * If setting by frequency, convert to a channel + /* + * If setting by frequency, convert to a channel */ if (fwrq->e == 1) { long f = fwrq->m / 100000; @@ -704,9 +704,9 @@ woal_get_txpow(struct net_device *dev, struct iw_request_info *info, return ret; } -/** - * @brief Set power management - * +/** + * @brief Set power management + * * @param dev A pointer to net_device structure * @param info A pointer to iw_request_info structure * @param vwrq A pointer to iw_param structure @@ -735,9 +735,9 @@ woal_set_power(struct net_device *dev, struct iw_request_info *info, return ret; } -/** - * @brief Get power management - * +/** + * @brief Get power management + * * @param dev A pointer to net_device structure * @param info A pointer to iw_request_info structure * @param vwrq A pointer to iw_param structure @@ -791,7 +791,7 @@ woal_set_retry(struct net_device *dev, struct iw_request_info *info, ENTER(); if (vwrq->flags == IW_RETRY_LIMIT) { - /* + /* * The MAC has a 4-bit Total_Tx_Count register * Total_Tx_Count = 1 + Tx_Retry_Count */ @@ -908,20 +908,20 @@ woal_set_encode(struct net_device *dev, struct iw_request_info *info, else sec->param.encrypt_key.key_len = MIN_WEP_KEY_SIZE; } else { - /* - * No key provided so it is either enable key, + /* + * No key provided so it is either enable key, * on or off */ if (dwrq->flags & IW_ENCODE_DISABLED) { PRINTM(MINFO, "*** iwconfig mlanX key off ***\n"); sec->param.encrypt_key.key_disable = MTRUE; } else { - /* + /* * iwconfig mlanX key [n] - * iwconfig mlanX key on + * iwconfig mlanX key on * iwconfig mlanX key open * iwconfig mlanX key restricted - * Do we want to just set the transmit key index ? + * Do we want to just set the transmit key index ? */ if (index < 0) { PRINTM(MINFO, "*** iwconfig mlanX key on ***\n"); @@ -999,8 +999,8 @@ woal_get_encode(struct net_device *dev, struct iw_request_info *info, goto done; } dwrq->flags = 0; - /* - * Check encryption mode + /* + * Check encryption mode */ switch (auth_mode) { case MLAN_AUTH_MODE_OPEN: @@ -1325,8 +1325,8 @@ woal_get_gen_ie(struct net_device *dev, struct iw_request_info *info, /** * @brief Set IE * - * Pass an opaque block of data, expected to be IEEE IEs, to the driver - * for eventual passthrough to the firmware in an associate/join + * Pass an opaque block of data, expected to be IEEE IEs, to the driver + * for eventual passthrough to the firmware in an associate/join * (and potentially start) command. * * @param dev A pointer to net_device structure @@ -1384,8 +1384,8 @@ woal_set_gen_ie(struct net_device *dev, struct iw_request_info *info, return ret; } -/** - * @brief Extended version of encoding configuration +/** + * @brief Extended version of encoding configuration * * @param dev A pointer to net_device structure * @param info A pointer to iw_request_info structure @@ -1498,8 +1498,8 @@ woal_set_encode_ext(struct net_device *dev, return ret; } -/** - * @brief Extended version of encoding configuration +/** + * @brief Extended version of encoding configuration * * @param dev A pointer to net_device structure * @param info A pointer to iw_request_info structure @@ -1518,8 +1518,8 @@ woal_get_encode_ext(struct net_device *dev, return -EOPNOTSUPP; } -/** - * @brief Request MLME operation +/** + * @brief Request MLME operation * * @param dev A pointer to net_device structure * @param info A pointer to iw_request_info structure @@ -1819,7 +1819,7 @@ woal_get_range(struct net_device *dev, struct iw_request_info *info, woal_sort_channels(&range->freq[0], range->num_frequency); - /* + /* * Set an indication of the max TCP throughput in bit/s that we can * expect using this interface */ @@ -1856,12 +1856,12 @@ woal_get_range(struct net_device *dev, struct iw_request_info *info, range->pmt_flags = IW_POWER_TIMEOUT; range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R; - /* + /* * Minimum version we recommend */ range->we_version_source = 15; - /* + /* * Version we are compiled with */ range->we_version_compiled = WIRELESS_EXT; @@ -1872,10 +1872,10 @@ woal_get_range(struct net_device *dev, struct iw_request_info *info, range->min_retry = MLAN_TX_RETRY_MIN; range->max_retry = MLAN_TX_RETRY_MAX; - /* + /* * Set the qual, level and noise range values */ - /* + /* * need to put the right values here */ /** Maximum quality percentage */ @@ -1892,7 +1892,7 @@ woal_get_range(struct net_device *dev, struct iw_request_info *info, range->sensitivity = 0; - /* + /* * Setup the supported power level ranges */ memset(range->txpower, 0, sizeof(range->txpower)); @@ -1911,13 +1911,13 @@ woal_get_range(struct net_device *dev, struct iw_request_info *info, } #ifdef MEF_CFG_RX_FILTER -/** +/** * @brief Enable/disable Rx broadcast/multicast filter in non-HS mode * * @param priv A pointer to moal_private structure * @param enable MTRUE/MFALSE: enable/disable * - * @return 0 -- success, otherwise fail + * @return 0 -- success, otherwise fail */ static int woal_set_rxfilter(moal_private * priv, BOOLEAN enable) @@ -1955,7 +1955,7 @@ woal_set_rxfilter(moal_private * priv, BOOLEAN enable) #endif /** - * @brief Set priv command + * @brief Set priv command * * @param dev A pointer to net_device structure * @param info A pointer to iw_request_info structure @@ -2322,7 +2322,7 @@ woal_set_essid(struct net_device *dev, struct iw_request_info *info, req_ssid.ssid_len = dwrq->length - 1; #endif - /* + /* * Check if we asked for `any' or 'particular' */ if (!dwrq->flags) { @@ -2410,9 +2410,9 @@ woal_set_essid(struct net_device *dev, struct iw_request_info *info, return ret; } -/** - * @brief Get current essid - * +/** + * @brief Get current essid + * * @param dev A pointer to net_device structure * @param info A pointer to iw_request_info structure * @param dwrq A pointer to iw_point structure @@ -2753,7 +2753,7 @@ woal_get_scan(struct net_device *dev, struct iw_request_info *info, #endif current_val = current_ev + IW_EV_LCP_LEN; - /* + /* * Check if we added any event */ if ((unsigned int) (current_val - current_ev) > IW_EV_LCP_LEN) @@ -2870,9 +2870,9 @@ static const iw_handler woal_private_handler[] = { #if WIRELESS_EXT > 14 -/** +/** * @brief This function sends customized event to application. - * + * * @param priv A pointer to moal_private structure * @param str A pointer to event string * @@ -2904,11 +2904,11 @@ woal_send_iwevcustom_event(moal_private * priv, t_s8 * str) #endif #if WIRELESS_EXT >= 18 -/** +/** * @brief This function sends mic error event to application. - * + * * @param priv A pointer to moal_private structure - * @param event MIC MERROR EVENT. + * @param event MIC MERROR EVENT. * * @return N/A */ @@ -3006,7 +3006,7 @@ woal_get_wireless_stats(struct net_device *dev) ENTER(); - /* + /* * Since schedule() is not allowed from an atomic context * such as when dev_base_lock for netdevices is acquired * for reading/writing in kernel before this call, HostCmd -- cgit v1.2.3 From 5d5d968f15e3304c6ae913e1b09424f5cd93ebe8 Mon Sep 17 00:00:00 2001 From: Narayan Reddy Date: Thu, 26 Apr 2012 10:34:33 +0530 Subject: net: wireless: sd8797: change wlan interface to wlan0 Change wlan interface from mlan to wlan. Bug 954218 Change-Id: I5b2b2840a4830eda908a47cc0fc59d0479a1df34 Signed-off-by: Narayan Reddy Reviewed-on: http://git-master/r/98997 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Bharat Nihalani Reviewed-by: Rakesh Kumar --- drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c | 7 ++++++- drivers/net/wireless/sd8797/mlinux/moal_main.c | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/net/wireless/sd8797/mlinux') diff --git a/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c b/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c index 4e9ef8850b53..2282216f7d55 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c @@ -1133,7 +1133,12 @@ woal_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd) ret = -EINVAL; #endif #else - ret = -EINVAL; + /* + * FIXME Some of the IOCTLs are not supported by Marvel driver + * for CFG80211 and hence it is failing to turn on from UI, + * so returing 0(Sucess) for the time being. + */ + ret = 0; #endif break; } diff --git a/drivers/net/wireless/sd8797/mlinux/moal_main.c b/drivers/net/wireless/sd8797/mlinux/moal_main.c index 47c3252483a4..eac248b70129 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_main.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_main.c @@ -1385,7 +1385,7 @@ woal_add_interface(moal_handle * handle, t_u8 bss_index, t_u8 bss_type) } #ifdef STA_SUPPORT /* Allocate device name */ - if ((bss_type == MLAN_BSS_TYPE_STA) && (dev_alloc_name(dev, "mlan%d") < 0)) { + if ((bss_type == MLAN_BSS_TYPE_STA) && (dev_alloc_name(dev, "wlan%d") < 0)) { PRINTM(MERROR, "Could not allocate mlan device name\n"); goto error; } -- cgit v1.2.3 From 1aed8b0aad50077c193beee5be4174a23a2f46d9 Mon Sep 17 00:00:00 2001 From: Mohan T Date: Mon, 14 May 2012 12:07:54 +0530 Subject: net: wireless: sd8797: Integrate M2614311 Release Integrate Marvell SD8797 M2614311-GPL driver release Package Ver: T3T-14.69.11.p122-M2614311_A0B0-MGPL Bug 954218 Change-Id: Ic4c110cc06f45cf3f612df323e68c75edeb46e11 Signed-off-by: Mohan T Reviewed-on: http://git-master/r/100052 Reviewed-by: Rakesh Kumar GVS: Gerrit_Virtual_Submit Reviewed-by: Bharat Nihalani --- drivers/net/wireless/sd8797/mlinux/mlan.h | 35 + drivers/net/wireless/sd8797/mlinux/mlan_decl.h | 893 ++++++ drivers/net/wireless/sd8797/mlinux/mlan_ieee.h | 1322 +++++++++ drivers/net/wireless/sd8797/mlinux/mlan_ioctl.h | 2981 ++++++++++++++++++++ drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c | 630 ++++- drivers/net/wireless/sd8797/mlinux/moal_cfg80211.h | 16 +- .../net/wireless/sd8797/mlinux/moal_eth_ioctl.c | 1246 +++++++- .../net/wireless/sd8797/mlinux/moal_eth_ioctl.h | 23 +- drivers/net/wireless/sd8797/mlinux/moal_ioctl.c | 272 +- drivers/net/wireless/sd8797/mlinux/moal_main.c | 323 ++- drivers/net/wireless/sd8797/mlinux/moal_main.h | 74 +- drivers/net/wireless/sd8797/mlinux/moal_priv.c | 188 +- drivers/net/wireless/sd8797/mlinux/moal_priv.h | 14 + drivers/net/wireless/sd8797/mlinux/moal_proc.c | 6 +- drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c | 6 + drivers/net/wireless/sd8797/mlinux/moal_shim.c | 83 +- .../net/wireless/sd8797/mlinux/moal_sta_cfg80211.c | 358 +-- .../net/wireless/sd8797/mlinux/moal_uap_cfg80211.c | 482 +--- drivers/net/wireless/sd8797/mlinux/moal_wext.c | 17 +- drivers/net/wireless/sd8797/mlinux/moal_wext.h | 1 - 20 files changed, 7955 insertions(+), 1015 deletions(-) create mode 100644 drivers/net/wireless/sd8797/mlinux/mlan.h create mode 100644 drivers/net/wireless/sd8797/mlinux/mlan_decl.h create mode 100644 drivers/net/wireless/sd8797/mlinux/mlan_ieee.h create mode 100644 drivers/net/wireless/sd8797/mlinux/mlan_ioctl.h (limited to 'drivers/net/wireless/sd8797/mlinux') diff --git a/drivers/net/wireless/sd8797/mlinux/mlan.h b/drivers/net/wireless/sd8797/mlinux/mlan.h new file mode 100644 index 000000000000..a341e1547099 --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/mlan.h @@ -0,0 +1,35 @@ +/** @file mlan.h + * + * @brief This file declares all APIs that will be called from MOAL module. + * It also defines the data structures used for APIs between MLAN and MOAL. + * + * Copyright (C) 2008-2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +/****************************************************** +Change log: + 10/13/2008: initial version + 11/07/2008: split mlan.h into mlan_decl.h & mlan_ioctl.h +******************************************************/ + +#ifndef _MLAN_H_ +#define _MLAN_H_ + +#include "mlan_decl.h" +#include "mlan_ioctl.h" +#include "mlan_ieee.h" + +#endif /* !_MLAN_H_ */ diff --git a/drivers/net/wireless/sd8797/mlinux/mlan_decl.h b/drivers/net/wireless/sd8797/mlinux/mlan_decl.h new file mode 100644 index 000000000000..41cf2bf5f2f1 --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/mlan_decl.h @@ -0,0 +1,893 @@ +/** @file mlan_decl.h + * + * @brief This file declares the generic data structures and APIs. + * + * Copyright (C) 2008-2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +/****************************************************** +Change log: + 11/07/2008: initial version +******************************************************/ + +#ifndef _MLAN_DECL_H_ +#define _MLAN_DECL_H_ + +/** MLAN release version */ +#define MLAN_RELEASE_VERSION "311" + +/** Re-define generic data types for MLAN/MOAL */ +/** Signed char (1-byte) */ +typedef char t_s8; +/** Unsigned char (1-byte) */ +typedef unsigned char t_u8; +/** Signed short (2-bytes) */ +typedef short t_s16; +/** Unsigned short (2-bytes) */ +typedef unsigned short t_u16; +/** Signed long (4-bytes) */ +typedef int t_s32; +/** Unsigned long (4-bytes) */ +typedef unsigned int t_u32; +/** Signed long long 8-bytes) */ +typedef long long t_s64; +/** Unsigned long long 8-bytes) */ +typedef unsigned long long t_u64; +/** Void pointer (4-bytes) */ +typedef void t_void; +/** Size type */ +typedef t_u32 t_size; +/** Boolean type */ +typedef t_u8 t_bool; + +#ifdef MLAN_64BIT +/** Pointer type (64-bit) */ +typedef t_u64 t_ptr; +/** Signed value (64-bit) */ +typedef t_s64 t_sval; +#else +/** Pointer type (32-bit) */ +typedef t_u32 t_ptr; +/** Signed value (32-bit) */ +typedef t_s32 t_sval; +#endif + +/** Constants below */ + +#ifdef __GNUC__ +/** Structure packing begins */ +#define MLAN_PACK_START +/** Structure packeing end */ +#define MLAN_PACK_END __attribute__ ((packed)) +#else /* !__GNUC__ */ +#ifdef PRAGMA_PACK +/** Structure packing begins */ +#define MLAN_PACK_START +/** Structure packeing end */ +#define MLAN_PACK_END +#else /* !PRAGMA_PACK */ +/** Structure packing begins */ +#define MLAN_PACK_START __packed +/** Structure packing end */ +#define MLAN_PACK_END +#endif /* PRAGMA_PACK */ +#endif /* __GNUC__ */ + +#ifndef INLINE +#ifdef __GNUC__ +/** inline directive */ +#define INLINE inline +#else +/** inline directive */ +#define INLINE __inline +#endif +#endif + +/** MLAN TRUE */ +#define MTRUE (1) +/** MLAN FALSE */ +#define MFALSE (0) + +/** Macros for Data Alignment : size */ +#define ALIGN_SZ(p, a) \ + (((p) + ((a) - 1)) & ~((a) - 1)) + +/** Macros for Data Alignment : address */ +#define ALIGN_ADDR(p, a) \ + ((((t_ptr)(p)) + (((t_ptr)(a)) - 1)) & ~(((t_ptr)(a)) - 1)) + +/** Return the byte offset of a field in the given structure */ +#define MLAN_FIELD_OFFSET(type, field) ((t_u32)(t_ptr)&(((type *)0)->field)) +/** Return aligned offset */ +#define OFFSET_ALIGN_ADDR(p, a) (t_u32)(ALIGN_ADDR(p, a) - (t_ptr)p) + +/** Maximum BSS numbers */ +#define MLAN_MAX_BSS_NUM (16) + +/** NET IP alignment */ +#define MLAN_NET_IP_ALIGN 0 + +/** DMA alignment */ +#define DMA_ALIGNMENT 64 +/** max size of TxPD */ +#define MAX_TXPD_SIZE 32 + +/** Minimum data header length */ +#define MLAN_MIN_DATA_HEADER_LEN (DMA_ALIGNMENT+MAX_TXPD_SIZE) + +/** rx data header length */ +#define MLAN_RX_HEADER_LEN MLAN_MIN_DATA_HEADER_LEN + +/** This is current limit on Maximum Tx AMPDU allowed */ +#define MLAN_MAX_TX_BASTREAM_SUPPORTED 2 +/** This is current limit on Maximum Rx AMPDU allowed */ +#define MLAN_MAX_RX_BASTREAM_SUPPORTED 16 + +#ifdef STA_SUPPORT +/** Default Win size attached during ADDBA request */ +#define MLAN_STA_AMPDU_DEF_TXWINSIZE 16 +/** Default Win size attached during ADDBA response */ +#define MLAN_STA_AMPDU_DEF_RXWINSIZE 32 +#endif /* STA_SUPPORT */ +#ifdef UAP_SUPPORT +/** Default Win size attached during ADDBA request */ +#define MLAN_UAP_AMPDU_DEF_TXWINSIZE 32 +/** Default Win size attached during ADDBA response */ +#define MLAN_UAP_AMPDU_DEF_RXWINSIZE 16 +#endif /* UAP_SUPPORT */ +/** Block ack timeout value */ +#define MLAN_DEFAULT_BLOCK_ACK_TIMEOUT 0xffff +/** Maximum Tx Win size configured for ADDBA request [10 bits] */ +#define MLAN_AMPDU_MAX_TXWINSIZE 0x3ff +/** Maximum Rx Win size configured for ADDBA request [10 bits] */ +#define MLAN_AMPDU_MAX_RXWINSIZE 0x3ff + +/** Rate index for HR/DSSS 0 */ +#define MLAN_RATE_INDEX_HRDSSS0 0 +/** Rate index for HR/DSSS 3 */ +#define MLAN_RATE_INDEX_HRDSSS3 3 +/** Rate index for OFDM 0 */ +#define MLAN_RATE_INDEX_OFDM0 4 +/** Rate index for OFDM 7 */ +#define MLAN_RATE_INDEX_OFDM7 11 +/** Rate index for MCS 0 */ +#define MLAN_RATE_INDEX_MCS0 12 +/** Rate index for MCS 7 */ +#define MLAN_RATE_INDEX_MCS7 19 +/** Rate index for MCS 9 */ +#define MLAN_RATE_INDEX_MCS9 21 +/** Rate index for MCS15 */ +#define MLAN_RATE_INDEX_MCS15 27 +/** Rate index for MCS 32 */ +#define MLAN_RATE_INDEX_MCS32 44 +/** Rate index for MCS 127 */ +#define MLAN_RATE_INDEX_MCS127 139 + +/** Rate bitmap for OFDM 0 */ +#define MLAN_RATE_BITMAP_OFDM0 16 +/** Rate bitmap for OFDM 7 */ +#define MLAN_RATE_BITMAP_OFDM7 23 +/** Rate bitmap for MCS 0 */ +#define MLAN_RATE_BITMAP_MCS0 32 +/** Rate bitmap for MCS 127 */ +#define MLAN_RATE_BITMAP_MCS127 159 + +/** Size of rx data buffer */ +#define MLAN_RX_DATA_BUF_SIZE (4 * 1024) +/** Size of rx command buffer */ +#define MLAN_RX_CMD_BUF_SIZE (2 * 1024) + +/** MLAN MAC Address Length */ +#define MLAN_MAC_ADDR_LENGTH (6) +/** MLAN 802.11 MAC Address */ +typedef t_u8 mlan_802_11_mac_addr[MLAN_MAC_ADDR_LENGTH]; + +/** MLAN Maximum SSID Length */ +#define MLAN_MAX_SSID_LENGTH (32) + +/** RTS/FRAG related defines */ +/** Minimum RTS value */ +#define MLAN_RTS_MIN_VALUE (0) +/** Maximum RTS value */ +#define MLAN_RTS_MAX_VALUE (2347) +/** Minimum FRAG value */ +#define MLAN_FRAG_MIN_VALUE (256) +/** Maximum FRAG value */ +#define MLAN_FRAG_MAX_VALUE (2346) + +/** Minimum tx retry count */ +#define MLAN_TX_RETRY_MIN (0) +/** Maximum tx retry count */ +#define MLAN_TX_RETRY_MAX (14) + +/** define SDIO block size for data Tx/Rx */ +/* We support up to 480-byte block size due to FW buffer limitation. */ +#define MLAN_SDIO_BLOCK_SIZE 256 + +/** define SDIO block size for firmware download */ +#define MLAN_SDIO_BLOCK_SIZE_FW_DNLD MLAN_SDIO_BLOCK_SIZE + +/** define allocated buffer size */ +#define ALLOC_BUF_SIZE (4 * 1024) + +/** SDIO IO Port mask */ +#define MLAN_SDIO_IO_PORT_MASK 0xfffff +/** SDIO Block/Byte mode mask */ +#define MLAN_SDIO_BYTE_MODE_MASK 0x80000000 + +/** Max retry number of IO write */ +#define MAX_WRITE_IOMEM_RETRY 2 + +/** IN parameter */ +#define IN +/** OUT parameter */ +#define OUT + +/** BIT value */ +#define MBIT(x) (((t_u32)1) << (x)) + +/** Buffer flag for requeued packet */ +#define MLAN_BUF_FLAG_REQUEUED_PKT MBIT(0) +/** Buffer flag for transmit buf from moal */ +#define MLAN_BUF_FLAG_MOAL_TX_BUF MBIT(1) +/** Buffer flag for malloc mlan_buffer */ +#define MLAN_BUF_FLAG_MALLOC_BUF MBIT(2) + +/** Buffer flag for bridge packet */ +#define MLAN_BUF_FLAG_BRIDGE_BUF MBIT(3) + +#ifdef DEBUG_LEVEL1 +/** Debug level bit definition */ +#define MMSG MBIT(0) +#define MFATAL MBIT(1) +#define MERROR MBIT(2) +#define MDATA MBIT(3) +#define MCMND MBIT(4) +#define MEVENT MBIT(5) +#define MINTR MBIT(6) +#define MIOCTL MBIT(7) + +#define MDAT_D MBIT(16) +#define MCMD_D MBIT(17) +#define MEVT_D MBIT(18) +#define MFW_D MBIT(19) +#define MIF_D MBIT(20) + +#define MENTRY MBIT(28) +#define MWARN MBIT(29) +#define MINFO MBIT(30) +#define MHEX_DUMP MBIT(31) +#endif /* DEBUG_LEVEL1 */ + +/** Memory allocation type: DMA */ +#define MLAN_MEM_DMA MBIT(0) + +/** Default memory allocation flag */ +#define MLAN_MEM_DEF 0 + +/** mlan_status */ +typedef enum _mlan_status +{ + MLAN_STATUS_FAILURE = 0xffffffff, + MLAN_STATUS_SUCCESS = 0, + MLAN_STATUS_PENDING, + MLAN_STATUS_RESOURCE, +} mlan_status; + +/** mlan_error_code */ +typedef enum _mlan_error_code +{ + /** No error */ + MLAN_ERROR_NO_ERROR = 0, + /** Firmware/device errors below (MSB=0) */ + MLAN_ERROR_FW_NOT_READY = 0x00000001, + MLAN_ERROR_FW_BUSY, + MLAN_ERROR_FW_CMDRESP, + MLAN_ERROR_DATA_TX_FAIL, + MLAN_ERROR_DATA_RX_FAIL, + /** Driver errors below (MSB=1) */ + MLAN_ERROR_PKT_SIZE_INVALID = 0x80000001, + MLAN_ERROR_PKT_TIMEOUT, + MLAN_ERROR_PKT_INVALID, + MLAN_ERROR_CMD_INVALID, + MLAN_ERROR_CMD_TIMEOUT, + MLAN_ERROR_CMD_DNLD_FAIL, + MLAN_ERROR_CMD_CANCEL, + MLAN_ERROR_CMD_RESP_FAIL, + MLAN_ERROR_CMD_ASSOC_FAIL, + MLAN_ERROR_CMD_SCAN_FAIL, + MLAN_ERROR_IOCTL_INVALID, + MLAN_ERROR_IOCTL_FAIL, + MLAN_ERROR_EVENT_UNKNOWN, + MLAN_ERROR_INVALID_PARAMETER, + MLAN_ERROR_NO_MEM, + /** More to add */ +} mlan_error_code; + +/** mlan_buf_type */ +typedef enum _mlan_buf_type +{ + MLAN_BUF_TYPE_CMD = 1, + MLAN_BUF_TYPE_DATA, + MLAN_BUF_TYPE_EVENT, + MLAN_BUF_TYPE_RAW_DATA, +} mlan_buf_type; + +/** MLAN BSS type */ +typedef enum _mlan_bss_type +{ + MLAN_BSS_TYPE_STA = 0, + MLAN_BSS_TYPE_UAP = 1, +#ifdef WIFI_DIRECT_SUPPORT + MLAN_BSS_TYPE_WIFIDIRECT = 2, +#endif + MLAN_BSS_TYPE_ANY = 0xff, +} mlan_bss_type; + +/** MLAN BSS role */ +typedef enum _mlan_bss_role +{ + MLAN_BSS_ROLE_STA = 0, + MLAN_BSS_ROLE_UAP = 1, + MLAN_BSS_ROLE_ANY = 0xff, +} mlan_bss_role; + +/** BSS role bit mask */ +#define BSS_ROLE_BIT_MASK MBIT(0) + +/** Get BSS role */ +#define GET_BSS_ROLE(priv) ((priv)->bss_role & BSS_ROLE_BIT_MASK) + +/** mlan_data_frame_type */ +typedef enum _mlan_data_frame_type +{ + MLAN_DATA_FRAME_TYPE_ETH_II = 0, + MLAN_DATA_FRAME_TYPE_802_11, +} mlan_data_frame_type; + +/** mlan_event_id */ +typedef enum _mlan_event_id +{ + /* Event generated by firmware (MSB=0) */ + MLAN_EVENT_ID_FW_UNKNOWN = 0x00000001, + MLAN_EVENT_ID_FW_ADHOC_LINK_SENSED, + MLAN_EVENT_ID_FW_ADHOC_LINK_LOST, + MLAN_EVENT_ID_FW_DISCONNECTED, + MLAN_EVENT_ID_FW_MIC_ERR_UNI, + MLAN_EVENT_ID_FW_MIC_ERR_MUL, + MLAN_EVENT_ID_FW_BCN_RSSI_LOW, + MLAN_EVENT_ID_FW_BCN_RSSI_HIGH, + MLAN_EVENT_ID_FW_BCN_SNR_LOW, + MLAN_EVENT_ID_FW_BCN_SNR_HIGH, + MLAN_EVENT_ID_FW_MAX_FAIL, + MLAN_EVENT_ID_FW_DATA_RSSI_LOW, + MLAN_EVENT_ID_FW_DATA_RSSI_HIGH, + MLAN_EVENT_ID_FW_DATA_SNR_LOW, + MLAN_EVENT_ID_FW_DATA_SNR_HIGH, + MLAN_EVENT_ID_FW_LINK_QUALITY, + MLAN_EVENT_ID_FW_PORT_RELEASE, + MLAN_EVENT_ID_FW_PRE_BCN_LOST, + MLAN_EVENT_ID_FW_WMM_CONFIG_CHANGE, + MLAN_EVENT_ID_FW_HS_WAKEUP, + MLAN_EVENT_ID_FW_BG_SCAN, + MLAN_EVENT_ID_FW_WEP_ICV_ERR, + MLAN_EVENT_ID_FW_STOP_TX, + MLAN_EVENT_ID_FW_START_TX, + MLAN_EVENT_ID_FW_CHANNEL_SWITCH_ANN, + MLAN_EVENT_ID_FW_RADAR_DETECTED, + MLAN_EVENT_ID_FW_CHANNEL_REPORT_RDY, + MLAN_EVENT_ID_FW_BW_CHANGED, +#ifdef WIFI_DIRECT_SUPPORT + MLAN_EVENT_ID_FW_REMAIN_ON_CHAN_EXPIRED, +#endif +#ifdef UAP_SUPPORT + MLAN_EVENT_ID_UAP_FW_BSS_START, + MLAN_EVENT_ID_UAP_FW_BSS_ACTIVE, + MLAN_EVENT_ID_UAP_FW_BSS_IDLE, + MLAN_EVENT_ID_UAP_FW_STA_CONNECT, + MLAN_EVENT_ID_UAP_FW_STA_DISCONNECT, +#endif + + /* Event generated by MLAN driver (MSB=1) */ + MLAN_EVENT_ID_DRV_CONNECTED = 0x80000001, + MLAN_EVENT_ID_DRV_DEFER_HANDLING, + MLAN_EVENT_ID_DRV_HS_ACTIVATED, + MLAN_EVENT_ID_DRV_HS_DEACTIVATED, + MLAN_EVENT_ID_DRV_MGMT_FRAME, + MLAN_EVENT_ID_DRV_OBSS_SCAN_PARAM, + MLAN_EVENT_ID_DRV_PASSTHRU, + MLAN_EVENT_ID_DRV_SCAN_REPORT, + MLAN_EVENT_ID_DRV_MEAS_REPORT, + MLAN_EVENT_ID_DRV_REPORT_STRING, + MLAN_EVENT_ID_DRV_DBG_DUMP, +} mlan_event_id; + +/** Data Structures */ +/** mlan_image data structure */ +typedef struct _mlan_fw_image +{ + /** Helper image buffer pointer */ + t_u8 *phelper_buf; + /** Helper image length */ + t_u32 helper_len; + /** Firmware image buffer pointer */ + t_u8 *pfw_buf; + /** Firmware image length */ + t_u32 fw_len; +} mlan_fw_image, *pmlan_fw_image; + +/** Custom data structure */ +typedef struct _mlan_init_param +{ + /** Cal data buffer pointer */ + t_u8 *pcal_data_buf; + /** Cal data length */ + t_u32 cal_data_len; + /** Other custom data */ +} mlan_init_param, *pmlan_init_param; + +/** mlan_event data structure */ +typedef struct _mlan_event +{ + /** BSS index number for multiple BSS support */ + t_u32 bss_index; + /** Event ID */ + mlan_event_id event_id; + /** Event length */ + t_u32 event_len; + /** Event buffer */ + t_u8 event_buf[1]; +} mlan_event, *pmlan_event; + +/** mlan_event_scan_result data structure */ +typedef MLAN_PACK_START struct _mlan_event_scan_result +{ + /** Event ID */ + t_u16 event_id; + /** BSS index number for multiple BSS support */ + t_u8 bss_index; + /** BSS type */ + t_u8 bss_type; + /** More event available or not */ + t_u8 more_event; + /** Reserved */ + t_u8 reserved[3]; + /** Size of the response buffer */ + t_u16 buf_size; + /** Number of BSS in scan response */ + t_u8 num_of_set; +} MLAN_PACK_END mlan_event_scan_result, *pmlan_event_scan_result; + +/** mlan_ioctl_req data structure */ +typedef struct _mlan_ioctl_req +{ + /** Status code from firmware/driver */ + t_u32 status_code; + /** BSS index number for multiple BSS support */ + t_u32 bss_index; + /** Request id */ + t_u32 req_id; + /** Action: set or get */ + t_u32 action; + /** Pointer to buffer */ + t_u8 *pbuf; + /** Length of buffer */ + t_u32 buf_len; + /** Length of the data read/written in buffer */ + t_u32 data_read_written; + /** Length of buffer needed */ + t_u32 buf_len_needed; + /** Reserved for MOAL module */ + t_ptr reserved_1; +} mlan_ioctl_req, *pmlan_ioctl_req; + +/** mlan_buffer data structure */ +typedef struct _mlan_buffer +{ + /** Pointer to previous mlan_buffer */ + struct _mlan_buffer *pprev; + /** Pointer to next mlan_buffer */ + struct _mlan_buffer *pnext; + /** Status code from firmware/driver */ + t_u32 status_code; + /** Flags for this buffer */ + t_u32 flags; + /** BSS index number for multiple BSS support */ + t_u32 bss_index; + /** Buffer descriptor, e.g. skb in Linux */ + t_void *pdesc; + /** Pointer to buffer */ + t_u8 *pbuf; + /** Offset to data */ + t_u32 data_offset; + /** Data length */ + t_u32 data_len; + /** Buffer type: data, cmd, event etc. */ + mlan_buf_type buf_type; + + /** Fields below are valid for data packet only */ + /** QoS priority */ + t_u32 priority; + /** Time stamp when packet is received (seconds) */ + t_u32 in_ts_sec; + /** Time stamp when packet is received (micro seconds) */ + t_u32 in_ts_usec; + /** Time stamp when packet is processed (seconds) */ + t_u32 out_ts_sec; + /** Time stamp when packet is processed (micro seconds) */ + t_u32 out_ts_usec; + + /** Fields below are valid for MLAN module only */ + /** Pointer to parent mlan_buffer */ + struct _mlan_buffer *pparent; + /** Use count for this buffer */ + t_u32 use_count; +} mlan_buffer, *pmlan_buffer; + +/** mlan_bss_attr data structure */ +typedef struct _mlan_bss_attr +{ + /** BSS type */ + t_u32 bss_type; + /** Data frame type: Ethernet II, 802.11, etc. */ + t_u32 frame_type; + /** The BSS is active (non-0) or not (0). */ + t_u32 active; + /** BSS Priority */ + t_u32 bss_priority; + /** BSS number */ + t_u32 bss_num; +} mlan_bss_attr, *pmlan_bss_attr; + +#ifdef PRAGMA_PACK +#pragma pack(push, 1) +#endif + +/** Type enumeration for the command result */ +typedef MLAN_PACK_START enum _mlan_cmd_result_e +{ + MLAN_CMD_RESULT_SUCCESS = 0, + MLAN_CMD_RESULT_FAILURE = 1, + MLAN_CMD_RESULT_TIMEOUT = 2, + MLAN_CMD_RESULT_INVALID_DATA = 3 +} MLAN_PACK_END mlan_cmd_result_e; + +/** Type enumeration of WMM AC_QUEUES */ +typedef MLAN_PACK_START enum _mlan_wmm_ac_e +{ + WMM_AC_BK, + WMM_AC_BE, + WMM_AC_VI, + WMM_AC_VO +} MLAN_PACK_END mlan_wmm_ac_e; + +/** Type enumeration for the action field in the Queue Config command */ +typedef MLAN_PACK_START enum _mlan_wmm_queue_config_action_e +{ + MLAN_WMM_QUEUE_CONFIG_ACTION_GET = 0, + MLAN_WMM_QUEUE_CONFIG_ACTION_SET = 1, + MLAN_WMM_QUEUE_CONFIG_ACTION_DEFAULT = 2, + MLAN_WMM_QUEUE_CONFIG_ACTION_MAX +} MLAN_PACK_END mlan_wmm_queue_config_action_e; + +/** Type enumeration for the action field in the queue stats command */ +typedef MLAN_PACK_START enum _mlan_wmm_queue_stats_action_e +{ + MLAN_WMM_STATS_ACTION_START = 0, + MLAN_WMM_STATS_ACTION_STOP = 1, + MLAN_WMM_STATS_ACTION_GET_CLR = 2, + MLAN_WMM_STATS_ACTION_SET_CFG = 3, /* Not currently used */ + MLAN_WMM_STATS_ACTION_GET_CFG = 4, /* Not currently used */ + MLAN_WMM_STATS_ACTION_MAX +} MLAN_PACK_END mlan_wmm_queue_stats_action_e; + +/** + * @brief IOCTL structure for a Traffic stream status. + * + */ +typedef MLAN_PACK_START struct +{ + /** TSID: Range: 0->7 */ + t_u8 tid; + /** TSID specified is valid */ + t_u8 valid; + /** AC TSID is active on */ + t_u8 access_category; + /** UP specified for the TSID */ + t_u8 user_priority; + /** Power save mode for TSID: 0 (legacy), 1 (UAPSD) */ + t_u8 psb; + /** Upstream(0), Downlink(1), Bidirectional(3) */ + t_u8 flow_dir; + /** Medium time granted for the TSID */ + t_u16 medium_time; +} MLAN_PACK_END wlan_ioctl_wmm_ts_status_t, +/** Type definition of mlan_ds_wmm_ts_status for MLAN_OID_WMM_CFG_TS_STATUS */ + mlan_ds_wmm_ts_status, *pmlan_ds_wmm_ts_status; + +/** Max Ie length */ +#define MAX_IE_SIZE 256 + +/** custom IE */ +typedef MLAN_PACK_START struct _custom_ie +{ + /** IE Index */ + t_u16 ie_index; + /** Mgmt Subtype Mask */ + t_u16 mgmt_subtype_mask; + /** IE Length */ + t_u16 ie_length; + /** IE buffer */ + t_u8 ie_buffer[MAX_IE_SIZE]; +} MLAN_PACK_END custom_ie; + +/** Max IE index to FW */ +#define MAX_MGMT_IE_INDEX_TO_FW 4 +/** Max IE index per BSS */ +#define MAX_MGMT_IE_INDEX 16 + +/** custom IE info */ +typedef MLAN_PACK_START struct _custom_ie_info +{ + /** size of buffer */ + t_u16 buf_size; + /** no of buffers of buf_size */ + t_u16 buf_count; +} MLAN_PACK_END custom_ie_info; + +/** TLV buffer : Max Mgmt IE */ +typedef MLAN_PACK_START struct _tlvbuf_max_mgmt_ie +{ + /** Type */ + t_u16 type; + /** Length */ + t_u16 len; + /** No of tuples */ + t_u16 count; + /** custom IE info tuples */ + custom_ie_info info[MAX_MGMT_IE_INDEX]; +} MLAN_PACK_END tlvbuf_max_mgmt_ie; + +/** TLV buffer : custom IE */ +typedef MLAN_PACK_START struct _tlvbuf_custom_ie +{ + /** Type */ + t_u16 type; + /** Length */ + t_u16 len; + /** IE data */ + custom_ie ie_data_list[MAX_MGMT_IE_INDEX_TO_FW]; + /** Max mgmt IE TLV */ + tlvbuf_max_mgmt_ie max_mgmt_ie; +} MLAN_PACK_END mlan_ds_misc_custom_ie; + +#ifdef PRAGMA_PACK +#pragma pack(pop) +#endif + +/** mlan_callbacks data structure */ +typedef struct _mlan_callbacks +{ + /** moal_get_fw_data */ + mlan_status(*moal_get_fw_data) (IN t_void * pmoal_handle, + IN t_u32 offset, + IN t_u32 len, OUT t_u8 * pbuf); + /** moal_init_fw_complete */ + mlan_status(*moal_init_fw_complete) (IN t_void * pmoal_handle, + IN mlan_status status); + /** moal_shutdown_fw_complete */ + mlan_status(*moal_shutdown_fw_complete) (IN t_void * pmoal_handle, + IN mlan_status status); + /** moal_send_packet_complete */ + mlan_status(*moal_send_packet_complete) (IN t_void * pmoal_handle, + IN pmlan_buffer pmbuf, + IN mlan_status status); + /** moal_recv_complete */ + mlan_status(*moal_recv_complete) (IN t_void * pmoal_handle, + IN pmlan_buffer pmbuf, + IN t_u32 port, IN mlan_status status); + /** moal_recv_packet */ + mlan_status(*moal_recv_packet) (IN t_void * pmoal_handle, + IN pmlan_buffer pmbuf); + /** moal_recv_event */ + mlan_status(*moal_recv_event) (IN t_void * pmoal_handle, + IN pmlan_event pmevent); + /** moal_ioctl_complete */ + mlan_status(*moal_ioctl_complete) (IN t_void * pmoal_handle, + IN pmlan_ioctl_req pioctl_req, + IN mlan_status status); + /** moal_alloc_mlan_buffer */ + mlan_status(*moal_alloc_mlan_buffer) (IN t_void * pmoal_handle, + IN t_u32 size, + OUT pmlan_buffer * pmbuf); + /** moal_free_mlan_buffer */ + mlan_status(*moal_free_mlan_buffer) (IN t_void * pmoal_handle, + IN pmlan_buffer pmbuf); + /** moal_write_reg */ + mlan_status(*moal_write_reg) (IN t_void * pmoal_handle, + IN t_u32 reg, IN t_u32 data); + /** moal_read_reg */ + mlan_status(*moal_read_reg) (IN t_void * pmoal_handle, + IN t_u32 reg, OUT t_u32 * data); + /** moal_write_data_sync */ + mlan_status(*moal_write_data_sync) (IN t_void * pmoal_handle, + IN pmlan_buffer pmbuf, + IN t_u32 port, IN t_u32 timeout); + /** moal_read_data_sync */ + mlan_status(*moal_read_data_sync) (IN t_void * pmoal_handle, + IN OUT pmlan_buffer pmbuf, + IN t_u32 port, IN t_u32 timeout); + /** moal_malloc */ + mlan_status(*moal_malloc) (IN t_void * pmoal_handle, + IN t_u32 size, IN t_u32 flag, OUT t_u8 ** ppbuf); + /** moal_mfree */ + mlan_status(*moal_mfree) (IN t_void * pmoal_handle, IN t_u8 * pbuf); + /** moal_memset */ + t_void *(*moal_memset) (IN t_void * pmoal_handle, + IN t_void * pmem, IN t_u8 byte, IN t_u32 num); + /** moal_memcpy */ + t_void *(*moal_memcpy) (IN t_void * pmoal_handle, + IN t_void * pdest, + IN const t_void * psrc, IN t_u32 num); + /** moal_memmove */ + t_void *(*moal_memmove) (IN t_void * pmoal_handle, + IN t_void * pdest, + IN const t_void * psrc, IN t_u32 num); + /** moal_memcmp */ + t_s32(*moal_memcmp) (IN t_void * pmoal_handle, + IN const t_void * pmem1, + IN const t_void * pmem2, IN t_u32 num); + /** moal_udelay */ + t_void(*moal_udelay) (IN t_void * pmoal_handle, IN t_u32 udelay); + /** moal_get_system_time */ + mlan_status(*moal_get_system_time) (IN t_void * pmoal_handle, + OUT t_u32 * psec, OUT t_u32 * pusec); + /** moal_init_timer*/ + mlan_status(*moal_init_timer) (IN t_void * pmoal_handle, + OUT t_void ** pptimer, + IN t_void(*callback) (t_void * pcontext), + IN t_void * pcontext); + /** moal_free_timer */ + mlan_status(*moal_free_timer) (IN t_void * pmoal_handle, + IN t_void * ptimer); + /** moal_start_timer*/ + mlan_status(*moal_start_timer) (IN t_void * pmoal_handle, + IN t_void * ptimer, + IN t_u8 periodic, IN t_u32 msec); + /** moal_stop_timer*/ + mlan_status(*moal_stop_timer) (IN t_void * pmoal_handle, + IN t_void * ptimer); + /** moal_init_lock */ + mlan_status(*moal_init_lock) (IN t_void * pmoal_handle, + OUT t_void ** pplock); + /** moal_free_lock */ + mlan_status(*moal_free_lock) (IN t_void * pmoal_handle, + IN t_void * plock); + /** moal_spin_lock */ + mlan_status(*moal_spin_lock) (IN t_void * pmoal_handle, + IN t_void * plock); + /** moal_spin_unlock */ + mlan_status(*moal_spin_unlock) (IN t_void * pmoal_handle, + IN t_void * plock); + /** moal_print */ + t_void(*moal_print) (IN t_void * pmoal_handle, + IN t_u32 level, IN t_s8 * pformat, IN ...); + /** moal_print_netintf */ + t_void(*moal_print_netintf) (IN t_void * pmoal_handle, + IN t_u32 bss_index, IN t_u32 level); + /** moal_assert */ + t_void(*moal_assert) (IN t_void * pmoal_handle, IN t_u32 cond); +} mlan_callbacks, *pmlan_callbacks; + +/** Interrupt Mode SDIO */ +#define INT_MODE_SDIO 0 +/** Interrupt Mode GPIO */ +#define INT_MODE_GPIO 1 + +/** Parameter unchanged, use MLAN default setting */ +#define MLAN_INIT_PARA_UNCHANGED 0 +/** Parameter enabled, override MLAN default setting */ +#define MLAN_INIT_PARA_ENABLED 1 +/** Parameter disabled, override MLAN default setting */ +#define MLAN_INIT_PARA_DISABLED 2 + +/** mlan_device data structure */ +typedef struct _mlan_device +{ + /** MOAL Handle */ + t_void *pmoal_handle; + /** BSS Attributes */ + mlan_bss_attr bss_attr[MLAN_MAX_BSS_NUM]; + /** Callbacks */ + mlan_callbacks callbacks; +#ifdef MFG_CMD_SUPPORT + /** MFG mode */ + t_u32 mfg_mode; +#endif + /** SDIO interrupt mode (0: INT_MODE_SDIO, 1: INT_MODE_GPIO) */ + t_u32 int_mode; + /** GPIO interrupt pin number */ + t_u32 gpio_pin; +#ifdef DEBUG_LEVEL1 + /** Driver debug bit masks */ + t_u32 drvdbg; +#endif +#ifdef SDIO_MULTI_PORT_TX_AGGR + /** SDIO MPA Tx */ + t_u32 mpa_tx_cfg; +#endif +#ifdef SDIO_MULTI_PORT_RX_AGGR + /** SDIO MPA Rx */ + t_u32 mpa_rx_cfg; +#endif + /** Auto deep sleep */ + t_u32 auto_ds; + /** IEEE PS mode */ + t_u32 ps_mode; + /** Max Tx buffer size */ + t_u32 max_tx_buf; +#if defined(STA_SUPPORT) + /** 802.11d configuration */ + t_u32 cfg_11d; +#endif +} mlan_device, *pmlan_device; + +/** MLAN API function prototype */ +#define MLAN_API + +/** Registration */ +MLAN_API mlan_status mlan_register(IN pmlan_device pmdevice, + OUT t_void ** ppmlan_adapter); + +/** Un-registration */ +MLAN_API mlan_status mlan_unregister(IN t_void * pmlan_adapter); + +/** Firmware Downloading */ +MLAN_API mlan_status mlan_dnld_fw(IN t_void * pmlan_adapter, + IN pmlan_fw_image pmfw); + +/** Custom data pass API */ +MLAN_API mlan_status mlan_set_init_param(IN t_void * pmlan_adapter, + IN pmlan_init_param pparam); + +/** Firmware Initialization */ +MLAN_API mlan_status mlan_init_fw(IN t_void * pmlan_adapter); + +/** Firmware Shutdown */ +MLAN_API mlan_status mlan_shutdown_fw(IN t_void * pmlan_adapter); + +/** Main Process */ +MLAN_API mlan_status mlan_main_process(IN t_void * pmlan_adapter); + +/** Packet Transmission */ +MLAN_API mlan_status mlan_send_packet(IN t_void * pmlan_adapter, + IN pmlan_buffer pmbuf); + +/** Packet Reception complete callback */ +MLAN_API mlan_status mlan_recv_packet_complete(IN t_void * pmlan_adapter, + IN pmlan_buffer pmbuf, + IN mlan_status status); + +/** interrupt handler */ +MLAN_API t_void mlan_interrupt(IN t_void * pmlan_adapter); + +/** mlan ioctl */ +MLAN_API mlan_status mlan_ioctl(IN t_void * pmlan_adapter, + IN pmlan_ioctl_req pioctl_req); +/** mlan select wmm queue */ +MLAN_API t_u8 mlan_select_wmm_queue(IN t_void * pmlan_adapter, + IN t_u8 bss_num, IN t_u8 tid); +#endif /* !_MLAN_DECL_H_ */ diff --git a/drivers/net/wireless/sd8797/mlinux/mlan_ieee.h b/drivers/net/wireless/sd8797/mlinux/mlan_ieee.h new file mode 100644 index 000000000000..2431e06f48fa --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/mlan_ieee.h @@ -0,0 +1,1322 @@ +/** @file mlan_ieee.h + * + * @brief This file contains IEEE information element related + * definitions used in MLAN and MOAL module. + * + * Copyright (C) 2008-2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +/****************************************************** +Change log: + 11/03/2008: initial version +******************************************************/ + +#ifndef _MLAN_IEEE_H_ +#define _MLAN_IEEE_H_ + +/** FIX IES size in beacon buffer */ +#define WLAN_802_11_FIXED_IE_SIZE 12 +/** WLAN supported rates */ +#define WLAN_SUPPORTED_RATES 14 + +/** WLAN supported rates extension*/ +#define WLAN_SUPPORTED_RATES_EXT 32 + +/** Enumeration definition*/ +/** WLAN_802_11_NETWORK_TYPE */ +typedef enum _WLAN_802_11_NETWORK_TYPE +{ + Wlan802_11FH, + Wlan802_11DS, + /* Defined as upper bound */ + Wlan802_11NetworkTypeMax +} WLAN_802_11_NETWORK_TYPE; + +/** Maximum size of IEEE Information Elements */ +#define IEEE_MAX_IE_SIZE 256 + +#ifdef BIG_ENDIAN_SUPPORT +/** Frame control: Type Mgmt frame */ +#define IEEE80211_FC_MGMT_FRAME_TYPE_MASK 0x3000 +/** Frame control: SubType Mgmt frame */ +#define IEEE80211_GET_FC_MGMT_FRAME_SUBTYPE(fc) (((fc) & 0xF000) >> 12) +#else +/** Frame control: Type Mgmt frame */ +#define IEEE80211_FC_MGMT_FRAME_TYPE_MASK 0x000C +/** Frame control: SubType Mgmt frame */ +#define IEEE80211_GET_FC_MGMT_FRAME_SUBTYPE(fc) (((fc) & 0x00F0) >> 4) +#endif + +#ifdef PRAGMA_PACK +#pragma pack(push, 1) +#endif + +/** IEEE Type definitions */ +typedef MLAN_PACK_START enum _IEEEtypes_ElementId_e +{ + SSID = 0, + SUPPORTED_RATES = 1, + + FH_PARAM_SET = 2, + DS_PARAM_SET = 3, + CF_PARAM_SET = 4, + + IBSS_PARAM_SET = 6, + +#ifdef STA_SUPPORT + COUNTRY_INFO = 7, +#endif /* STA_SUPPORT */ + + POWER_CONSTRAINT = 32, + POWER_CAPABILITY = 33, + TPC_REQUEST = 34, + TPC_REPORT = 35, + SUPPORTED_CHANNELS = 36, + CHANNEL_SWITCH_ANN = 37, + QUIET = 40, + IBSS_DFS = 41, + HT_CAPABILITY = 45, + HT_OPERATION = 61, + BSSCO_2040 = 72, + OVERLAPBSSSCANPARAM = 74, + EXT_CAPABILITY = 127, + + ERP_INFO = 42, + + EXTENDED_SUPPORTED_RATES = 50, + + VENDOR_SPECIFIC_221 = 221, + WMM_IE = VENDOR_SPECIFIC_221, + + WPS_IE = VENDOR_SPECIFIC_221, + + WPA_IE = VENDOR_SPECIFIC_221, + RSN_IE = 48, + VS_IE = VENDOR_SPECIFIC_221, + WAPI_IE = 68, +} MLAN_PACK_END IEEEtypes_ElementId_e; + +/** IEEE IE header */ +typedef MLAN_PACK_START struct _IEEEtypes_Header_t +{ + /** Element ID */ + t_u8 element_id; + /** Length */ + t_u8 len; +} MLAN_PACK_END IEEEtypes_Header_t, *pIEEEtypes_Header_t; + +/** Vendor specific IE header */ +typedef MLAN_PACK_START struct _IEEEtypes_VendorHeader_t +{ + /** Element ID */ + t_u8 element_id; + /** Length */ + t_u8 len; + /** OUI */ + t_u8 oui[3]; + /** OUI type */ + t_u8 oui_type; + /** OUI subtype */ + t_u8 oui_subtype; + /** Version */ + t_u8 version; +} MLAN_PACK_END IEEEtypes_VendorHeader_t, *pIEEEtypes_VendorHeader_t; + +/** Vendor specific IE */ +typedef MLAN_PACK_START struct _IEEEtypes_VendorSpecific_t +{ + /** Vendor specific IE header */ + IEEEtypes_VendorHeader_t vend_hdr; + /** IE Max - size of previous fields */ + t_u8 data[IEEE_MAX_IE_SIZE - sizeof(IEEEtypes_VendorHeader_t)]; +} +MLAN_PACK_END IEEEtypes_VendorSpecific_t, *pIEEEtypes_VendorSpecific_t; + +/** IEEE IE */ +typedef MLAN_PACK_START struct _IEEEtypes_Generic_t +{ + /** Generic IE header */ + IEEEtypes_Header_t ieee_hdr; + /** IE Max - size of previous fields */ + t_u8 data[IEEE_MAX_IE_SIZE - sizeof(IEEEtypes_Header_t)]; +} +MLAN_PACK_END IEEEtypes_Generic_t, *pIEEEtypes_Generic_t; + +/** Capability information mask */ +#define CAPINFO_MASK (~(MBIT(15) | MBIT(14) | \ + MBIT(12) | MBIT(11) | MBIT(9))) + +/** Capability Bit Map*/ +#ifdef BIG_ENDIAN_SUPPORT +typedef MLAN_PACK_START struct _IEEEtypes_CapInfo_t +{ + t_u8 rsrvd1:2; + t_u8 dsss_ofdm:1; + t_u8 rsvrd2:2; + t_u8 short_slot_time:1; + t_u8 rsrvd3:1; + t_u8 spectrum_mgmt:1; + t_u8 chan_agility:1; + t_u8 pbcc:1; + t_u8 short_preamble:1; + t_u8 privacy:1; + t_u8 cf_poll_rqst:1; + t_u8 cf_pollable:1; + t_u8 ibss:1; + t_u8 ess:1; +} MLAN_PACK_END IEEEtypes_CapInfo_t, *pIEEEtypes_CapInfo_t; +#else +typedef MLAN_PACK_START struct _IEEEtypes_CapInfo_t +{ + /** Capability Bit Map : ESS */ + t_u8 ess:1; + /** Capability Bit Map : IBSS */ + t_u8 ibss:1; + /** Capability Bit Map : CF pollable */ + t_u8 cf_pollable:1; + /** Capability Bit Map : CF poll request */ + t_u8 cf_poll_rqst:1; + /** Capability Bit Map : privacy */ + t_u8 privacy:1; + /** Capability Bit Map : Short preamble */ + t_u8 short_preamble:1; + /** Capability Bit Map : PBCC */ + t_u8 pbcc:1; + /** Capability Bit Map : Channel agility */ + t_u8 chan_agility:1; + /** Capability Bit Map : Spectrum management */ + t_u8 spectrum_mgmt:1; + /** Capability Bit Map : Reserved */ + t_u8 rsrvd3:1; + /** Capability Bit Map : Short slot time */ + t_u8 short_slot_time:1; + /** Capability Bit Map : APSD */ + t_u8 Apsd:1; + /** Capability Bit Map : Reserved */ + t_u8 rsvrd2:1; + /** Capability Bit Map : DSS OFDM */ + t_u8 dsss_ofdm:1; + /** Capability Bit Map : Reserved */ + t_u8 rsrvd1:2; +} MLAN_PACK_END IEEEtypes_CapInfo_t, *pIEEEtypes_CapInfo_t; +#endif /* BIG_ENDIAN_SUPPORT */ + +/** IEEEtypes_CfParamSet_t */ +typedef MLAN_PACK_START struct _IEEEtypes_CfParamSet_t +{ + /** CF peremeter : Element ID */ + t_u8 element_id; + /** CF peremeter : Length */ + t_u8 len; + /** CF peremeter : Count */ + t_u8 cfp_cnt; + /** CF peremeter : Period */ + t_u8 cfp_period; + /** CF peremeter : Maximum duration */ + t_u16 cfp_max_duration; + /** CF peremeter : Remaining duration */ + t_u16 cfp_duration_remaining; +} MLAN_PACK_END IEEEtypes_CfParamSet_t, *pIEEEtypes_CfParamSet_t; + +/** IEEEtypes_IbssParamSet_t */ +typedef MLAN_PACK_START struct _IEEEtypes_IbssParamSet_t +{ + /** Element ID */ + t_u8 element_id; + /** Length */ + t_u8 len; + /** ATIM window value in milliseconds */ + t_u16 atim_window; +} MLAN_PACK_END IEEEtypes_IbssParamSet_t, *pIEEEtypes_IbssParamSet_t; + +/** IEEEtypes_SsParamSet_t */ +typedef MLAN_PACK_START union _IEEEtypes_SsParamSet_t +{ + /** SS parameter : CF parameter set */ + IEEEtypes_CfParamSet_t cf_param_set; + /** SS parameter : IBSS parameter set */ + IEEEtypes_IbssParamSet_t ibss_param_set; +} MLAN_PACK_END IEEEtypes_SsParamSet_t, *pIEEEtypes_SsParamSet_t; + +/** IEEEtypes_FhParamSet_t */ +typedef MLAN_PACK_START struct _IEEEtypes_FhParamSet_t +{ + /** FH parameter : Element ID */ + t_u8 element_id; + /** FH parameter : Length */ + t_u8 len; + /** FH parameter : Dwell time in milliseconds */ + t_u16 dwell_time; + /** FH parameter : Hop set */ + t_u8 hop_set; + /** FH parameter : Hop pattern */ + t_u8 hop_pattern; + /** FH parameter : Hop index */ + t_u8 hop_index; +} MLAN_PACK_END IEEEtypes_FhParamSet_t, *pIEEEtypes_FhParamSet_t; + +/** IEEEtypes_DsParamSet_t */ +typedef MLAN_PACK_START struct _IEEEtypes_DsParamSet_t +{ + /** DS parameter : Element ID */ + t_u8 element_id; + /** DS parameter : Length */ + t_u8 len; + /** DS parameter : Current channel */ + t_u8 current_chan; +} MLAN_PACK_END IEEEtypes_DsParamSet_t, *pIEEEtypes_DsParamSet_t; + +/** IEEEtypes_PhyParamSet_t */ +typedef MLAN_PACK_START union _IEEEtypes_PhyParamSet_t +{ + /** FH parameter set */ + IEEEtypes_FhParamSet_t fh_param_set; + /** DS parameter set */ + IEEEtypes_DsParamSet_t ds_param_set; +} MLAN_PACK_END IEEEtypes_PhyParamSet_t, *pIEEEtypes_PhyParamSet_t; + +/** IEEEtypes_ERPInfo_t */ +typedef MLAN_PACK_START struct _IEEEtypes_ERPInfo_t +{ + /** Element ID */ + t_u8 element_id; + /** Length */ + t_u8 len; + /** ERP flags */ + t_u8 erp_flags; +} MLAN_PACK_END IEEEtypes_ERPInfo_t, *pIEEEtypes_ERPInfo_t; + +/** IEEEtypes_AId_t */ +typedef t_u16 IEEEtypes_AId_t; + +/** IEEEtypes_StatusCode_t */ +typedef t_u16 IEEEtypes_StatusCode_t; + +/** IEEEtypes_AssocRsp_t */ +typedef MLAN_PACK_START struct _IEEEtypes_AssocRsp_t +{ + /** Capability information */ + IEEEtypes_CapInfo_t capability; + /** Association response status code */ + IEEEtypes_StatusCode_t status_code; + /** Association ID */ + IEEEtypes_AId_t a_id; + /** IE data buffer */ + t_u8 ie_buffer[1]; +} MLAN_PACK_END IEEEtypes_AssocRsp_t, *pIEEEtypes_AssocRsp_t; + +/** 802.11 supported rates */ +typedef t_u8 WLAN_802_11_RATES[WLAN_SUPPORTED_RATES]; + +/** cipher TKIP */ +#define WPA_CIPHER_TKIP 2 +/** cipher AES */ +#define WPA_CIPHER_AES_CCM 4 +/** AKM: 8021x */ +#define RSN_AKM_8021X 1 +/** AKM: PSK */ +#define RSN_AKM_PSK 2 + +/** wpa_suite_t */ +typedef MLAN_PACK_START struct _wpa_suite_t +{ + /** OUI */ + t_u8 oui[3]; + /** tyep */ + t_u8 type; +} MLAN_PACK_END wpa_suite, wpa_suite_mcast_t; + +/** wpa_suite_ucast_t */ +typedef MLAN_PACK_START struct +{ + /* count */ + t_u16 count; + /** wpa_suite list */ + wpa_suite list[1]; +} MLAN_PACK_END wpa_suite_ucast_t, wpa_suite_auth_key_mgmt_t; + +/** IEEEtypes_Rsn_t */ +typedef MLAN_PACK_START struct _IEEEtypes_Rsn_t +{ + /** Rsn : Element ID */ + t_u8 element_id; + /** Rsn : Length */ + t_u8 len; + /** Rsn : version */ + t_u16 version; + /** Rsn : group cipher */ + wpa_suite_mcast_t group_cipher; + /** Rsn : pairwise cipher */ + wpa_suite_ucast_t pairwise_cipher; +} MLAN_PACK_END IEEEtypes_Rsn_t, *pIEEEtypes_Rsn_t; + +/** IEEEtypes_Wpa_t */ +typedef MLAN_PACK_START struct _IEEEtypes_Wpa_t +{ + /** Wpa : Element ID */ + t_u8 element_id; + /** Wpa : Length */ + t_u8 len; + /** Wpa : oui */ + t_u8 oui[4]; + /** version */ + t_u16 version; + /** Wpa : group cipher */ + wpa_suite_mcast_t group_cipher; + /** Wpa : pairwise cipher */ + wpa_suite_ucast_t pairwise_cipher; +} MLAN_PACK_END IEEEtypes_Wpa_t, *pIEEEtypes_Wpa_t; + +/** Maximum number of AC QOS queues available in the driver/firmware */ +#define MAX_AC_QUEUES 4 + +/** Data structure of WMM QoS information */ +typedef MLAN_PACK_START struct _IEEEtypes_WmmQosInfo_t +{ +#ifdef BIG_ENDIAN_SUPPORT + /** QoS UAPSD */ + t_u8 qos_uapsd:1; + /** Reserved */ + t_u8 reserved:3; + /** Parameter set count */ + t_u8 para_set_count:4; +#else + /** Parameter set count */ + t_u8 para_set_count:4; + /** Reserved */ + t_u8 reserved:3; + /** QoS UAPSD */ + t_u8 qos_uapsd:1; +#endif /* BIG_ENDIAN_SUPPORT */ +} MLAN_PACK_END IEEEtypes_WmmQosInfo_t, *pIEEEtypes_WmmQosInfo_t; + +/** Data structure of WMM Aci/Aifsn */ +typedef MLAN_PACK_START struct _IEEEtypes_WmmAciAifsn_t +{ +#ifdef BIG_ENDIAN_SUPPORT + /** Reserved */ + t_u8 reserved:1; + /** Aci */ + t_u8 aci:2; + /** Acm */ + t_u8 acm:1; + /** Aifsn */ + t_u8 aifsn:4; +#else + /** Aifsn */ + t_u8 aifsn:4; + /** Acm */ + t_u8 acm:1; + /** Aci */ + t_u8 aci:2; + /** Reserved */ + t_u8 reserved:1; +#endif /* BIG_ENDIAN_SUPPORT */ +} MLAN_PACK_END IEEEtypes_WmmAciAifsn_t, *pIEEEtypes_WmmAciAifsn_t; + +/** Data structure of WMM ECW */ +typedef MLAN_PACK_START struct _IEEEtypes_WmmEcw_t +{ +#ifdef BIG_ENDIAN_SUPPORT + /** Maximum Ecw */ + t_u8 ecw_max:4; + /** Minimum Ecw */ + t_u8 ecw_min:4; +#else + /** Minimum Ecw */ + t_u8 ecw_min:4; + /** Maximum Ecw */ + t_u8 ecw_max:4; +#endif /* BIG_ENDIAN_SUPPORT */ +} MLAN_PACK_END IEEEtypes_WmmEcw_t, *pIEEEtypes_WmmEcw_t; + +/** Data structure of WMM AC parameters */ +typedef MLAN_PACK_START struct _IEEEtypes_WmmAcParameters_t +{ + IEEEtypes_WmmAciAifsn_t aci_aifsn; /**< AciAifSn */ + IEEEtypes_WmmEcw_t ecw; /**< Ecw */ + t_u16 tx_op_limit; /**< Tx op limit */ +} MLAN_PACK_END IEEEtypes_WmmAcParameters_t, *pIEEEtypes_WmmAcParameters_t; + +/** Data structure of WMM Info IE */ +typedef MLAN_PACK_START struct _IEEEtypes_WmmInfo_t +{ + + /** + * WMM Info IE - Vendor Specific Header: + * element_id [221/0xdd] + * Len [7] + * Oui [00:50:f2] + * OuiType [2] + * OuiSubType [0] + * Version [1] + */ + IEEEtypes_VendorHeader_t vend_hdr; + + /** QoS information */ + IEEEtypes_WmmQosInfo_t qos_info; + +} MLAN_PACK_END IEEEtypes_WmmInfo_t, *pIEEEtypes_WmmInfo_t; + +/** Data structure of WMM parameter IE */ +typedef MLAN_PACK_START struct _IEEEtypes_WmmParameter_t +{ + /** + * WMM Parameter IE - Vendor Specific Header: + * element_id [221/0xdd] + * Len [24] + * Oui [00:50:f2] + * OuiType [2] + * OuiSubType [1] + * Version [1] + */ + IEEEtypes_VendorHeader_t vend_hdr; + + /** QoS information */ + IEEEtypes_WmmQosInfo_t qos_info; + /** Reserved */ + t_u8 reserved; + + /** AC Parameters Record WMM_AC_BE, WMM_AC_BK, WMM_AC_VI, WMM_AC_VO */ + IEEEtypes_WmmAcParameters_t ac_params[MAX_AC_QUEUES]; +} MLAN_PACK_END IEEEtypes_WmmParameter_t, *pIEEEtypes_WmmParameter_t; + +/** Enumerator for TSPEC direction */ +typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_Info_Direction_e +{ + + TSPEC_DIR_UPLINK = 0, + TSPEC_DIR_DOWNLINK = 1, + /* 2 is a reserved value */ + TSPEC_DIR_BIDIRECT = 3, + +} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_Direction_e; + +/** Enumerator for TSPEC PSB */ +typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_Info_PSB_e +{ + + TSPEC_PSB_LEGACY = 0, + TSPEC_PSB_TRIG = 1, + +} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_PSB_e; + +/** Enumerator for TSPEC Ack Policy */ +typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e +{ + + TSPEC_ACKPOLICY_NORMAL = 0, + TSPEC_ACKPOLICY_NOACK = 1, + /* 2 is reserved */ + TSPEC_ACKPOLICY_BLOCKACK = 3, + +} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e; + +/** Enumerator for TSPEC Trafffice type */ +typedef MLAN_PACK_START enum _IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e +{ + + TSPEC_TRAFFIC_APERIODIC = 0, + TSPEC_TRAFFIC_PERIODIC = 1, + +} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e; + +/** Data structure of WMM TSPEC information */ +typedef MLAN_PACK_START struct +{ +#ifdef BIG_ENDIAN_SUPPORT + t_u8 Reserved17_23:7; // ! Reserved + t_u8 Schedule:1; + IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e AckPolicy:2; + t_u8 UserPri:3; // ! 802.1d User Priority + IEEEtypes_WMM_TSPEC_TS_Info_PSB_e PowerSaveBehavior:1; // ! + // Legacy/Trigg + t_u8 Aggregation:1; // ! Reserved + t_u8 AccessPolicy2:1; // ! + t_u8 AccessPolicy1:1; // ! + IEEEtypes_WMM_TSPEC_TS_Info_Direction_e Direction:2; + t_u8 TID:4; // ! Unique identifier + IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e TrafficType:1; +#else + IEEEtypes_WMM_TSPEC_TS_TRAFFIC_TYPE_e TrafficType:1; + t_u8 TID:4; // ! Unique identifier + IEEEtypes_WMM_TSPEC_TS_Info_Direction_e Direction:2; + t_u8 AccessPolicy1:1; // ! + t_u8 AccessPolicy2:1; // ! + t_u8 Aggregation:1; // ! Reserved + IEEEtypes_WMM_TSPEC_TS_Info_PSB_e PowerSaveBehavior:1; // ! + // Legacy/Trigg + t_u8 UserPri:3; // ! 802.1d User Priority + IEEEtypes_WMM_TSPEC_TS_Info_AckPolicy_e AckPolicy:2; + t_u8 Schedule:1; + t_u8 Reserved17_23:7; // ! Reserved +#endif +} MLAN_PACK_END IEEEtypes_WMM_TSPEC_TS_Info_t; + +/** Data structure of WMM TSPEC Nominal Size */ +typedef MLAN_PACK_START struct +{ +#ifdef BIG_ENDIAN_SUPPORT + t_u16 Fixed:1; // ! 1: Fixed size given in Size, 0: Var, size + // is nominal + t_u16 Size:15; // ! Nominal size in octets +#else + t_u16 Size:15; // ! Nominal size in octets + t_u16 Fixed:1; // ! 1: Fixed size given in Size, 0: Var, size + // is nominal +#endif +} MLAN_PACK_END IEEEtypes_WMM_TSPEC_NomMSDUSize_t; + +/** Data structure of WMM TSPEC SBWA */ +typedef MLAN_PACK_START struct +{ +#ifdef BIG_ENDIAN_SUPPORT + t_u16 Whole:3; // ! Whole portion + t_u16 Fractional:13; // ! Fractional portion +#else + t_u16 Fractional:13; // ! Fractional portion + t_u16 Whole:3; // ! Whole portion +#endif +} MLAN_PACK_END IEEEtypes_WMM_TSPEC_SBWA; + +/** Data structure of WMM TSPEC Body */ +typedef MLAN_PACK_START struct +{ + + IEEEtypes_WMM_TSPEC_TS_Info_t TSInfo; + IEEEtypes_WMM_TSPEC_NomMSDUSize_t NomMSDUSize; + t_u16 MaximumMSDUSize; + t_u32 MinServiceInterval; + t_u32 MaxServiceInterval; + t_u32 InactivityInterval; + t_u32 SuspensionInterval; + t_u32 ServiceStartTime; + t_u32 MinimumDataRate; + t_u32 MeanDataRate; + t_u32 PeakDataRate; + t_u32 MaxBurstSize; + t_u32 DelayBound; + t_u32 MinPHYRate; + IEEEtypes_WMM_TSPEC_SBWA SurplusBWAllowance; + t_u16 MediumTime; +} MLAN_PACK_END IEEEtypes_WMM_TSPEC_Body_t; + +/** Data structure of WMM TSPEC all elements */ +typedef MLAN_PACK_START struct +{ + t_u8 ElementId; + t_u8 Len; + t_u8 OuiType[4]; /* 00:50:f2:02 */ + t_u8 OuiSubType; /* 01 */ + t_u8 Version; + + IEEEtypes_WMM_TSPEC_Body_t TspecBody; + +} MLAN_PACK_END IEEEtypes_WMM_TSPEC_t; + +/** WMM Action Category values */ +typedef MLAN_PACK_START enum _IEEEtypes_ActionCategory_e +{ + + IEEE_MGMT_ACTION_CATEGORY_SPECTRUM_MGMT = 0, + IEEE_MGMT_ACTION_CATEGORY_QOS = 1, + IEEE_MGMT_ACTION_CATEGORY_DLS = 2, + IEEE_MGMT_ACTION_CATEGORY_BLOCK_ACK = 3, + IEEE_MGMT_ACTION_CATEGORY_PUBLIC = 4, + IEEE_MGMT_ACTION_CATEGORY_RADIO_RSRC = 5, + IEEE_MGMT_ACTION_CATEGORY_FAST_BSS_TRANS = 6, + IEEE_MGMT_ACTION_CATEGORY_HT = 7, + + IEEE_MGMT_ACTION_CATEGORY_WNM = 10, + IEEE_MGMT_ACTION_CATEGORY_UNPROTECT_WNM = 11, + + IEEE_MGMT_ACTION_CATEGORY_WMM_TSPEC = 17 +} MLAN_PACK_END IEEEtypes_ActionCategory_e; + +/** WMM TSPEC operations */ +typedef MLAN_PACK_START enum _IEEEtypes_WMM_Tspec_Action_e +{ + + TSPEC_ACTION_CODE_ADDTS_REQ = 0, + TSPEC_ACTION_CODE_ADDTS_RSP = 1, + TSPEC_ACTION_CODE_DELTS = 2, + +} MLAN_PACK_END IEEEtypes_WMM_Tspec_Action_e; + +/** WMM TSPEC Category Action Base */ +typedef MLAN_PACK_START struct +{ + + IEEEtypes_ActionCategory_e category; + IEEEtypes_WMM_Tspec_Action_e action; + t_u8 dialogToken; + +} MLAN_PACK_END IEEEtypes_WMM_Tspec_Action_Base_Tspec_t; + +/** WMM TSPEC AddTS request structure */ +typedef MLAN_PACK_START struct +{ + + IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct; + t_u8 statusCode; + IEEEtypes_WMM_TSPEC_t tspecIE; + + /* Place holder for additional elements after the TSPEC */ + t_u8 subElem[256]; + +} MLAN_PACK_END IEEEtypes_Action_WMM_AddTsReq_t; + +/** WMM TSPEC AddTS response structure */ +typedef MLAN_PACK_START struct +{ + IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct; + t_u8 statusCode; + IEEEtypes_WMM_TSPEC_t tspecIE; + + /* Place holder for additional elements after the TSPEC */ + t_u8 subElem[256]; + +} MLAN_PACK_END IEEEtypes_Action_WMM_AddTsRsp_t; + +/** WMM TSPEC DelTS structure */ +typedef MLAN_PACK_START struct +{ + IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct; + t_u8 reasonCode; + IEEEtypes_WMM_TSPEC_t tspecIE; + +} MLAN_PACK_END IEEEtypes_Action_WMM_DelTs_t; + +/** union of WMM TSPEC structures */ +typedef MLAN_PACK_START union +{ + IEEEtypes_WMM_Tspec_Action_Base_Tspec_t tspecAct; + + IEEEtypes_Action_WMM_AddTsReq_t addTsReq; + IEEEtypes_Action_WMM_AddTsRsp_t addTsRsp; + IEEEtypes_Action_WMM_DelTs_t delTs; + +} MLAN_PACK_END IEEEtypes_Action_WMMAC_t; + +/** union of WMM TSPEC & Action category */ +typedef MLAN_PACK_START union +{ + IEEEtypes_ActionCategory_e category; + + IEEEtypes_Action_WMMAC_t wmmAc; + +} MLAN_PACK_END IEEEtypes_ActionFrame_t; + +/** Data structure for subband set */ +typedef MLAN_PACK_START struct _IEEEtypes_SubbandSet_t +{ + /** First channel */ + t_u8 first_chan; + /** Number of channels */ + t_u8 no_of_chan; + /** Maximum Tx power in dBm */ + t_u8 max_tx_pwr; +} MLAN_PACK_END IEEEtypes_SubbandSet_t, *pIEEEtypes_SubbandSet_t; + +#ifdef STA_SUPPORT +/** Data structure for Country IE */ +typedef MLAN_PACK_START struct _IEEEtypes_CountryInfoSet_t +{ + /** Element ID */ + t_u8 element_id; + /** Length */ + t_u8 len; + /** Country code */ + t_u8 country_code[COUNTRY_CODE_LEN]; + /** Set of subbands */ + IEEEtypes_SubbandSet_t sub_band[1]; +} MLAN_PACK_END IEEEtypes_CountryInfoSet_t, *pIEEEtypes_CountryInfoSet_t; + +/** Data structure for Country IE full set */ +typedef MLAN_PACK_START struct _IEEEtypes_CountryInfoFullSet_t +{ + /** Element ID */ + t_u8 element_id; + /** Length */ + t_u8 len; + /** Country code */ + t_u8 country_code[COUNTRY_CODE_LEN]; + /** Set of subbands */ + IEEEtypes_SubbandSet_t sub_band[MRVDRV_MAX_SUBBAND_802_11D]; +} MLAN_PACK_END IEEEtypes_CountryInfoFullSet_t, + *pIEEEtypes_CountryInfoFullSet_t; + +#endif /* STA_SUPPORT */ + +/** HT Capabilities Data */ +typedef struct MLAN_PACK_START _HTCap_t +{ + /** HT Capabilities Info field */ + t_u16 ht_cap_info; + /** A-MPDU Parameters field */ + t_u8 ampdu_param; + /** Supported MCS Set field */ + t_u8 supported_mcs_set[16]; + /** HT Extended Capabilities field */ + t_u16 ht_ext_cap; + /** Transmit Beamforming Capabilities field */ + t_u32 tx_bf_cap; + /** Antenna Selection Capability field */ + t_u8 asel; +} MLAN_PACK_END HTCap_t, *pHTCap_t; + +/** HT Information Data */ +typedef struct MLAN_PACK_START _HTInfo_t +{ + /** Primary channel */ + t_u8 pri_chan; + /** Field 2 */ + t_u8 field2; + /** Field 3 */ + t_u16 field3; + /** Field 4 */ + t_u16 field4; + /** Bitmap indicating MCSs supported by all HT STAs in the BSS */ + t_u8 basic_mcs_set[16]; +} MLAN_PACK_END HTInfo_t, *pHTInfo_t; + +/** 20/40 BSS Coexistence Data */ +typedef struct MLAN_PACK_START _BSSCo2040_t +{ + /** 20/40 BSS Coexistence value */ + t_u8 bss_co_2040_value; +} MLAN_PACK_END BSSCo2040_t, *pBSSCo2040_t; + +/** Extended Capabilities Data */ +typedef struct MLAN_PACK_START _ExtCap_t +{ + /** Extended Capabilities value */ + t_u8 ext_cap_value; +} MLAN_PACK_END ExtCap_t, *pExtCap_t; + +/** Overlapping BSS Scan Parameters Data */ +typedef struct MLAN_PACK_START _OverlapBSSScanParam_t +{ + /** OBSS Scan Passive Dwell in milliseconds */ + t_u16 obss_scan_passive_dwell; + /** OBSS Scan Active Dwell in milliseconds */ + t_u16 obss_scan_active_dwell; + /** BSS Channel Width Trigger Scan Interval in seconds */ + t_u16 bss_chan_width_trigger_scan_int; + /** OBSS Scan Passive Total Per Channel */ + t_u16 obss_scan_passive_total; + /** OBSS Scan Active Total Per Channel */ + t_u16 obss_scan_active_total; + /** BSS Width Channel Transition Delay Factor */ + t_u16 bss_width_chan_trans_delay; + /** OBSS Scan Activity Threshold */ + t_u16 obss_scan_active_threshold; +} MLAN_PACK_END OBSSScanParam_t, *pOBSSScanParam_t; + +/** HT Capabilities IE */ +typedef MLAN_PACK_START struct _IEEEtypes_HTCap_t +{ + /** Generic IE header */ + IEEEtypes_Header_t ieee_hdr; + /** HTCap struct */ + HTCap_t ht_cap; +} MLAN_PACK_END IEEEtypes_HTCap_t, *pIEEEtypes_HTCap_t; + +/** HT Information IE */ +typedef MLAN_PACK_START struct _IEEEtypes_HTInfo_t +{ + /** Generic IE header */ + IEEEtypes_Header_t ieee_hdr; + /** HTInfo struct */ + HTInfo_t ht_info; +} MLAN_PACK_END IEEEtypes_HTInfo_t, *pIEEEtypes_HTInfo_t; + +/** 20/40 BSS Coexistence IE */ +typedef MLAN_PACK_START struct _IEEEtypes_2040BSSCo_t +{ + /** Generic IE header */ + IEEEtypes_Header_t ieee_hdr; + /** BSSCo2040_t struct */ + BSSCo2040_t bss_co_2040; +} MLAN_PACK_END IEEEtypes_2040BSSCo_t, *pIEEEtypes_2040BSSCo_t; + +/** Extended Capabilities IE */ +typedef MLAN_PACK_START struct _IEEEtypes_ExtCap_t +{ + /** Generic IE header */ + IEEEtypes_Header_t ieee_hdr; + /** ExtCap_t struct */ + ExtCap_t ext_cap; +} MLAN_PACK_END IEEEtypes_ExtCap_t, *pIEEEtypes_ExtCap_t; + +/** Overlapping BSS Scan Parameters IE */ +typedef MLAN_PACK_START struct _IEEEtypes_OverlapBSSScanParam_t +{ + /** Generic IE header */ + IEEEtypes_Header_t ieee_hdr; + /** OBSSScanParam_t struct */ + OBSSScanParam_t obss_scan_param; +} MLAN_PACK_END IEEEtypes_OverlapBSSScanParam_t, + *pIEEEtypes_OverlapBSSScanParam_t; + +/** Maximum number of subbands in the IEEEtypes_SupportedChannels_t structure */ +#define WLAN_11H_MAX_SUBBANDS 5 + +/** Maximum number of DFS channels configured in IEEEtypes_IBSS_DFS_t */ +#define WLAN_11H_MAX_IBSS_DFS_CHANNELS 25 + +/** IEEE Power Constraint element (7.3.2.15) */ +typedef MLAN_PACK_START struct +{ + t_u8 element_id; /**< IEEE Element ID = 32 */ + t_u8 len; /**< Element length after id and len */ + t_u8 local_constraint; /**< Local power constraint applied to 11d chan info */ +} MLAN_PACK_END IEEEtypes_PowerConstraint_t; + +/** IEEE Power Capability element (7.3.2.16) */ +typedef MLAN_PACK_START struct +{ + t_u8 element_id; /**< IEEE Element ID = 33 */ + t_u8 len; /**< Element length after id and len */ + t_s8 min_tx_power_capability; /**< Minimum Transmit power (dBm) */ + t_s8 max_tx_power_capability; /**< Maximum Transmit power (dBm) */ +} MLAN_PACK_END IEEEtypes_PowerCapability_t; + +/** IEEE TPC Report element (7.3.2.18) */ +typedef MLAN_PACK_START struct +{ + t_u8 element_id; /**< IEEE Element ID = 35 */ + t_u8 len; /**< Element length after id and len */ + t_s8 tx_power; /**< Max power used to transmit the TPC Report frame (dBm) */ + t_s8 link_margin; /**< Link margin when TPC Request received (dB) */ +} MLAN_PACK_END IEEEtypes_TPCReport_t; + +/* IEEE Supported Channel sub-band description (7.3.2.19) */ +/** + * Sub-band description used in the supported channels element. + */ +typedef MLAN_PACK_START struct +{ + t_u8 start_chan; /**< Starting channel in the subband */ + t_u8 num_chans; /**< Number of channels in the subband */ + +} MLAN_PACK_END IEEEtypes_SupportChan_Subband_t; + +/* IEEE Supported Channel element (7.3.2.19) */ +/** + * Sent in association requests. Details the sub-bands and number + * of channels supported in each subband + */ +typedef MLAN_PACK_START struct +{ + t_u8 element_id; /**< IEEE Element ID = 36 */ + t_u8 len; /**< Element length after id and len */ + + /** Configured sub-bands information in the element */ + IEEEtypes_SupportChan_Subband_t subband[WLAN_11H_MAX_SUBBANDS]; + +} MLAN_PACK_END IEEEtypes_SupportedChannels_t; + +/* IEEE Channel Switch Announcement Element (7.3.2.20) */ +/** + * Provided in beacons and probe responses. Used to advertise when + * and to which channel it is changing to. Only starting STAs in + * an IBSS and APs are allowed to originate a chan switch element. + */ +typedef MLAN_PACK_START struct +{ + t_u8 element_id; /**< IEEE Element ID = 37 */ + t_u8 len; /**< Element length after id and len */ + t_u8 chan_switch_mode; /**< STA should not transmit any frames if 1 */ + t_u8 new_channel_num; /**< Channel # that AP/IBSS is moving to */ + t_u8 chan_switch_count; /**< # of TBTTs before channel switch */ + +} MLAN_PACK_END IEEEtypes_ChanSwitchAnn_t; + +/* IEEE Quiet Period Element (7.3.2.23) */ +/** + * Provided in beacons and probe responses. Indicates times during + * which the STA should not be transmitting data. Only starting STAs in + * an IBSS and APs are allowed to originate a quiet element. + */ +typedef MLAN_PACK_START struct +{ + t_u8 element_id; /**< IEEE Element ID = 40 */ + t_u8 len; /**< Element length after id and len */ + t_u8 quiet_count; /**< Number of TBTTs until beacon with the quiet period */ + t_u8 quiet_period; /**< Regular quiet period, # of TBTTS between periods */ + t_u16 quiet_duration; /**< Duration of the quiet period in TUs */ + t_u16 quiet_offset; /**< Offset in TUs from the TBTT for the quiet period */ + +} MLAN_PACK_END IEEEtypes_Quiet_t; + +/** +*** @brief Map octet of the basic measurement report (7.3.2.22.1) +**/ +typedef MLAN_PACK_START struct +{ +#ifdef BIG_ENDIAN_SUPPORT + t_u8 rsvd5_7:3; /**< Reserved */ + t_u8 unmeasured:1; /**< Channel is unmeasured */ + t_u8 radar:1; /**< Radar detected on channel */ + t_u8 unidentified_sig:1; /**< Unidentified signal found on channel */ + t_u8 ofdm_preamble:1; /**< OFDM preamble detected on channel */ + t_u8 bss:1; /**< At least one valid MPDU received on channel */ +#else + t_u8 bss:1; /**< At least one valid MPDU received on channel */ + t_u8 ofdm_preamble:1; /**< OFDM preamble detected on channel */ + t_u8 unidentified_sig:1; /**< Unidentified signal found on channel */ + t_u8 radar:1; /**< Radar detected on channel */ + t_u8 unmeasured:1; /**< Channel is unmeasured */ + t_u8 rsvd5_7:3; /**< Reserved */ +#endif /* BIG_ENDIAN_SUPPORT */ + +} MLAN_PACK_END MeasRptBasicMap_t; + +/* IEEE DFS Channel Map field (7.3.2.24) */ +/** + * Used to list supported channels and provide a octet "map" field which + * contains a basic measurement report for that channel in the + * IEEEtypes_IBSS_DFS_t element + */ +typedef MLAN_PACK_START struct +{ + t_u8 channel_number; /**< Channel number */ + MeasRptBasicMap_t rpt_map; /**< Basic measurement report for the channel */ + +} MLAN_PACK_END IEEEtypes_ChannelMap_t; + +/* IEEE IBSS DFS Element (7.3.2.24) */ +/** + * IBSS DFS element included in ad hoc beacons and probe responses. + * Provides information regarding the IBSS DFS Owner as well as the + * originating STAs supported channels and basic measurement results. + */ +typedef MLAN_PACK_START struct +{ + t_u8 element_id; /**< IEEE Element ID = 41 */ + t_u8 len; /**< Element length after id and len */ + t_u8 dfs_owner[MLAN_MAC_ADDR_LENGTH]; /**< DFS Owner STA Address */ + t_u8 dfs_recovery_interval; /**< DFS Recovery time in TBTTs */ + + /** Variable length map field, one Map entry for each supported channel */ + IEEEtypes_ChannelMap_t channel_map[WLAN_11H_MAX_IBSS_DFS_CHANNELS]; + +} MLAN_PACK_END IEEEtypes_IBSS_DFS_t; + +/* 802.11h BSS information kept for each BSSID received in scan results */ +/** + * IEEE BSS information needed from scan results for later processing in + * join commands + */ +typedef struct +{ + t_u8 sensed_11h; /**< Capability bit set or 11h IE found in this BSS */ + + IEEEtypes_PowerConstraint_t power_constraint; /**< Power Constraint IE */ + IEEEtypes_PowerCapability_t power_capability; /**< Power Capability IE */ + IEEEtypes_TPCReport_t tpc_report; /**< TPC Report IE */ + IEEEtypes_ChanSwitchAnn_t chan_switch_ann; /**< Channel Switch Announcement IE */ + IEEEtypes_Quiet_t quiet; /**< Quiet IE */ + IEEEtypes_IBSS_DFS_t ibss_dfs; /**< IBSS DFS Element IE */ + +} wlan_11h_bss_info_t; + +#ifdef STA_SUPPORT +/** Macro for maximum size of scan response buffer */ +#define MAX_SCAN_RSP_BUF (16 * 1024) + +/** Maximum number of channels that can be sent in user scan config */ +#define WLAN_USER_SCAN_CHAN_MAX 50 + +/** Maximum length of SSID list */ +#define MRVDRV_MAX_SSID_LIST_LENGTH 10 + +/** Scan all the channels in specified band */ +#define BAND_SPECIFIED 0x80 + +/** + * IOCTL SSID List sub-structure sent in wlan_ioctl_user_scan_cfg + * + * Used to specify SSID specific filters as well as SSID pattern matching + * filters for scan result processing in firmware. + */ +typedef MLAN_PACK_START struct _wlan_user_scan_ssid +{ + /** SSID */ + t_u8 ssid[MLAN_MAX_SSID_LENGTH + 1]; + /** Maximum length of SSID */ + t_u8 max_len; +} MLAN_PACK_END wlan_user_scan_ssid; + +/** + * @brief IOCTL channel sub-structure sent in wlan_ioctl_user_scan_cfg + * + * Multiple instances of this structure are included in the IOCTL command + * to configure a instance of a scan on the specific channel. + */ +typedef MLAN_PACK_START struct _wlan_user_scan_chan +{ + /** Channel Number to scan */ + t_u8 chan_number; + /** Radio type: 'B/G' Band = 0, 'A' Band = 1 */ + t_u8 radio_type; + /** Scan type: Active = 1, Passive = 2 */ + t_u8 scan_type; + /** Reserved */ + t_u8 reserved; + /** Scan duration in milliseconds; if 0 default used */ + t_u32 scan_time; +} MLAN_PACK_END wlan_user_scan_chan; + +/** + * Input structure to configure an immediate scan cmd to firmware + * + * Specifies a number of parameters to be used in general for the scan + * as well as a channel list (wlan_user_scan_chan) for each scan period + * desired. + */ +typedef MLAN_PACK_START struct +{ + /** + * Flag set to keep the previous scan table intact + * + * If set, the scan results will accumulate, replacing any previous + * matched entries for a BSS with the new scan data + */ + t_u8 keep_previous_scan; + /** + * BSS mode to be sent in the firmware command + * + * Field can be used to restrict the types of networks returned in the + * scan. Valid settings are: + * + * - MLAN_SCAN_MODE_BSS (infrastructure) + * - MLAN_SCAN_MODE_IBSS (adhoc) + * - MLAN_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure) + */ + t_u8 bss_mode; + /** + * Configure the number of probe requests for active chan scans + */ + t_u8 num_probes; + /** + * @brief Reserved + */ + t_u8 reserved; + /** + * @brief BSSID filter sent in the firmware command to limit the results + */ + t_u8 specific_bssid[MLAN_MAC_ADDR_LENGTH]; + /** + * SSID filter list used in the to limit the scan results + */ + wlan_user_scan_ssid ssid_list[MRVDRV_MAX_SSID_LIST_LENGTH]; + /** + * Variable number (fixed maximum) of channels to scan up + */ + wlan_user_scan_chan chan_list[WLAN_USER_SCAN_CHAN_MAX]; +} MLAN_PACK_END wlan_user_scan_cfg; + +/** Default scan interval in millisecond*/ +#define DEFAULT_BGSCAN_INTERVAL 30000 + +/** action get all, except pps/uapsd config */ +#define BG_SCAN_ACT_GET 0x0000 +/** action set all, except pps/uapsd config */ +#define BG_SCAN_ACT_SET 0x0001 +/** action get pps/uapsd config */ +#define BG_SCAN_ACT_GET_PPS_UAPSD 0x0100 +/** action set pps/uapsd config */ +#define BG_SCAN_ACT_SET_PPS_UAPSD 0x0101 +/** action set all */ +#define BG_SCAN_ACT_SET_ALL 0xff01 +/** ssid match */ +#define BG_SCAN_SSID_MATCH 0x0001 +/** ssid match and RSSI exceeded */ +#define BG_SCAN_SSID_RSSI_MATCH 0x0004 +/** Maximum number of channels that can be sent in bg scan config */ +#define WLAN_BG_SCAN_CHAN_MAX 32 + +/** + * Input structure to configure bs scan cmd to firmware + */ +typedef MLAN_PACK_START struct +{ + /** action */ + t_u16 action; + /** enable/disable */ + t_u8 enable; + /** BSS type: + * MLAN_SCAN_MODE_BSS (infrastructure) + * MLAN_SCAN_MODE_IBSS (adhoc) + * MLAN_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure) + */ + t_u8 bss_type; + /** number of channel scanned during each scan */ + t_u8 chan_per_scan; + /** interval between consecutive scan */ + t_u32 scan_interval; + /** bit 0: ssid match bit 1: ssid match and SNR exceeded + * bit 2: ssid match and RSSI exceeded + * bit 31: wait for all channel scan to complete to report scan result + */ + t_u32 report_condition; + /* Configure the number of probe requests for active chan scans */ + t_u8 num_probes; + /** RSSI threshold */ + t_u8 rssi_threshold; + /** SNR threshold */ + t_u8 snr_threshold; + /** repeat count */ + t_u16 repeat_count; + /** SSID filter list used in the to limit the scan results */ + wlan_user_scan_ssid ssid_list[MRVDRV_MAX_SSID_LIST_LENGTH]; + /** Variable number (fixed maximum) of channels to scan up */ + wlan_user_scan_chan chan_list[WLAN_BG_SCAN_CHAN_MAX]; +} MLAN_PACK_END wlan_bgscan_cfg; +#endif /* STA_SUPPORT */ + +#ifdef PRAGMA_PACK +#pragma pack(pop) +#endif + +/** BSSDescriptor_t + * Structure used to store information for beacon/probe response + */ +typedef struct _BSSDescriptor_t +{ + /** MAC address */ + mlan_802_11_mac_addr mac_address; + + /** SSID */ + mlan_802_11_ssid ssid; + + /** WEP encryption requirement */ + t_u32 privacy; + + /** Receive signal strength in dBm */ + t_s32 rssi; + + /** Channel */ + t_u32 channel; + + /** Freq */ + t_u32 freq; + + /** Beacon period */ + t_u16 beacon_period; + + /** ATIM window */ + t_u32 atim_window; + + /** ERP flags */ + t_u8 erp_flags; + + /** Type of network in use */ + WLAN_802_11_NETWORK_TYPE network_type_use; + + /** Network infrastructure mode */ + t_u32 bss_mode; + + /** Network supported rates */ + WLAN_802_11_RATES supported_rates; + + /** Supported data rates */ + t_u8 data_rates[WLAN_SUPPORTED_RATES]; + + /** Network band. + * BAND_B(0x01): 'b' band + * BAND_G(0x02): 'g' band + * BAND_A(0X04): 'a' band + */ + t_u16 bss_band; + + /** TSF timestamp from the current firmware TSF */ + t_u64 network_tsf; + + /** TSF value included in the beacon/probe response */ + t_u8 time_stamp[8]; + + /** PHY parameter set */ + IEEEtypes_PhyParamSet_t phy_param_set; + + /** SS parameter set */ + IEEEtypes_SsParamSet_t ss_param_set; + + /** Capability information */ + IEEEtypes_CapInfo_t cap_info; + + /** WMM IE */ + IEEEtypes_WmmParameter_t wmm_ie; + + /** 802.11h BSS information */ + wlan_11h_bss_info_t wlan_11h_bss_info; + + /** Indicate disabling 11n when associate with AP */ + t_u8 disable_11n; + /** 802.11n BSS information */ + /** HT Capabilities IE */ + IEEEtypes_HTCap_t *pht_cap; + /** HT Capabilities Offset */ + t_u16 ht_cap_offset; + /** HT Information IE */ + IEEEtypes_HTInfo_t *pht_info; + /** HT Information Offset */ + t_u16 ht_info_offset; + /** 20/40 BSS Coexistence IE */ + IEEEtypes_2040BSSCo_t *pbss_co_2040; + /** 20/40 BSS Coexistence Offset */ + t_u16 bss_co_2040_offset; + /** Extended Capabilities IE */ + IEEEtypes_ExtCap_t *pext_cap; + /** Extended Capabilities Offset */ + t_u16 ext_cap_offset; + /** Overlapping BSS Scan Parameters IE */ + IEEEtypes_OverlapBSSScanParam_t *poverlap_bss_scan_param; + /** Overlapping BSS Scan Parameters Offset */ + t_u16 overlap_bss_offset; + +#ifdef STA_SUPPORT + /** Country information set */ + IEEEtypes_CountryInfoFullSet_t country_info; +#endif /* STA_SUPPORT */ + + /** WPA IE */ + IEEEtypes_VendorSpecific_t *pwpa_ie; + /** WPA IE offset in the beacon buffer */ + t_u16 wpa_offset; + /** RSN IE */ + IEEEtypes_Generic_t *prsn_ie; + /** RSN IE offset in the beacon buffer */ + t_u16 rsn_offset; +#ifdef STA_SUPPORT + /** WAPI IE */ + IEEEtypes_Generic_t *pwapi_ie; + /** WAPI IE offset in the beacon buffer */ + t_u16 wapi_offset; +#endif + + /** Pointer to the returned scan response */ + t_u8 *pbeacon_buf; + /** Length of the stored scan response */ + t_u32 beacon_buf_size; + /** Max allocated size for updated scan response */ + t_u32 beacon_buf_size_max; + +} BSSDescriptor_t, *pBSSDescriptor_t; + +#endif /* !_MLAN_IEEE_H_ */ diff --git a/drivers/net/wireless/sd8797/mlinux/mlan_ioctl.h b/drivers/net/wireless/sd8797/mlinux/mlan_ioctl.h new file mode 100644 index 000000000000..964de9197ffe --- /dev/null +++ b/drivers/net/wireless/sd8797/mlinux/mlan_ioctl.h @@ -0,0 +1,2981 @@ +/** @file mlan_ioctl.h + * + * @brief This file declares the IOCTL data structures and APIs. + * + * Copyright (C) 2008-2011, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +/****************************************************** +Change log: + 11/07/2008: initial version +******************************************************/ + +#ifndef _MLAN_IOCTL_H_ +#define _MLAN_IOCTL_H_ + +/** Enumeration for IOCTL request ID */ +enum _mlan_ioctl_req_id +{ + /* Scan Group */ + MLAN_IOCTL_SCAN = 0x00010000, + MLAN_OID_SCAN_NORMAL, + MLAN_OID_SCAN_SPECIFIC_SSID, + MLAN_OID_SCAN_USER_CONFIG, + MLAN_OID_SCAN_CONFIG, + MLAN_OID_SCAN_GET_CURRENT_BSS, + MLAN_OID_SCAN_CANCEL, + MLAN_OID_SCAN_TABLE_FLUSH, + MLAN_OID_SCAN_BGSCAN_CONFIG, + /* BSS Configuration Group */ + MLAN_IOCTL_BSS = 0x00020000, + MLAN_OID_BSS_START, + MLAN_OID_BSS_STOP, + MLAN_OID_BSS_MODE, + MLAN_OID_BSS_CHANNEL, + MLAN_OID_BSS_CHANNEL_LIST, + MLAN_OID_BSS_MAC_ADDR, + MLAN_OID_BSS_MULTICAST_LIST, + MLAN_OID_BSS_FIND_BSS, + MLAN_OID_IBSS_BCN_INTERVAL, + MLAN_OID_IBSS_ATIM_WINDOW, + MLAN_OID_IBSS_CHANNEL, +#ifdef UAP_SUPPORT + MLAN_OID_UAP_BSS_CONFIG, + MLAN_OID_UAP_DEAUTH_STA, + MLAN_OID_UAP_BSS_RESET, +#endif +#if defined(STA_SUPPORT) && defined(UAP_SUPPORT) + MLAN_OID_BSS_ROLE, +#endif +#ifdef WIFI_DIRECT_SUPPORT + MLAN_OID_WIFI_DIRECT_MODE, +#endif + + /* Radio Configuration Group */ + MLAN_IOCTL_RADIO_CFG = 0x00030000, + MLAN_OID_RADIO_CTRL, + MLAN_OID_BAND_CFG, + MLAN_OID_ANT_CFG, +#ifdef WIFI_DIRECT_SUPPORT + MLAN_OID_REMAIN_CHAN_CFG, +#endif + + /* SNMP MIB Group */ + MLAN_IOCTL_SNMP_MIB = 0x00040000, + MLAN_OID_SNMP_MIB_RTS_THRESHOLD, + MLAN_OID_SNMP_MIB_FRAG_THRESHOLD, + MLAN_OID_SNMP_MIB_RETRY_COUNT, +#if defined(UAP_SUPPORT) + MLAN_OID_SNMP_MIB_DOT11D, + MLAN_OID_SNMP_MIB_DOT11H, +#endif + MLAN_OID_SNMP_MIB_DTIM_PERIOD, + + /* Status Information Group */ + MLAN_IOCTL_GET_INFO = 0x00050000, + MLAN_OID_GET_STATS, + MLAN_OID_GET_SIGNAL, + MLAN_OID_GET_FW_INFO, + MLAN_OID_GET_VER_EXT, + MLAN_OID_GET_BSS_INFO, + MLAN_OID_GET_DEBUG_INFO, +#ifdef UAP_SUPPORT + MLAN_OID_UAP_STA_LIST, +#endif + + /* Security Configuration Group */ + MLAN_IOCTL_SEC_CFG = 0x00060000, + MLAN_OID_SEC_CFG_AUTH_MODE, + MLAN_OID_SEC_CFG_ENCRYPT_MODE, + MLAN_OID_SEC_CFG_WPA_ENABLED, + MLAN_OID_SEC_CFG_ENCRYPT_KEY, + MLAN_OID_SEC_CFG_PASSPHRASE, + MLAN_OID_SEC_CFG_EWPA_ENABLED, + MLAN_OID_SEC_CFG_ESUPP_MODE, + MLAN_OID_SEC_CFG_WAPI_ENABLED, + MLAN_OID_SEC_CFG_PORT_CTRL_ENABLED, + + /* Rate Group */ + MLAN_IOCTL_RATE = 0x00070000, + MLAN_OID_RATE_CFG, + MLAN_OID_GET_DATA_RATE, + MLAN_OID_SUPPORTED_RATES, + + /* Power Configuration Group */ + MLAN_IOCTL_POWER_CFG = 0x00080000, + MLAN_OID_POWER_CFG, + MLAN_OID_POWER_CFG_EXT, + + /* Power Management Configuration Group */ + MLAN_IOCTL_PM_CFG = 0x00090000, + MLAN_OID_PM_CFG_IEEE_PS, + MLAN_OID_PM_CFG_HS_CFG, + MLAN_OID_PM_CFG_INACTIVITY_TO, + MLAN_OID_PM_CFG_DEEP_SLEEP, + MLAN_OID_PM_CFG_SLEEP_PD, + MLAN_OID_PM_CFG_PS_CFG, + MLAN_OID_PM_CFG_SLEEP_PARAMS, +#ifdef UAP_SUPPORT + MLAN_OID_PM_CFG_PS_MODE, +#endif /* UAP_SUPPORT */ + MLAN_OID_PM_INFO, + + /* WMM Configuration Group */ + MLAN_IOCTL_WMM_CFG = 0x000A0000, + MLAN_OID_WMM_CFG_ENABLE, + MLAN_OID_WMM_CFG_QOS, + MLAN_OID_WMM_CFG_ADDTS, + MLAN_OID_WMM_CFG_DELTS, + MLAN_OID_WMM_CFG_QUEUE_CONFIG, + MLAN_OID_WMM_CFG_QUEUE_STATS, + MLAN_OID_WMM_CFG_QUEUE_STATUS, + MLAN_OID_WMM_CFG_TS_STATUS, + + /* WPS Configuration Group */ + MLAN_IOCTL_WPS_CFG = 0x000B0000, + MLAN_OID_WPS_CFG_SESSION, + + /* 802.11n Configuration Group */ + MLAN_IOCTL_11N_CFG = 0x000C0000, + MLAN_OID_11N_CFG_TX, + MLAN_OID_11N_HTCAP_CFG, + MLAN_OID_11N_CFG_ADDBA_REJECT, + MLAN_OID_11N_CFG_AGGR_PRIO_TBL, + MLAN_OID_11N_CFG_ADDBA_PARAM, + MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE, + MLAN_OID_11N_CFG_AMSDU_AGGR_CTRL, + MLAN_OID_11N_CFG_SUPPORTED_MCS_SET, + MLAN_OID_11N_CFG_TX_BF_CAP, + MLAN_OID_11N_CFG_TX_BF_CFG, + MLAN_OID_11N_CFG_STREAM_CFG, + + /* 802.11d Configuration Group */ + MLAN_IOCTL_11D_CFG = 0x000D0000, +#ifdef STA_SUPPORT + MLAN_OID_11D_CFG_ENABLE, + MLAN_OID_11D_CLR_CHAN_TABLE, +#endif /* STA_SUPPORT */ + MLAN_OID_11D_DOMAIN_INFO, + + /* Register Memory Access Group */ + MLAN_IOCTL_REG_MEM = 0x000E0000, + MLAN_OID_REG_RW, + MLAN_OID_EEPROM_RD, + MLAN_OID_MEM_RW, + + /* Multi-Radio Configuration Group */ + MLAN_IOCTL_MFR_CFG = 0x00100000, + + /* 802.11h Configuration Group */ + MLAN_IOCTL_11H_CFG = 0x00110000, + MLAN_OID_11H_CHANNEL_CHECK, + MLAN_OID_11H_LOCAL_POWER_CONSTRAINT, +#if defined(DFS_TESTING_SUPPORT) + MLAN_OID_11H_DFS_TESTING, +#endif + + /* Miscellaneous Configuration Group */ + MLAN_IOCTL_MISC_CFG = 0x00200000, + MLAN_OID_MISC_GEN_IE, + MLAN_OID_MISC_REGION, + MLAN_OID_MISC_WARM_RESET, +#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR) + MLAN_OID_MISC_SDIO_MPA_CTRL, +#endif + MLAN_OID_MISC_HOST_CMD, + MLAN_OID_MISC_SYS_CLOCK, + MLAN_OID_MISC_SOFT_RESET, + MLAN_OID_MISC_WWS, + MLAN_OID_MISC_INIT_SHUTDOWN, + MLAN_OID_MISC_CUSTOM_IE, + MLAN_OID_MISC_TX_DATAPAUSE, + MLAN_OID_MISC_IP_ADDR, + MLAN_OID_MISC_MAC_CONTROL, + MLAN_OID_MISC_MEF_CFG, + MLAN_OID_MISC_CFP_CODE, + MLAN_OID_MISC_COUNTRY_CODE, + MLAN_OID_MISC_THERMAL, + MLAN_OID_MISC_RX_MGMT_IND, + MLAN_OID_MISC_SUBSCRIBE_EVENT, +#ifdef DEBUG_LEVEL1 + MLAN_OID_MISC_DRVDBG, +#endif + MLAN_OID_MISC_OTP_USER_DATA, +}; + +/** Sub command size */ +#define MLAN_SUB_COMMAND_SIZE 4 + +/** Enumeration for the action of IOCTL request */ +enum _mlan_act_ioctl +{ + MLAN_ACT_SET = 1, + MLAN_ACT_GET, + MLAN_ACT_CANCEL +}; + +/** Enumeration for generic enable/disable */ +enum _mlan_act_generic +{ + MLAN_ACT_DISABLE = 0, + MLAN_ACT_ENABLE = 1 +}; + +/** Enumeration for scan mode */ +enum _mlan_scan_mode +{ + MLAN_SCAN_MODE_UNCHANGED = 0, + MLAN_SCAN_MODE_BSS, + MLAN_SCAN_MODE_IBSS, + MLAN_SCAN_MODE_ANY +}; + +/** Enumeration for scan type */ +enum _mlan_scan_type +{ + MLAN_SCAN_TYPE_UNCHANGED = 0, + MLAN_SCAN_TYPE_ACTIVE, + MLAN_SCAN_TYPE_PASSIVE +}; + +/** Max number of supported rates */ +#define MLAN_SUPPORTED_RATES 32 + +/** RSSI scan */ +#define SCAN_RSSI(RSSI) (0x100 - ((t_u8)(RSSI))) + +/** Max passive scan time for each channel in milliseconds */ +#define MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME 2000 + +/** Max active scan time for each channel in milliseconds */ +#define MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME 500 + +/** Maximum number of probes to send on each channel */ +#define MAX_PROBES 4 + +/** Default number of probes to send on each channel */ +#define DEFAULT_PROBES 4 + +/** + * @brief Sub-structure passed in wlan_ioctl_get_scan_table_entry for each BSS + * + * Fixed field information returned for the scan response in the IOCTL + * response. + */ +typedef struct _wlan_get_scan_table_fixed +{ + /** BSSID of this network */ + t_u8 bssid[MLAN_MAC_ADDR_LENGTH]; + /** Channel this beacon/probe response was detected */ + t_u8 channel; + /** RSSI for the received packet */ + t_u8 rssi; + /** TSF value in microseconds from the firmware at packet reception */ + t_u64 network_tsf; +} wlan_get_scan_table_fixed; + +/** mlan_802_11_ssid data structure */ +typedef struct _mlan_802_11_ssid +{ + /** SSID Length */ + t_u32 ssid_len; + /** SSID information field */ + t_u8 ssid[MLAN_MAX_SSID_LENGTH]; +} mlan_802_11_ssid, *pmlan_802_11_ssid; + +/** + * Sructure to retrieve the scan table + */ +typedef struct +{ + /** + * - Zero based scan entry to start retrieval in command request + * - Number of scans entries returned in command response + */ + t_u32 scan_number; + /** + * Buffer marker for multiple wlan_ioctl_get_scan_table_entry structures. + * Each struct is padded to the nearest 32 bit boundary. + */ + t_u8 scan_table_entry_buf[1]; +} wlan_ioctl_get_scan_table_info; + +/** + * Structure passed in the wlan_ioctl_get_scan_table_info for each + * BSS returned in the WLAN_GET_SCAN_RESP IOCTL + */ +typedef struct _wlan_ioctl_get_scan_table_entry +{ + /** + * Fixed field length included in the response. + * + * Length value is included so future fixed fields can be added to the + * response without breaking backwards compatibility. Use the length + * to find the offset for the bssInfoLength field, not a sizeof() calc. + */ + t_u32 fixed_field_length; + + /** + * Length of the BSS Information (probe resp or beacon) that + * follows after the fixed_field_length + */ + t_u32 bss_info_length; + + /** + * Always present, fixed length data fields for the BSS + */ + wlan_get_scan_table_fixed fixed_fields; + + /* + * Probe response or beacon scanned for the BSS. + * + * Field layout: + * - TSF 8 octets + * - Beacon Interval 2 octets + * - Capability Info 2 octets + * + * - IEEE Infomation Elements; variable number & length per 802.11 spec + */ + /* t_u8 bss_info_buffer[0]; */ +} wlan_ioctl_get_scan_table_entry; + +/** Type definition of mlan_scan_time_params */ +typedef struct _mlan_scan_time_params +{ + /** Scan channel time for specific scan in milliseconds */ + t_u32 specific_scan_time; + /** Scan channel time for active scan in milliseconds */ + t_u32 active_scan_time; + /** Scan channel time for passive scan in milliseconds */ + t_u32 passive_scan_time; +} mlan_scan_time_params, *pmlan_scan_time_params; + +/** Type definition of mlan_user_scan */ +typedef struct _mlan_user_scan +{ + /** Length of scan_cfg_buf */ + t_u32 scan_cfg_len; + /** Buffer of scan config */ + t_u8 scan_cfg_buf[1]; +} mlan_user_scan, *pmlan_user_scan; + +/** Type definition of mlan_scan_req */ +typedef struct _mlan_scan_req +{ + /** BSS mode for scanning */ + t_u32 scan_mode; + /** Scan type */ + t_u32 scan_type; + /** SSID */ + mlan_802_11_ssid scan_ssid; + /** Scan time parameters */ + mlan_scan_time_params scan_time; + /** Scan config parameters in user scan */ + mlan_user_scan user_scan; +} mlan_scan_req, *pmlan_scan_req; + +/** Type defnition of mlan_scan_resp */ +typedef struct _mlan_scan_resp +{ + /** Number of scan result */ + t_u32 num_in_scan_table; + /** Scan table */ + t_u8 *pscan_table; + /* Age in seconds */ + t_u32 age_in_secs; +} mlan_scan_resp, *pmlan_scan_resp; + +/** Type definition of mlan_scan_cfg */ +typedef struct _mlan_scan_cfg +{ + /** Scan type */ + t_u32 scan_type; + /** BSS mode for scanning */ + t_u32 scan_mode; + /** Scan probe */ + t_u32 scan_probe; + /** Scan time parameters */ + mlan_scan_time_params scan_time; + /** Extended Scan */ + t_u32 ext_scan; +} mlan_scan_cfg, *pmlan_scan_cfg; + +/** Type defnition of mlan_ds_scan for MLAN_IOCTL_SCAN */ +typedef struct _mlan_ds_scan +{ + /** Sub-command */ + t_u32 sub_command; + /** Scan request/response */ + union + { + /** Scan request */ + mlan_scan_req scan_req; + /** Scan response */ + mlan_scan_resp scan_resp; + /** Scan config parameters in user scan */ + mlan_user_scan user_scan; + /** Scan config parameters */ + mlan_scan_cfg scan_cfg; + } param; +} mlan_ds_scan, *pmlan_ds_scan; + +/*-----------------------------------------------------------------*/ +/** BSS Configuration Group */ +/*-----------------------------------------------------------------*/ +/** Enumeration for BSS mode */ +enum _mlan_bss_mode +{ + MLAN_BSS_MODE_INFRA = 1, + MLAN_BSS_MODE_IBSS, + MLAN_BSS_MODE_AUTO +}; + +/** Maximum key length */ +#define MLAN_MAX_KEY_LENGTH 32 + +/** max Wmm AC queues */ +#define MAX_AC_QUEUES 4 + +/** Maximum atim window in milliseconds */ +#define MLAN_MAX_ATIM_WINDOW 50 + +/** Minimum beacon interval */ +#define MLAN_MIN_BEACON_INTERVAL 20 +/** Maximum beacon interval */ +#define MLAN_MAX_BEACON_INTERVAL 1000 +/** Default beacon interval */ +#define MLAN_BEACON_INTERVAL 100 + +/** Receive all packets */ +#define MLAN_PROMISC_MODE 1 +/** Receive multicast packets in multicast list */ +#define MLAN_MULTICAST_MODE 2 +/** Receive all multicast packets */ +#define MLAN_ALL_MULTI_MODE 4 + +/** Maximum size of multicast list */ +#define MLAN_MAX_MULTICAST_LIST_SIZE 32 + +/** mlan_multicast_list data structure for MLAN_OID_BSS_MULTICAST_LIST */ +typedef struct _mlan_multicast_list +{ + /** Multicast mode */ + t_u32 mode; + /** Number of multicast addresses in the list */ + t_u32 num_multicast_addr; + /** Multicast address list */ + mlan_802_11_mac_addr mac_list[MLAN_MAX_MULTICAST_LIST_SIZE]; +} mlan_multicast_list, *pmlan_multicast_list; + +/** Max channel */ +#define MLAN_MAX_CHANNEL 165 + +/** Maximum number of channels in table */ +#define MLAN_MAX_CHANNEL_NUM 128 + +/** Channel/frequence for MLAN_OID_BSS_CHANNEL */ +typedef struct _chan_freq +{ + /** Channel Number */ + t_u32 channel; + /** Frequency of this Channel */ + t_u32 freq; +} chan_freq; + +/** mlan_chan_list data structure for MLAN_OID_BSS_CHANNEL_LIST */ +typedef struct _mlan_chan_list +{ + /** Number of channel */ + t_u32 num_of_chan; + /** Channel-Frequency table */ + chan_freq cf[MLAN_MAX_CHANNEL_NUM]; +} mlan_chan_list; + +/** mlan_ssid_bssid data structure for MLAN_OID_BSS_START and MLAN_OID_BSS_FIND_BSS */ +typedef struct _mlan_ssid_bssid +{ + /** SSID */ + mlan_802_11_ssid ssid; + /** BSSID */ + mlan_802_11_mac_addr bssid; + /** index in BSSID list, start from 1 */ + t_u32 idx; +} mlan_ssid_bssid; + +#ifdef UAP_SUPPORT +/** Maximum packet forward control value */ +#define MAX_PKT_FWD_CTRL 15 +/** Maximum BEACON period */ +#define MAX_BEACON_PERIOD 4000 +/** Minimum BEACON period */ +#define MIN_BEACON_PERIOD 50 +/** Maximum DTIM period */ +#define MAX_DTIM_PERIOD 100 +/** Minimum DTIM period */ +#define MIN_DTIM_PERIOD 1 +/** Maximum TX Power Limit */ +#define MAX_TX_POWER 20 +/** Minimum TX Power Limit */ +#define MIN_TX_POWER 0 +/** MAX station count */ +#define MAX_STA_COUNT 10 +/** Maximum RTS threshold */ +#define MAX_RTS_THRESHOLD 2347 +/** Maximum fragmentation threshold */ +#define MAX_FRAG_THRESHOLD 2346 +/** Minimum fragmentation threshold */ +#define MIN_FRAG_THRESHOLD 256 +/** data rate 54 M */ +#define DATA_RATE_54M 108 +/** antenna A */ +#define ANTENNA_MODE_A 0 +/** antenna B */ +#define ANTENNA_MODE_B 1 +/** transmit antenna */ +#define TX_ANTENNA 1 +/** receive antenna */ +#define RX_ANTENNA 0 +/** Maximum stage out time */ +#define MAX_STAGE_OUT_TIME 864000 +/** Minimum stage out time */ +#define MIN_STAGE_OUT_TIME 300 +/** Maximum Retry Limit */ +#define MAX_RETRY_LIMIT 14 + +/** Maximum group key timer in seconds */ +#define MAX_GRP_TIMER 86400 + +/** Maximum value of 4 byte configuration */ +#define MAX_VALID_DWORD 0x7FFFFFFF /* (1 << 31) - 1 */ + +/** Band config ACS mode */ +#define BAND_CONFIG_ACS_MODE 0x40 +/** Band config manual */ +#define BAND_CONFIG_MANUAL 0x00 + +/** Maximum data rates */ +#define MAX_DATA_RATES 14 + +/** auto data rate */ +#define DATA_RATE_AUTO 0 + +/**filter mode: disable */ +#define MAC_FILTER_MODE_DISABLE 0 +/**filter mode: block mac address */ +#define MAC_FILTER_MODE_ALLOW_MAC 1 +/**filter mode: block mac address */ +#define MAC_FILTER_MODE_BLOCK_MAC 2 +/** Maximum mac filter num */ +#define MAX_MAC_FILTER_NUM 16 + +/* Bitmap for protocol to use */ +/** No security */ +#define PROTOCOL_NO_SECURITY 0x01 +/** Static WEP */ +#define PROTOCOL_STATIC_WEP 0x02 +/** WPA */ +#define PROTOCOL_WPA 0x08 +/** WPA2 */ +#define PROTOCOL_WPA2 0x20 +/** WP2 Mixed */ +#define PROTOCOL_WPA2_MIXED 0x28 +/** EAP */ +#define PROTOCOL_EAP 0x40 +/** WAPI */ +#define PROTOCOL_WAPI 0x80 + +/** Key_mgmt_psk */ +#define KEY_MGMT_NONE 0x04 +/** Key_mgmt_none */ +#define KEY_MGMT_PSK 0x02 +/** Key_mgmt_eap */ +#define KEY_MGMT_EAP 0x01 + +/** TKIP */ +#define CIPHER_TKIP 0x04 +/** AES CCMP */ +#define CIPHER_AES_CCMP 0x08 + +/** Valid cipher bitmap */ +#define VALID_CIPHER_BITMAP 0x0c + +/** Channel List Entry */ +typedef struct _channel_list +{ + /** Channel Number */ + t_u8 chan_number; + /** Band Config */ + t_u8 band_config_type; +} scan_chan_list; + +/** mac_filter data structure */ +typedef struct _mac_filter +{ + /** mac filter mode */ + t_u16 filter_mode; + /** mac adress count */ + t_u16 mac_count; + /** mac address list */ + mlan_802_11_mac_addr mac_list[MAX_MAC_FILTER_NUM]; +} mac_filter; + +/** wpa parameter */ +typedef struct _wpa_param +{ + /** Pairwise cipher WPA */ + t_u8 pairwise_cipher_wpa; + /** Pairwise cipher WPA2 */ + t_u8 pairwise_cipher_wpa2; + /** group cipher */ + t_u8 group_cipher; + /** RSN replay protection */ + t_u8 rsn_protection; + /** passphrase length */ + t_u32 length; + /** passphrase */ + t_u8 passphrase[64]; + /**group key rekey time in seconds */ + t_u32 gk_rekey_time; +} wpa_param; + +/** wep key */ +typedef struct _wep_key +{ + /** key index 0-3 */ + t_u8 key_index; + /** is default */ + t_u8 is_default; + /** length */ + t_u16 length; + /** key data */ + t_u8 key[26]; +} wep_key; + +/** wep param */ +typedef struct _wep_param +{ + /** key 0 */ + wep_key key0; + /** key 1 */ + wep_key key1; + /** key 2 */ + wep_key key2; + /** key 3 */ + wep_key key3; +} wep_param; + +/** Data structure of WMM QoS information */ +typedef struct _wmm_qos_info_t +{ +#ifdef BIG_ENDIAN_SUPPORT + /** QoS UAPSD */ + t_u8 qos_uapsd:1; + /** Reserved */ + t_u8 reserved:3; + /** Parameter set count */ + t_u8 para_set_count:4; +#else + /** Parameter set count */ + t_u8 para_set_count:4; + /** Reserved */ + t_u8 reserved:3; + /** QoS UAPSD */ + t_u8 qos_uapsd:1; +#endif /* BIG_ENDIAN_SUPPORT */ +} wmm_qos_info_t, *pwmm_qos_info_t; + +/** Data structure of WMM ECW */ +typedef struct _wmm_ecw_t +{ +#ifdef BIG_ENDIAN_SUPPORT + /** Maximum Ecw */ + t_u8 ecw_max:4; + /** Minimum Ecw */ + t_u8 ecw_min:4; +#else + /** Minimum Ecw */ + t_u8 ecw_min:4; + /** Maximum Ecw */ + t_u8 ecw_max:4; +#endif /* BIG_ENDIAN_SUPPORT */ +} wmm_ecw_t, *pwmm_ecw_t; + +/** Data structure of WMM Aci/Aifsn */ +typedef struct _wmm_aci_aifsn_t +{ +#ifdef BIG_ENDIAN_SUPPORT + /** Reserved */ + t_u8 reserved:1; + /** Aci */ + t_u8 aci:2; + /** Acm */ + t_u8 acm:1; + /** Aifsn */ + t_u8 aifsn:4; +#else + /** Aifsn */ + t_u8 aifsn:4; + /** Acm */ + t_u8 acm:1; + /** Aci */ + t_u8 aci:2; + /** Reserved */ + t_u8 reserved:1; +#endif /* BIG_ENDIAN_SUPPORT */ +} wmm_aci_aifsn_t, *pwmm_aci_aifsn_t; + +/** Data structure of WMM AC parameters */ +typedef struct _wmm_ac_parameters_t +{ + wmm_aci_aifsn_t aci_aifsn; /**< AciAifSn */ + wmm_ecw_t ecw; /**< Ecw */ + t_u16 tx_op_limit; /**< Tx op limit */ +} wmm_ac_parameters_t, *pwmm_ac_parameters_t; + +/** Data structure of WMM parameter IE */ +typedef struct _wmm_parameter_t +{ + /** OuiType: 00:50:f2:02 */ + t_u8 ouitype[4]; + /** Oui subtype: 01 */ + t_u8 ouisubtype; + /** version: 01 */ + t_u8 version; + /** QoS information */ + t_u8 qos_info; + /** Reserved */ + t_u8 reserved; + /** AC Parameters Record WMM_AC_BE, WMM_AC_BK, WMM_AC_VI, WMM_AC_VO */ + wmm_ac_parameters_t ac_params[MAX_AC_QUEUES]; +} wmm_parameter_t, *pwmm_parameter_t; + +/** mlan_bss_param + * Note: For each entry you must enter an invalid value + * in the MOAL function woal_set_sys_config_invalid_data(). + * Otherwise for a valid data an unwanted TLV will be + * added to that command. + */ +typedef struct _mlan_uap_bss_param +{ + /** AP mac addr */ + mlan_802_11_mac_addr mac_addr; + /** SSID */ + mlan_802_11_ssid ssid; + /** Broadcast ssid control */ + t_u8 bcast_ssid_ctl; + /** Radio control: on/off */ + t_u8 radio_ctl; + /** dtim period */ + t_u8 dtim_period; + /** beacon period */ + t_u16 beacon_period; + /** rates */ + t_u8 rates[MAX_DATA_RATES]; + /** Tx data rate */ + t_u16 tx_data_rate; + /** multicast/broadcast data rate */ + t_u16 mcbc_data_rate; + /** Tx power level in dBm */ + t_u8 tx_power_level; + /** Tx antenna */ + t_u8 tx_antenna; + /** Rx antenna */ + t_u8 rx_antenna; + /** packet forward control */ + t_u8 pkt_forward_ctl; + /** max station count */ + t_u16 max_sta_count; + /** mac filter */ + mac_filter filter; + /** station ageout timer in unit of 100ms */ + t_u32 sta_ageout_timer; + /** PS station ageout timer in unit of 100ms */ + t_u32 ps_sta_ageout_timer; + /** RTS threshold */ + t_u16 rts_threshold; + /** fragmentation threshold */ + t_u16 frag_threshold; + /** retry_limit */ + t_u16 retry_limit; + /** pairwise update timeout in milliseconds */ + t_u32 pairwise_update_timeout; + /** pairwise handshake retries */ + t_u32 pwk_retries; + /** groupwise update timeout in milliseconds */ + t_u32 groupwise_update_timeout; + /** groupwise handshake retries */ + t_u32 gwk_retries; + /** preamble type */ + t_u8 preamble_type; + /** band cfg */ + t_u8 band_cfg; + /** channel */ + t_u8 channel; + /** auth mode */ + t_u16 auth_mode; + /** encryption protocol */ + t_u16 protocol; + /** key managment type */ + t_u16 key_mgmt; + /** wep param */ + wep_param wep_cfg; + /** wpa param */ + wpa_param wpa_cfg; + /** Mgmt IE passthru mask */ + t_u32 mgmt_ie_passthru_mask; + /* + * 11n HT Cap HTCap_t ht_cap + */ + /** HT Capabilities Info field */ + t_u16 ht_cap_info; + /** A-MPDU Parameters field */ + t_u8 ampdu_param; + /** Supported MCS Set field */ + t_u8 supported_mcs_set[16]; + /** HT Extended Capabilities field */ + t_u16 ht_ext_cap; + /** Transmit Beamforming Capabilities field */ + t_u32 tx_bf_cap; + /** Antenna Selection Capability field */ + t_u8 asel; + /** Enable 2040 Coex */ + t_u8 enable_2040coex; + /** key management operation */ + t_u16 key_mgmt_operation; + /** BSS status */ + t_u16 bss_status; +#ifdef WIFI_DIRECT_SUPPORT + /* pre shared key */ + t_u8 psk[MLAN_MAX_KEY_LENGTH]; +#endif /* WIFI_DIRECT_SUPPORT */ + /** Number of channels in scan_channel_list */ + t_u32 num_of_chan; + /** scan channel list in ACS mode */ + scan_chan_list chan_list[MLAN_MAX_CHANNEL]; + /** Wmm parameters */ + wmm_parameter_t wmm_para; +} mlan_uap_bss_param; + +/** mlan_deauth_param */ +typedef struct _mlan_deauth_param +{ + /** STA mac addr */ + t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH]; + /** deauth reason */ + t_u16 reason_code; +} mlan_deauth_param; +#endif + +#ifdef WIFI_DIRECT_SUPPORT +/** mode: disable wifi direct */ +#define WIFI_DIRECT_MODE_DISABLE 0 +/** mode: listen */ +#define WIFI_DIRECT_MODE_LISTEN 1 +/** mode: GO */ +#define WIFI_DIRECT_MODE_GO 2 +/** mode: client */ +#define WIFI_DIRECT_MODE_CLIENT 3 +/** mode: find */ +#define WIFI_DIRECT_MODE_FIND 4 +/** mode: stop find */ +#define WIFI_DIRECT_MODE_STOP_FIND 5 +#endif + +/** Type definition of mlan_ds_bss for MLAN_IOCTL_BSS */ +typedef struct _mlan_ds_bss +{ + /** Sub-command */ + t_u32 sub_command; + /** BSS parameter */ + union + { + /** SSID-BSSID for MLAN_OID_BSS_START */ + mlan_ssid_bssid ssid_bssid; + /** BSSID for MLAN_OID_BSS_STOP */ + mlan_802_11_mac_addr bssid; + /** BSS mode for MLAN_OID_BSS_MODE */ + t_u32 bss_mode; + /** BSS channel/frequency for MLAN_OID_BSS_CHANNEL */ + chan_freq bss_chan; + /** BSS channel list for MLAN_OID_BSS_CHANNEL_LIST */ + mlan_chan_list chanlist; + /** MAC address for MLAN_OID_BSS_MAC_ADDR */ + mlan_802_11_mac_addr mac_addr; + /** Multicast list for MLAN_OID_BSS_MULTICAST_LIST */ + mlan_multicast_list multicast_list; + /** Beacon interval for MLAN_OID_IBSS_BCN_INTERVAL */ + t_u32 bcn_interval; + /** ATIM window for MLAN_OID_IBSS_ATIM_WINDOW */ + t_u32 atim_window; +#ifdef UAP_SUPPORT + /** BSS param for AP mode */ + mlan_uap_bss_param bss_config; + /** deauth param for MLAN_OID_UAP_DEAUTH_STA */ + mlan_deauth_param deauth_param; +#endif +#if defined(STA_SUPPORT) && defined(UAP_SUPPORT) + /** BSS role */ + t_u8 bss_role; +#endif +#ifdef WIFI_DIRECT_SUPPORT + t_u16 wfd_mode; +#endif + } param; +} mlan_ds_bss, *pmlan_ds_bss; + +/*-----------------------------------------------------------------*/ +/** Radio Control Group */ +/*-----------------------------------------------------------------*/ +/** Enumeration for band */ +enum _mlan_band_def +{ + BAND_B = 1, + BAND_G = 2, + BAND_A = 4, + BAND_GN = 8, + BAND_AN = 16, +}; + +/** NO secondary channel */ +#define NO_SEC_CHANNEL 0 +/** secondary channel is above primary channel */ +#define SEC_CHANNEL_ABOVE 1 +/** secondary channel is below primary channel */ +#define SEC_CHANNEL_BELOW 3 +/** Channel bandwidth */ +#define CHANNEL_BW_20MHZ 0 +#define CHANNEL_BW_40MHZ_ABOVE 1 +#define CHANNEL_BW_40MHZ_BELOW 3 + +/** Type definition of mlan_ds_band_cfg for MLAN_OID_BAND_CFG */ +typedef struct _mlan_ds_band_cfg +{ + /** Infra band */ + t_u32 config_bands; + /** Ad-hoc start band */ + t_u32 adhoc_start_band; + /** Ad-hoc start channel */ + t_u32 adhoc_channel; + /** Ad-hoc channel bandwidth */ + t_u32 sec_chan_offset; + /** fw supported band */ + t_u32 fw_bands; +} mlan_ds_band_cfg; + +/** Type definition of mlan_ds_ant_cfg for MLAN_OID_ANT_CFG */ +typedef struct _mlan_ds_ant_cfg +{ + /** Tx antenna mode */ + t_u32 tx_antenna; + /** Rx antenna mode */ + t_u32 rx_antenna; +} mlan_ds_ant_cfg, *pmlan_ds_ant_cfg; + +#ifdef WIFI_DIRECT_SUPPORT +/** Type definition of mlan_ds_remain_chan for MLAN_OID_REMAIN_CHAN_CFG */ +typedef struct _mlan_ds_remain_chan +{ + /** remove flag */ + t_u16 remove; + /** status */ + t_u8 status; + /** Band cfg */ + t_u8 bandcfg; + /** channel */ + t_u8 channel; + /** remain time: Unit ms*/ + t_u32 remain_period; +} mlan_ds_remain_chan, *pmlan_ds_remain_chan; +#endif + +/** Type definition of mlan_ds_radio_cfg for MLAN_IOCTL_RADIO_CFG */ +typedef struct _mlan_ds_radio_cfg +{ + /** Sub-command */ + t_u32 sub_command; + /** Radio control parameter */ + union + { + /** Radio on/off for MLAN_OID_RADIO_CTRL */ + t_u32 radio_on_off; + /** Band info for MLAN_OID_BAND_CFG */ + mlan_ds_band_cfg band_cfg; + /** Antenna info for MLAN_OID_ANT_CFG */ + mlan_ds_ant_cfg ant_cfg; + /** Antenna info for MLAN_OID_ANT_CFG */ + t_u32 antenna; +#ifdef WIFI_DIRECT_SUPPORT + /** remain on channel for MLAN_OID_REMAIN_CHAN_CFG */ + mlan_ds_remain_chan remain_chan; +#endif + } param; +} mlan_ds_radio_cfg, *pmlan_ds_radio_cfg; + +/*-----------------------------------------------------------------*/ +/** SNMP MIB Group */ +/*-----------------------------------------------------------------*/ +/** Type definition of mlan_ds_snmp_mib for MLAN_IOCTL_SNMP_MIB */ +typedef struct _mlan_ds_snmp_mib +{ + /** Sub-command */ + t_u32 sub_command; + /** SNMP MIB parameter */ + union + { + /** RTS threshold for MLAN_OID_SNMP_MIB_RTS_THRESHOLD */ + t_u32 rts_threshold; + /** Fragment threshold for MLAN_OID_SNMP_MIB_FRAG_THRESHOLD */ + t_u32 frag_threshold; + /** Retry count for MLAN_OID_SNMP_MIB_RETRY_COUNT */ + t_u32 retry_count; +#if defined(UAP_SUPPORT) + /** OID value for MLAN_OID_SNMP_MIB_DOT11D/H */ + t_u32 oid_value; +#endif + /** DTIM period for MLAN_OID_SNMP_MIB_DTIM_PERIOD */ + t_u32 dtim_period; + } param; +} mlan_ds_snmp_mib, *pmlan_ds_snmp_mib; + +/*-----------------------------------------------------------------*/ +/** Status Information Group */ +/*-----------------------------------------------------------------*/ +/** Enumeration for ad-hoc status */ +enum _mlan_adhoc_status +{ + ADHOC_IDLE, + ADHOC_STARTED, + ADHOC_JOINED, + ADHOC_COALESCED, ADHOC_STARTING +}; + +/** Type definition of mlan_ds_get_stats for MLAN_OID_GET_STATS */ +typedef struct _mlan_ds_get_stats +{ + /** Statistics counter */ + /** Multicast transmitted frame count */ + t_u32 mcast_tx_frame; + /** Failure count */ + t_u32 failed; + /** Retry count */ + t_u32 retry; + /** Multi entry count */ + t_u32 multi_retry; + /** Duplicate frame count */ + t_u32 frame_dup; + /** RTS success count */ + t_u32 rts_success; + /** RTS failure count */ + t_u32 rts_failure; + /** Ack failure count */ + t_u32 ack_failure; + /** Rx fragmentation count */ + t_u32 rx_frag; + /** Multicast Tx frame count */ + t_u32 mcast_rx_frame; + /** FCS error count */ + t_u32 fcs_error; + /** Tx frame count */ + t_u32 tx_frame; + /** WEP ICV error count */ + t_u32 wep_icv_error[4]; +} mlan_ds_get_stats, *pmlan_ds_get_stats; + +/** Type definition of mlan_ds_uap_stats for MLAN_OID_GET_STATS */ +typedef struct _mlan_ds_uap_stats +{ + /** tkip mic failures */ + t_u32 tkip_mic_failures; + /** ccmp decrypt errors */ + t_u32 ccmp_decrypt_errors; + /** wep undecryptable count */ + t_u32 wep_undecryptable_count; + /** wep icv error count */ + t_u32 wep_icv_error_count; + /** decrypt failure count */ + t_u32 decrypt_failure_count; + /** dot11 multicast tx count */ + t_u32 mcast_tx_count; + /** dot11 failed count */ + t_u32 failed_count; + /** dot11 retry count */ + t_u32 retry_count; + /** dot11 multi retry count */ + t_u32 multi_retry_count; + /** dot11 frame duplicate count */ + t_u32 frame_dup_count; + /** dot11 rts success count */ + t_u32 rts_success_count; + /** dot11 rts failure count */ + t_u32 rts_failure_count; + /** dot11 ack failure count */ + t_u32 ack_failure_count; + /** dot11 rx ragment count */ + t_u32 rx_fragment_count; + /** dot11 mcast rx frame count */ + t_u32 mcast_rx_frame_count; + /** dot11 fcs error count */ + t_u32 fcs_error_count; + /** dot11 tx frame count */ + t_u32 tx_frame_count; + /** dot11 rsna tkip cm invoked */ + t_u32 rsna_tkip_cm_invoked; + /** dot11 rsna 4way handshake failures */ + t_u32 rsna_4way_hshk_failures; +} mlan_ds_uap_stats, *pmlan_ds_uap_stats; + +/** Mask of last beacon RSSI */ +#define BCN_RSSI_LAST_MASK 0x00000001 +/** Mask of average beacon RSSI */ +#define BCN_RSSI_AVG_MASK 0x00000002 +/** Mask of last data RSSI */ +#define DATA_RSSI_LAST_MASK 0x00000004 +/** Mask of average data RSSI */ +#define DATA_RSSI_AVG_MASK 0x00000008 +/** Mask of last beacon SNR */ +#define BCN_SNR_LAST_MASK 0x00000010 +/** Mask of average beacon SNR */ +#define BCN_SNR_AVG_MASK 0x00000020 +/** Mask of last data SNR */ +#define DATA_SNR_LAST_MASK 0x00000040 +/** Mask of average data SNR */ +#define DATA_SNR_AVG_MASK 0x00000080 +/** Mask of last beacon NF */ +#define BCN_NF_LAST_MASK 0x00000100 +/** Mask of average beacon NF */ +#define BCN_NF_AVG_MASK 0x00000200 +/** Mask of last data NF */ +#define DATA_NF_LAST_MASK 0x00000400 +/** Mask of average data NF */ +#define DATA_NF_AVG_MASK 0x00000800 +/** Mask of all RSSI_INFO */ +#define ALL_RSSI_INFO_MASK 0x00000fff + +/** Type definition of mlan_ds_get_signal for MLAN_OID_GET_SIGNAL */ +typedef struct _mlan_ds_get_signal +{ + /** Selector of get operation */ + /* + * Bit0: Last Beacon RSSI, Bit1: Average Beacon RSSI, + * Bit2: Last Data RSSI, Bit3: Average Data RSSI, + * Bit4: Last Beacon SNR, Bit5: Average Beacon SNR, + * Bit6: Last Data SNR, Bit7: Average Data SNR, + * Bit8: Last Beacon NF, Bit9: Average Beacon NF, + * Bit10: Last Data NF, Bit11: Average Data NF + */ + t_u16 selector; + + /** RSSI */ + /** RSSI of last beacon */ + t_s16 bcn_rssi_last; + /** RSSI of beacon average */ + t_s16 bcn_rssi_avg; + /** RSSI of last data packet */ + t_s16 data_rssi_last; + /** RSSI of data packet average */ + t_s16 data_rssi_avg; + + /** SNR */ + /** SNR of last beacon */ + t_s16 bcn_snr_last; + /** SNR of beacon average */ + t_s16 bcn_snr_avg; + /** SNR of last data packet */ + t_s16 data_snr_last; + /** SNR of data packet average */ + t_s16 data_snr_avg; + + /** NF */ + /** NF of last beacon */ + t_s16 bcn_nf_last; + /** NF of beacon average */ + t_s16 bcn_nf_avg; + /** NF of last data packet */ + t_s16 data_nf_last; + /** NF of data packet average */ + t_s16 data_nf_avg; +} mlan_ds_get_signal, *pmlan_ds_get_signal; + +/** mlan_fw_info data structure for MLAN_OID_GET_FW_INFO */ +typedef struct _mlan_fw_info +{ + /** Firmware version */ + t_u32 fw_ver; + /** MAC address */ + mlan_802_11_mac_addr mac_addr; + /** Device support for MIMO abstraction of MCSs */ + t_u8 hw_dev_mcs_support; + /** fw supported band */ + t_u8 fw_bands; +} mlan_fw_info, *pmlan_fw_info; + +/** Version string buffer length */ +#define MLAN_MAX_VER_STR_LEN 128 + +/** mlan_ver_ext data structure for MLAN_OID_GET_VER_EXT */ +typedef struct _mlan_ver_ext +{ + /** Selected version string */ + t_u32 version_str_sel; + /** Version string */ + char version_str[MLAN_MAX_VER_STR_LEN]; +} mlan_ver_ext, *pmlan_ver_ext; + +/** mlan_bss_info data structure for MLAN_OID_GET_BSS_INFO */ +typedef struct _mlan_bss_info +{ + /** BSS mode */ + t_u32 bss_mode; + /** SSID */ + mlan_802_11_ssid ssid; + /** Table index */ + t_u32 scan_table_idx; + /** Channel */ + t_u32 bss_chan; + /** Band */ + t_u8 bss_band; + /** Region code */ + t_u32 region_code; + /** Connection status */ + t_u32 media_connected; + /** Radio on */ + t_u32 radio_on; + /** Max power level in dBm */ + t_u32 max_power_level; + /** Min power level in dBm */ + t_u32 min_power_level; + /** Adhoc state */ + t_u32 adhoc_state; + /** NF of last beacon */ + t_s32 bcn_nf_last; + /** wep status */ + t_u32 wep_status; + /** Host Sleep configured flag */ + t_u32 is_hs_configured; + /** Deep Sleep flag */ + t_u32 is_deep_sleep; + /** BSSID */ + mlan_802_11_mac_addr bssid; +#ifdef STA_SUPPORT + /** Capability Info */ + t_u16 capability_info; + /** Beacon Interval */ + t_u16 beacon_interval; + /** Listen Interval */ + t_u16 listen_interval; + /** Association Id */ + t_u16 assoc_id; + /** AP/Peer supported rates */ + t_u8 peer_supp_rates[MLAN_SUPPORTED_RATES]; +#endif /* STA_SUPPORT */ +} mlan_bss_info, *pmlan_bss_info; + +/** MAXIMUM number of TID */ +#define MAX_NUM_TID 8 + +/** Max RX Win size */ +#define MAX_RX_WINSIZE 64 + +/** rx_reorder_tbl */ +typedef struct +{ + /** TID */ + t_u16 tid; + /** TA */ + t_u8 ta[MLAN_MAC_ADDR_LENGTH]; + /** Start window */ + t_u32 start_win; + /** Window size */ + t_u32 win_size; + /** amsdu flag */ + t_u8 amsdu; + /** buffer status */ + t_u32 buffer[MAX_RX_WINSIZE]; +} rx_reorder_tbl; + +/** tx_ba_stream_tbl */ +typedef struct +{ + /** TID */ + t_u16 tid; + /** RA */ + t_u8 ra[MLAN_MAC_ADDR_LENGTH]; + /** amsdu flag */ + t_u8 amsdu; +} tx_ba_stream_tbl; + +/** Debug command number */ +#define DBG_CMD_NUM 5 + +/** mlan_debug_info data structure for MLAN_OID_GET_DEBUG_INFO */ +typedef struct _mlan_debug_info +{ + /* WMM AC_BK count */ + t_u32 wmm_ac_bk; + /* WMM AC_BE count */ + t_u32 wmm_ac_be; + /* WMM AC_VI count */ + t_u32 wmm_ac_vi; + /* WMM AC_VO count */ + t_u32 wmm_ac_vo; + /** Corresponds to max_tx_buf_size member of mlan_adapter*/ + t_u32 max_tx_buf_size; + /** Corresponds to tx_buf_size member of mlan_adapter*/ + t_u32 tx_buf_size; + /** Corresponds to curr_tx_buf_size member of mlan_adapter*/ + t_u32 curr_tx_buf_size; + /** Tx table num */ + t_u32 tx_tbl_num; + /** Tx ba stream table */ + tx_ba_stream_tbl tx_tbl[MLAN_MAX_TX_BASTREAM_SUPPORTED]; + /** Rx table num */ + t_u32 rx_tbl_num; + /** Rx reorder table*/ + rx_reorder_tbl rx_tbl[MLAN_MAX_RX_BASTREAM_SUPPORTED]; + /** Corresponds to ps_mode member of mlan_adapter */ + t_u16 ps_mode; + /** Corresponds to ps_state member of mlan_adapter */ + t_u32 ps_state; +#ifdef STA_SUPPORT + /** Corresponds to is_deep_sleep member of mlan_adapter */ + t_u8 is_deep_sleep; +#endif /** STA_SUPPORT */ + /** Corresponds to pm_wakeup_card_req member of mlan_adapter */ + t_u8 pm_wakeup_card_req; + /** Corresponds to pm_wakeup_fw_try member of mlan_adapter */ + t_u32 pm_wakeup_fw_try; + /** Corresponds to is_hs_configured member of mlan_adapter */ + t_u8 is_hs_configured; + /** Corresponds to hs_activated member of mlan_adapter */ + t_u8 hs_activated; + /** Corresponds to pps_uapsd_mode member of mlan_adapter */ + t_u16 pps_uapsd_mode; + /** Corresponds to sleep_period.period member of mlan_adapter */ + t_u16 sleep_pd; + /** Corresponds to wmm_qosinfo member of mlan_private */ + t_u8 qos_cfg; + /** Corresponds to tx_lock_flag member of mlan_adapter */ + t_u8 tx_lock_flag; + /** Corresponds to port_open member of mlan_private */ + t_u8 port_open; + /** Corresponds to scan_processing member of mlan_adapter */ + t_u32 scan_processing; + /** Number of host to card command failures */ + t_u32 num_cmd_host_to_card_failure; + /** Number of host to card sleep confirm failures */ + t_u32 num_cmd_sleep_cfm_host_to_card_failure; + /** Number of host to card Tx failures */ + t_u32 num_tx_host_to_card_failure; + /** Number of card to host command/event failures */ + t_u32 num_cmdevt_card_to_host_failure; + /** Number of card to host Rx failures */ + t_u32 num_rx_card_to_host_failure; + /** Number of interrupt read failures */ + t_u32 num_int_read_failure; + /** Last interrupt status */ + t_u32 last_int_status; + /** Number of deauthentication events */ + t_u32 num_event_deauth; + /** Number of disassosiation events */ + t_u32 num_event_disassoc; + /** Number of link lost events */ + t_u32 num_event_link_lost; + /** Number of deauthentication commands */ + t_u32 num_cmd_deauth; + /** Number of association comamnd successes */ + t_u32 num_cmd_assoc_success; + /** Number of association command failures */ + t_u32 num_cmd_assoc_failure; + /** Number of Tx timeouts */ + t_u32 num_tx_timeout; + /** Number of command timeouts */ + t_u32 num_cmd_timeout; + /** Timeout command ID */ + t_u16 timeout_cmd_id; + /** Timeout command action */ + t_u16 timeout_cmd_act; + /** List of last command IDs */ + t_u16 last_cmd_id[DBG_CMD_NUM]; + /** List of last command actions */ + t_u16 last_cmd_act[DBG_CMD_NUM]; + /** Last command index */ + t_u16 last_cmd_index; + /** List of last command response IDs */ + t_u16 last_cmd_resp_id[DBG_CMD_NUM]; + /** Last command response index */ + t_u16 last_cmd_resp_index; + /** List of last events */ + t_u16 last_event[DBG_CMD_NUM]; + /** Last event index */ + t_u16 last_event_index; + + /** Corresponds to data_sent member of mlan_adapter */ + t_u8 data_sent; + /** Corresponds to cmd_sent member of mlan_adapter */ + t_u8 cmd_sent; + /** SDIO multiple port read bitmap */ + t_u32 mp_rd_bitmap; + /** SDIO multiple port write bitmap */ + t_u32 mp_wr_bitmap; + /** Current available port for read */ + t_u8 curr_rd_port; + /** Current available port for write */ + t_u8 curr_wr_port; + /** Corresponds to cmdresp_received member of mlan_adapter */ + t_u8 cmd_resp_received; + /** Corresponds to event_received member of mlan_adapter */ + t_u8 event_received; + /** pendig tx pkts */ + t_u32 tx_pkts_queued; +#ifdef UAP_SUPPORT + /** pending bridge pkts */ + t_u16 num_bridge_pkts; + /** dropped pkts */ + t_u32 num_drop_pkts; +#endif +} mlan_debug_info, *pmlan_debug_info; + +#ifdef UAP_SUPPORT +/** Maximum number of clients supported by AP */ +#define MAX_NUM_CLIENTS MAX_STA_COUNT + +/** station info */ +typedef struct _sta_info +{ + /** STA MAC address */ + t_u8 mac_address[MLAN_MAC_ADDR_LENGTH]; + /** Power mfg status */ + t_u8 power_mfg_status; + /** RSSI */ + t_s8 rssi; +} sta_info; + +/** mlan_ds_sta_list structure for MLAN_OID_UAP_STA_LIST */ +typedef struct _mlan_ds_sta_list +{ + /** station count */ + t_u16 sta_count; + /** station list */ + sta_info info[MAX_NUM_CLIENTS]; +} mlan_ds_sta_list, *pmlan_ds_sta_list; +#endif + +/** Type definition of mlan_ds_get_info for MLAN_IOCTL_GET_INFO */ +typedef struct _mlan_ds_get_info +{ + /** Sub-command */ + t_u32 sub_command; + + /** Status information parameter */ + union + { + /** Signal information for MLAN_OID_GET_SIGNAL */ + mlan_ds_get_signal signal; + /** Statistics information for MLAN_OID_GET_STATS */ + mlan_ds_get_stats stats; + /** Firmware information for MLAN_OID_GET_FW_INFO */ + mlan_fw_info fw_info; + /** Extended version information for MLAN_OID_GET_VER_EXT */ + mlan_ver_ext ver_ext; + /** BSS information for MLAN_OID_GET_BSS_INFO */ + mlan_bss_info bss_info; + /** Debug information for MLAN_OID_GET_DEBUG_INFO */ + mlan_debug_info debug_info; +#ifdef UAP_SUPPORT + /** UAP Statistics information for MLAN_OID_GET_STATS */ + mlan_ds_uap_stats ustats; + /** UAP station list for MLAN_OID_UAP_STA_LIST */ + mlan_ds_sta_list sta_list; +#endif + } param; +} mlan_ds_get_info, *pmlan_ds_get_info; + +/*-----------------------------------------------------------------*/ +/** Security Configuration Group */ +/*-----------------------------------------------------------------*/ +/** Enumeration for authentication mode */ +enum _mlan_auth_mode +{ + MLAN_AUTH_MODE_OPEN = 0x00, + MLAN_AUTH_MODE_SHARED = 0x01, + MLAN_AUTH_MODE_NETWORKEAP = 0x80, + MLAN_AUTH_MODE_AUTO = 0xFF, +}; + +/** Enumeration for encryption mode */ +enum _mlan_encryption_mode +{ + MLAN_ENCRYPTION_MODE_NONE = 0, + MLAN_ENCRYPTION_MODE_WEP40 = 1, + MLAN_ENCRYPTION_MODE_TKIP = 2, + MLAN_ENCRYPTION_MODE_CCMP = 3, + MLAN_ENCRYPTION_MODE_WEP104 = 4, +}; + +/** Enumeration for PSK */ +enum _mlan_psk_type +{ + MLAN_PSK_PASSPHRASE = 1, + MLAN_PSK_PMK, + MLAN_PSK_CLEAR, + MLAN_PSK_QUERY, +}; + +/** The bit to indicate the key is for unicast */ +#define MLAN_KEY_INDEX_UNICAST 0x40000000 +/** The key index to indicate default key */ +#define MLAN_KEY_INDEX_DEFAULT 0x000000ff +/** Maximum key length */ +// #define MLAN_MAX_KEY_LENGTH 32 +/** Minimum passphrase length */ +#define MLAN_MIN_PASSPHRASE_LENGTH 8 +/** Maximum passphrase length */ +#define MLAN_MAX_PASSPHRASE_LENGTH 63 +/** PMK length */ +#define MLAN_PMK_HEXSTR_LENGTH 64 +/* A few details needed for WEP (Wireless Equivalent Privacy) */ +/** 104 bits */ +#define MAX_WEP_KEY_SIZE 13 +/** 40 bits RC4 - WEP */ +#define MIN_WEP_KEY_SIZE 5 +/** packet number size */ +#define PN_SIZE 16 +/** max seq size of wpa/wpa2 key */ +#define SEQ_MAX_SIZE 8 + +/** key flag for tx_seq */ +#define KEY_FLAG_TX_SEQ_VALID 0x00000001 +/** key flag for rx_seq */ +#define KEY_FLAG_RX_SEQ_VALID 0x00000002 +/** key flag for group key */ +#define KEY_FLAG_GROUP_KEY 0x00000004 +/** key flag for tx and rx */ +#define KEY_FLAG_SET_TX_KEY 0x00000008 +/** key flag for remove key */ +#define KEY_FLAG_REMOVE_KEY 0x80000000 + +/** Type definition of mlan_ds_encrypt_key for MLAN_OID_SEC_CFG_ENCRYPT_KEY */ +typedef struct _mlan_ds_encrypt_key +{ + /** Key disabled, all other fields will be ignore when this flag set to MTRUE */ + t_u32 key_disable; + /** key removed flag, when this flag is set to MTRUE, only key_index will be check */ + t_u32 key_remove; + /** Key index, used as current tx key index when is_current_wep_key is set to MTRUE */ + t_u32 key_index; + /** Current Tx key flag */ + t_u32 is_current_wep_key; + /** Key length */ + t_u32 key_len; + /** Key */ + t_u8 key_material[MLAN_MAX_KEY_LENGTH]; + /** mac address */ + t_u8 mac_addr[MLAN_MAC_ADDR_LENGTH]; + /** wapi key flag */ + t_u32 is_wapi_key; + /** Initial packet number */ + t_u8 pn[PN_SIZE]; + /** key flags */ + t_u32 key_flags; +} mlan_ds_encrypt_key, *pmlan_ds_encrypt_key; + +/** Type definition of mlan_passphrase_t */ +typedef struct _mlan_passphrase_t +{ + /** Length of passphrase */ + t_u32 passphrase_len; + /** Passphrase */ + t_u8 passphrase[MLAN_MAX_PASSPHRASE_LENGTH]; +} mlan_passphrase_t; + +/** Type defnition of mlan_pmk_t */ +typedef struct _mlan_pmk_t +{ + /** PMK */ + t_u8 pmk[MLAN_MAX_KEY_LENGTH]; +} mlan_pmk_t; + +/** Embedded supplicant RSN type: No RSN */ +#define RSN_TYPE_NO_RSN MBIT(0) +/** Embedded supplicant RSN type: WPA */ +#define RSN_TYPE_WPA MBIT(3) +/** Embedded supplicant RSN type: WPA-NONE */ +#define RSN_TYPE_WPANONE MBIT(4) +/** Embedded supplicant RSN type: WPA2 */ +#define RSN_TYPE_WPA2 MBIT(5) +/** Embedded supplicant RSN type: RFU */ +#define RSN_TYPE_VALID_BITS (RSN_TYPE_NO_RSN | RSN_TYPE_WPA | RSN_TYPE_WPANONE | RSN_TYPE_WPA2) + +/** Embedded supplicant cipher type: TKIP */ +#define EMBED_CIPHER_TKIP MBIT(2) +/** Embedded supplicant cipher type: AES */ +#define EMBED_CIPHER_AES MBIT(3) +/** Embedded supplicant cipher type: RFU */ +#define EMBED_CIPHER_VALID_BITS (EMBED_CIPHER_TKIP | EMBED_CIPHER_AES) + +/** Type definition of mlan_ds_passphrase for MLAN_OID_SEC_CFG_PASSPHRASE */ +typedef struct _mlan_ds_passphrase +{ + /** SSID may be used */ + mlan_802_11_ssid ssid; + /** BSSID may be used */ + mlan_802_11_mac_addr bssid; + /** Flag for passphrase or pmk used */ + t_u16 psk_type; + /** Passphrase or PMK */ + union + { + /** Passphrase */ + mlan_passphrase_t passphrase; + /** PMK */ + mlan_pmk_t pmk; + } psk; +} mlan_ds_passphrase, *pmlan_ds_passphrase; + +/** Type definition of mlan_ds_esupp_mode for MLAN_OID_SEC_CFG_ESUPP_MODE */ +typedef struct _mlan_ds_ewpa_mode +{ + /** RSN mode */ + t_u32 rsn_mode; + /** Active pairwise cipher */ + t_u32 act_paircipher; + /** Active pairwise cipher */ + t_u32 act_groupcipher; +} mlan_ds_esupp_mode, *pmlan_ds_esupp_mode; + +/** Type definition of mlan_ds_sec_cfg for MLAN_IOCTL_SEC_CFG */ +typedef struct _mlan_ds_sec_cfg +{ + /** Sub-command */ + t_u32 sub_command; + /** Security configuration parameter */ + union + { + /** Authentication mode for MLAN_OID_SEC_CFG_AUTH_MODE */ + t_u32 auth_mode; + /** Encryption mode for MLAN_OID_SEC_CFG_ENCRYPT_MODE */ + t_u32 encrypt_mode; + /** WPA enabled flag for MLAN_OID_SEC_CFG_WPA_ENABLED */ + t_u32 wpa_enabled; + /** WAPI enabled flag for MLAN_OID_SEC_CFG_WAPI_ENABLED */ + t_u32 wapi_enabled; + /** Port Control enabled flag for MLAN_OID_SEC_CFG_PORT_CTRL */ + t_u32 port_ctrl_enabled; + /** Encryption key for MLAN_OID_SEC_CFG_ENCRYPT_KEY */ + mlan_ds_encrypt_key encrypt_key; + /** Passphrase for MLAN_OID_SEC_CFG_PASSPHRASE */ + mlan_ds_passphrase passphrase; + /** Embedded supplicant WPA enabled flag for MLAN_OID_SEC_CFG_EWPA_ENABLED */ + t_u32 ewpa_enabled; + /** Embedded supplicant mode for MLAN_OID_SEC_CFG_ESUPP_MODE */ + mlan_ds_esupp_mode esupp_mode; + } param; +} mlan_ds_sec_cfg, *pmlan_ds_sec_cfg; + +/*-----------------------------------------------------------------*/ +/** Rate Configuration Group */ +/*-----------------------------------------------------------------*/ +/** Enumeration for rate type */ +enum _mlan_rate_type +{ + MLAN_RATE_INDEX, + MLAN_RATE_VALUE +}; + +/** Enumeration for rate format */ +enum _mlan_rate_format +{ + MLAN_RATE_FORMAT_LG = 0, + MLAN_RATE_FORMAT_HT, + MLAN_RATE_FORMAT_AUTO = 0xFF, +}; +/** Max bitmap rates size */ +#define MAX_BITMAP_RATES_SIZE 10 + +/** Type definition of mlan_rate_cfg_t for MLAN_OID_RATE_CFG */ +typedef struct _mlan_rate_cfg_t +{ + /** Fixed rate: 0, auto rate: 1 */ + t_u32 is_rate_auto; + /** Rate type. 0: index; 1: valude */ + t_u32 rate_type; + /** Rate/MCS index or rate value if fixed rate */ + t_u32 rate; + /** Rate Bitmap */ + t_u16 bitmap_rates[MAX_BITMAP_RATES_SIZE]; +} mlan_rate_cfg_t; + +/** HT channel bandwidth */ +typedef enum _mlan_ht_bw +{ + MLAN_HT_BW20, + MLAN_HT_BW40, +} mlan_ht_bw; + +/** HT guard interval */ +typedef enum _mlan_ht_gi +{ + MLAN_HT_LGI, + MLAN_HT_SGI, +} mlan_ht_gi; + +/** Band and BSS mode */ +typedef struct _mlan_band_data_rate +{ + /** Band configuration */ + t_u8 config_bands; + /** BSS mode (Infra or IBSS) */ + t_u8 bss_mode; +} mlan_band_data_rate; + +/** Type definition of mlan_data_rate for MLAN_OID_GET_DATA_RATE */ +typedef struct _mlan_data_rate +{ + /** Tx data rate */ + t_u32 tx_data_rate; + /** Rx data rate */ + t_u32 rx_data_rate; + + /** Tx channel bandwidth */ + t_u32 tx_ht_bw; + /** Tx guard interval */ + t_u32 tx_ht_gi; + /** Rx channel bandwidth */ + t_u32 rx_ht_bw; + /** Rx guard interval */ + t_u32 rx_ht_gi; +} mlan_data_rate; + +/** Type definition of mlan_ds_rate for MLAN_IOCTL_RATE */ +typedef struct _mlan_ds_rate +{ + /** Sub-command */ + t_u32 sub_command; + /** Rate configuration parameter */ + union + { + /** Rate configuration for MLAN_OID_RATE_CFG */ + mlan_rate_cfg_t rate_cfg; + /** Data rate for MLAN_OID_GET_DATA_RATE */ + mlan_data_rate data_rate; + /** Supported rates for MLAN_OID_SUPPORTED_RATES */ + t_u8 rates[MLAN_SUPPORTED_RATES]; + /** Band/BSS mode for getting supported rates */ + mlan_band_data_rate rate_band_cfg; + } param; +} mlan_ds_rate, *pmlan_ds_rate; + +/*-----------------------------------------------------------------*/ +/** Power Configuration Group */ +/*-----------------------------------------------------------------*/ + +/** Type definition of mlan_power_cfg_t for MLAN_OID_POWER_CFG */ +typedef struct _mlan_power_cfg_t +{ + /** Is power auto */ + t_u32 is_power_auto; + /** Power level in dBm */ + t_u32 power_level; +} mlan_power_cfg_t; + +/** max power table size */ +#define MAX_POWER_TABLE_SIZE 128 + +/** The HT BW40 bit in Tx rate index */ +#define TX_RATE_HT_BW40_BIT MBIT(7) + +/** Type definition of mlan_power_cfg_ext for MLAN_OID_POWER_CFG_EXT */ +typedef struct _mlan_power_cfg_ext +{ + /** Length of power_data */ + t_u32 len; + /** Buffer of power configuration data */ + t_u32 power_data[MAX_POWER_TABLE_SIZE]; +} mlan_power_cfg_ext; + +/** Type definition of mlan_ds_power_cfg for MLAN_IOCTL_POWER_CFG */ +typedef struct _mlan_ds_power_cfg +{ + /** Sub-command */ + t_u32 sub_command; + /** Power configuration parameter */ + union + { + /** Power configuration for MLAN_OID_POWER_CFG */ + mlan_power_cfg_t power_cfg; + /** Extended power configuration for MLAN_OID_POWER_CFG_EXT */ + mlan_power_cfg_ext power_ext; + } param; +} mlan_ds_power_cfg, *pmlan_ds_power_cfg; + +/*-----------------------------------------------------------------*/ +/** Power Management Configuration Group */ +/*-----------------------------------------------------------------*/ +/** Host sleep config conditions : Cancel */ +#define HOST_SLEEP_CFG_CANCEL 0xffffffff + +/** Host sleep config condition: broadcast data */ +#define HOST_SLEEP_COND_BROADCAST_DATA MBIT(0) +/** Host sleep config condition: unicast data */ +#define HOST_SLEEP_COND_UNICAST_DATA MBIT(1) +/** Host sleep config condition: mac event */ +#define HOST_SLEEP_COND_MAC_EVENT MBIT(2) +/** Host sleep config condition: multicast data */ +#define HOST_SLEEP_COND_MULTICAST_DATA MBIT(3) + +/** Host sleep config conditions: Default */ +#define HOST_SLEEP_DEF_COND (HOST_SLEEP_COND_BROADCAST_DATA | HOST_SLEEP_COND_UNICAST_DATA | HOST_SLEEP_COND_MAC_EVENT) +/** Host sleep config GPIO : Default */ +#define HOST_SLEEP_DEF_GPIO 0xff +/** Host sleep config gap : Default */ +#define HOST_SLEEP_DEF_GAP 200 + +/** Type definition of mlan_ds_hs_cfg for MLAN_OID_PM_CFG_HS_CFG */ +typedef struct _mlan_ds_hs_cfg +{ + /** MTRUE to invoke the HostCmd, MFALSE otherwise */ + t_u32 is_invoke_hostcmd; + /** Host sleep config condition */ + /** Bit0: broadcast data + * Bit1: unicast data + * Bit2: mac event + * Bit3: multicast data + */ + t_u32 conditions; + /** GPIO pin or 0xff for interface */ + t_u32 gpio; + /** Gap in milliseconds or or 0xff for special setting when GPIO is used to wakeup host */ + t_u32 gap; +} mlan_ds_hs_cfg, *pmlan_ds_hs_cfg; + +/** Enable deep sleep mode */ +#define DEEP_SLEEP_ON 1 +/** Disable deep sleep mode */ +#define DEEP_SLEEP_OFF 0 + +/** Default idle time in milliseconds for auto deep sleep */ +#define DEEP_SLEEP_IDLE_TIME 100 + +typedef struct _mlan_ds_auto_ds +{ + /** auto ds mode, 0 - disable, 1 - enable */ + t_u16 auto_ds; + /** auto ds idle time in milliseconds */ + t_u16 idletime; +} mlan_ds_auto_ds; + +/** Type definition of mlan_ds_inactivity_to for MLAN_OID_PM_CFG_INACTIVITY_TO */ +typedef struct _mlan_ds_inactivity_to +{ + /** Timeout unit in microsecond, 0 means 1000us (1ms) */ + t_u32 timeout_unit; + /** Inactivity timeout for unicast data */ + t_u32 unicast_timeout; + /** Inactivity timeout for multicast data */ + t_u32 mcast_timeout; + /** Timeout for additional Rx traffic after Null PM1 packet exchange */ + t_u32 ps_entry_timeout; +} mlan_ds_inactivity_to, *pmlan_ds_inactivity_to; + +/** Minimum sleep period in milliseconds */ +#define MIN_SLEEP_PERIOD 10 +/** Maximum sleep period in milliseconds */ +#define MAX_SLEEP_PERIOD 60 +/** Special setting for UPSD certification tests */ +#define SLEEP_PERIOD_RESERVED_FF 0xFF + +/** PS null interval disable */ +#define PS_NULL_DISABLE (-1) + +/** Local listen interval disable */ +#define MRVDRV_LISTEN_INTERVAL_DISABLE (-1) +/** Minimum listen interval */ +#define MRVDRV_MIN_LISTEN_INTERVAL 0 + +/** Minimum multiple DTIM */ +#define MRVDRV_MIN_MULTIPLE_DTIM 0 +/** Maximum multiple DTIM */ +#define MRVDRV_MAX_MULTIPLE_DTIM 5 +/** Ignore multiple DTIM */ +#define MRVDRV_IGNORE_MULTIPLE_DTIM 0xfffe +/** Match listen interval to closest DTIM */ +#define MRVDRV_MATCH_CLOSEST_DTIM 0xfffd + +/** Minimum adhoc awake period */ +#define MIN_ADHOC_AWAKE_PD 0 +/** Maximum adhoc awake period */ +#define MAX_ADHOC_AWAKE_PD 31 +/** Special adhoc awake period */ +#define SPECIAL_ADHOC_AWAKE_PD 255 + +/** Minimum beacon miss timeout in milliseconds */ +#define MIN_BCN_MISS_TO 0 +/** Maximum beacon miss timeout in milliseconds */ +#define MAX_BCN_MISS_TO 50 +/** Disable beacon miss timeout */ +#define DISABLE_BCN_MISS_TO 65535 + +/** Minimum delay to PS in milliseconds */ +#define MIN_DELAY_TO_PS 0 +/** Maximum delay to PS in milliseconds */ +#define MAX_DELAY_TO_PS 65535 +/** Delay to PS unchanged */ +#define DELAY_TO_PS_UNCHANGED (-1) +/** Default delay to PS in milliseconds */ +#define DELAY_TO_PS_DEFAULT 1000 + +/** PS mode: Unchanged */ +#define PS_MODE_UNCHANGED 0 +/** PS mode: Auto */ +#define PS_MODE_AUTO 1 +/** PS mode: Poll */ +#define PS_MODE_POLL 2 +/** PS mode: Null */ +#define PS_MODE_NULL 3 + +/** Type definition of mlan_ds_ps_cfg for MLAN_OID_PM_CFG_PS_CFG */ +typedef struct _mlan_ds_ps_cfg +{ + /** PS null interval in seconds */ + t_u32 ps_null_interval; + /** Multiple DTIM interval */ + t_u32 multiple_dtim_interval; + /** Listen interval */ + t_u32 listen_interval; + /** Adhoc awake period */ + t_u32 adhoc_awake_period; + /** Beacon miss timeout in milliseconds */ + t_u32 bcn_miss_timeout; + /** Delay to PS in milliseconds */ + t_s32 delay_to_ps; + /** PS mode */ + t_u32 ps_mode; +} mlan_ds_ps_cfg, *pmlan_ds_ps_cfg; + +/** Type definition of mlan_ds_sleep_params for MLAN_OID_PM_CFG_SLEEP_PARAMS */ +typedef struct _mlan_ds_sleep_params +{ + /** Error */ + t_u32 error; + /** Offset in microseconds */ + t_u32 offset; + /** Stable time in microseconds */ + t_u32 stable_time; + /** Calibration control */ + t_u32 cal_control; + /** External sleep clock */ + t_u32 ext_sleep_clk; + /** Reserved */ + t_u32 reserved; +} mlan_ds_sleep_params, *pmlan_ds_sleep_params; + +/** sleep_param */ +typedef struct _ps_sleep_param +{ + /** control bitmap */ + t_u32 ctrl_bitmap; + /** minimum sleep period (micro second) */ + t_u32 min_sleep; + /** maximum sleep period (micro second) */ + t_u32 max_sleep; +} ps_sleep_param; + +/** inactivity sleep_param */ +typedef struct _inact_sleep_param +{ + /** inactivity timeout (micro second) */ + t_u32 inactivity_to; + /** miniumu awake period (micro second) */ + t_u32 min_awake; + /** maximum awake period (micro second) */ + t_u32 max_awake; +} inact_sleep_param; + +/** flag for ps mode */ +#define PS_FLAG_PS_MODE 1 +/** flag for sleep param */ +#define PS_FLAG_SLEEP_PARAM 2 +/** flag for inactivity sleep param */ +#define PS_FLAG_INACT_SLEEP_PARAM 4 + +/** Disable power mode */ +#define PS_MODE_DISABLE 0 +/** Enable periodic dtim ps */ +#define PS_MODE_PERIODIC_DTIM 1 +/** Enable inactivity ps */ +#define PS_MODE_INACTIVITY 2 + +/** mlan_ds_ps_mgmt */ +typedef struct _mlan_ds_ps_mgmt +{ + /** flags for valid field */ + t_u16 flags; + /** power mode */ + t_u16 ps_mode; + /** sleep param */ + ps_sleep_param sleep_param; + /** inactivity sleep param */ + inact_sleep_param inact_param; +} mlan_ds_ps_mgmt; + +/** mlan_ds_ps_info */ +typedef struct _mlan_ds_ps_info +{ + /** suspend allowed flag */ + t_u32 is_suspend_allowed; +} mlan_ds_ps_info; + +/** Type definition of mlan_ds_pm_cfg for MLAN_IOCTL_PM_CFG */ +typedef struct _mlan_ds_pm_cfg +{ + /** Sub-command */ + t_u32 sub_command; + /** Power management parameter */ + union + { + /** Power saving mode for MLAN_OID_PM_CFG_IEEE_PS */ + t_u32 ps_mode; + /** Host Sleep configuration for MLAN_OID_PM_CFG_HS_CFG */ + mlan_ds_hs_cfg hs_cfg; + /** Deep sleep mode for MLAN_OID_PM_CFG_DEEP_SLEEP */ + mlan_ds_auto_ds auto_deep_sleep; + /** Inactivity timeout for MLAN_OID_PM_CFG_INACTIVITY_TO */ + mlan_ds_inactivity_to inactivity_to; + /** Sleep period for MLAN_OID_PM_CFG_SLEEP_PD */ + t_u32 sleep_period; + /** PS configuration parameters for MLAN_OID_PM_CFG_PS_CFG */ + mlan_ds_ps_cfg ps_cfg; + /** PS configuration parameters for MLAN_OID_PM_CFG_SLEEP_PARAMS */ + mlan_ds_sleep_params sleep_params; + /** PS configuration parameters for MLAN_OID_PM_CFG_PS_MODE */ + mlan_ds_ps_mgmt ps_mgmt; + /** power info for MLAN_OID_PM_INFO */ + mlan_ds_ps_info ps_info; + } param; +} mlan_ds_pm_cfg, *pmlan_ds_pm_cfg; + +/*-----------------------------------------------------------------*/ +/** WMM Configuration Group */ +/*-----------------------------------------------------------------*/ + +/** WMM TSpec size */ +#define MLAN_WMM_TSPEC_SIZE 63 +/** WMM Add TS extra IE bytes */ +#define MLAN_WMM_ADDTS_EXTRA_IE_BYTES 256 +/** WMM statistics for packets hist bins */ +#define MLAN_WMM_STATS_PKTS_HIST_BINS 7 +/** Maximum number of AC QOS queues available */ +#define MLAN_WMM_MAX_AC_QUEUES 4 + +/** + * @brief IOCTL structure to send an ADDTS request and retrieve the response. + * + * IOCTL structure from the application layer relayed to firmware to + * instigate an ADDTS management frame with an appropriate TSPEC IE as well + * as any additional IEs appended in the ADDTS Action frame. + * + * @sa woal_wmm_addts_req_ioctl + */ +typedef struct +{ + mlan_cmd_result_e cmd_result; /**< Firmware execution result */ + + t_u32 timeout_ms; /**< Timeout value in milliseconds */ + t_u8 ieee_status_code; /**< IEEE status code */ + + t_u32 ie_data_len; /**< Length of ie block in ie_data */ + t_u8 ie_data[MLAN_WMM_TSPEC_SIZE /**< TSPEC to send in the ADDTS */ + + MLAN_WMM_ADDTS_EXTRA_IE_BYTES]; /**< Extra IE buf*/ +} wlan_ioctl_wmm_addts_req_t; + +/** + * @brief IOCTL structure to send a DELTS request. + * + * IOCTL structure from the application layer relayed to firmware to + * instigate an DELTS management frame with an appropriate TSPEC IE. + * + * @sa woal_wmm_delts_req_ioctl + */ +typedef struct +{ + mlan_cmd_result_e cmd_result; /**< Firmware execution result */ + t_u8 ieee_reason_code; /**< IEEE reason code sent, unused for WMM */ + t_u32 ie_data_len; /**< Length of ie block in ie_data */ + t_u8 ie_data[MLAN_WMM_TSPEC_SIZE]; /**< TSPEC to send in the DELTS */ +} wlan_ioctl_wmm_delts_req_t; + +/** + * @brief IOCTL structure to configure a specific AC Queue's parameters + * + * IOCTL structure from the application layer relayed to firmware to + * get, set, or default the WMM AC queue parameters. + * + * - msdu_lifetime_expiry is ignored if set to 0 on a set command + * + * @sa woal_wmm_queue_config_ioctl + */ +typedef struct +{ + mlan_wmm_queue_config_action_e action; /**< Set, Get, or Default */ + mlan_wmm_ac_e access_category; /**< WMM_AC_BK(0) to WMM_AC_VO(3) */ + t_u16 msdu_lifetime_expiry; /**< lifetime expiry in TUs */ + t_u8 supported_rates[10]; /**< Not supported yet */ +} wlan_ioctl_wmm_queue_config_t; + +/** + * @brief IOCTL structure to start, stop, and get statistics for a WMM AC + * + * IOCTL structure from the application layer relayed to firmware to + * start or stop statistical collection for a given AC. Also used to + * retrieve and clear the collected stats on a given AC. + * + * @sa woal_wmm_queue_stats_ioctl + */ +typedef struct +{ + /** Action of Queue Config : Start, Stop, or Get */ + mlan_wmm_queue_stats_action_e action; + /** User Priority */ + t_u8 user_priority; + /** Number of successful packets transmitted */ + t_u16 pkt_count; + /** Packets lost; not included in pkt_count */ + t_u16 pkt_loss; + /** Average Queue delay in microseconds */ + t_u32 avg_queue_delay; + /** Average Transmission delay in microseconds */ + t_u32 avg_tx_delay; + /** Calculated used time in units of 32 microseconds */ + t_u16 used_time; + /** Calculated policed time in units of 32 microseconds */ + t_u16 policed_time; + /** Queue Delay Histogram; number of packets per queue delay range + * + * [0] - 0ms <= delay < 5ms + * [1] - 5ms <= delay < 10ms + * [2] - 10ms <= delay < 20ms + * [3] - 20ms <= delay < 30ms + * [4] - 30ms <= delay < 40ms + * [5] - 40ms <= delay < 50ms + * [6] - 50ms <= delay < msduLifetime (TUs) + */ + t_u16 delay_histogram[MLAN_WMM_STATS_PKTS_HIST_BINS]; +} wlan_ioctl_wmm_queue_stats_t, +/** Type definition of mlan_ds_wmm_queue_stats for MLAN_OID_WMM_CFG_QUEUE_STATS */ + mlan_ds_wmm_queue_stats, *pmlan_ds_wmm_queue_stats; + +/** + * @brief IOCTL sub structure for a specific WMM AC Status + */ +typedef struct +{ + /** WMM Acm */ + t_u8 wmm_acm; + /** Flow required flag */ + t_u8 flow_required; + /** Flow created flag */ + t_u8 flow_created; + /** Disabled flag */ + t_u8 disabled; +} wlan_ioctl_wmm_queue_status_ac_t; + +/** + * @brief IOCTL structure to retrieve the WMM AC Queue status + * + * IOCTL structure from the application layer to retrieve: + * - ACM bit setting for the AC + * - Firmware status (flow required, flow created, flow disabled) + * + * @sa woal_wmm_queue_status_ioctl + */ +typedef struct +{ + /** WMM AC queue status */ + wlan_ioctl_wmm_queue_status_ac_t ac_status[MLAN_WMM_MAX_AC_QUEUES]; +} wlan_ioctl_wmm_queue_status_t, +/** Type definition of mlan_ds_wmm_queue_status for MLAN_OID_WMM_CFG_QUEUE_STATUS */ + mlan_ds_wmm_queue_status, *pmlan_ds_wmm_queue_status; + +/** Type definition of mlan_ds_wmm_addts for MLAN_OID_WMM_CFG_ADDTS */ +typedef struct _mlan_ds_wmm_addts +{ + /** Result of ADDTS request */ + mlan_cmd_result_e result; + /** Timeout value in milliseconds */ + t_u32 timeout; + /** IEEE status code */ + t_u32 status_code; + /** Dialog token */ + t_u8 dialog_tok; + /** TSPEC data length */ + t_u8 ie_data_len; + /** TSPEC to send in the ADDTS + buffering for any extra IEs */ + t_u8 ie_data[MLAN_WMM_TSPEC_SIZE + MLAN_WMM_ADDTS_EXTRA_IE_BYTES]; +} mlan_ds_wmm_addts, *pmlan_ds_wmm_addts; + +/** Type definition of mlan_ds_wmm_delts for MLAN_OID_WMM_CFG_DELTS */ +typedef struct _mlan_ds_wmm_delts +{ + /** Result of DELTS request */ + mlan_cmd_result_e result; + /** IEEE status code */ + t_u32 status_code; + /** TSPEC data length */ + t_u8 ie_data_len; + /** TSPEC to send in the DELTS */ + t_u8 ie_data[MLAN_WMM_TSPEC_SIZE]; +} mlan_ds_wmm_delts, *pmlan_ds_wmm_delts; + +/** Type definition of mlan_ds_wmm_queue_config for MLAN_OID_WMM_CFG_QUEUE_CONFIG */ +typedef struct _mlan_ds_wmm_queue_config +{ + /** Action of Queue Config : Set, Get, or Default */ + mlan_wmm_queue_config_action_e action; + /** WMM Access Category: WMM_AC_BK(0) to WMM_AC_VO(3) */ + mlan_wmm_ac_e access_category; + /** Lifetime expiry in TUs */ + t_u16 msdu_lifetime_expiry; + /** Reserve for future use */ + t_u8 reserved[10]; +} mlan_ds_wmm_queue_config, *pmlan_ds_wmm_queue_config; + +/** Type definition of mlan_ds_wmm_cfg for MLAN_IOCTL_WMM_CFG */ +typedef struct _mlan_ds_wmm_cfg +{ + /** Sub-command */ + t_u32 sub_command; + /** WMM configuration parameter */ + union + { + /** WMM enable for MLAN_OID_WMM_CFG_ENABLE */ + t_u32 wmm_enable; + /** QoS configuration for MLAN_OID_WMM_CFG_QOS */ + t_u8 qos_cfg; + /** WMM add TS for MLAN_OID_WMM_CFG_ADDTS */ + mlan_ds_wmm_addts addts; + /** WMM delete TS for MLAN_OID_WMM_CFG_DELTS */ + mlan_ds_wmm_delts delts; + /** WMM queue configuration for MLAN_OID_WMM_CFG_QUEUE_CONFIG */ + mlan_ds_wmm_queue_config q_cfg; + /** WMM queue status for MLAN_OID_WMM_CFG_QUEUE_STATS */ + mlan_ds_wmm_queue_stats q_stats; + /** WMM queue status for MLAN_OID_WMM_CFG_QUEUE_STATUS */ + mlan_ds_wmm_queue_status q_status; + /** WMM TS status for MLAN_OID_WMM_CFG_TS_STATUS */ + mlan_ds_wmm_ts_status ts_status; + } param; +} mlan_ds_wmm_cfg, *pmlan_ds_wmm_cfg; + +/*-----------------------------------------------------------------*/ +/** WPS Configuration Group */ +/*-----------------------------------------------------------------*/ +/** Enumeration for WPS session */ +enum _mlan_wps_status +{ + MLAN_WPS_CFG_SESSION_START = 1, + MLAN_WPS_CFG_SESSION_END = 0 +}; + +/** Type definition of mlan_ds_wps_cfg for MLAN_IOCTL_WPS_CFG */ +typedef struct _mlan_ds_wps_cfg +{ + /** Sub-command */ + t_u32 sub_command; + /** WPS configuration parameter */ + union + { + /** WPS session for MLAN_OID_WPS_CFG_SESSION */ + t_u32 wps_session; + } param; +} mlan_ds_wps_cfg, *pmlan_ds_wps_cfg; + +/*-----------------------------------------------------------------*/ +/** 802.11n Configuration Group */ +/*-----------------------------------------------------------------*/ +/** Maximum MCS */ +#define NUM_MCS_FIELD 16 + +/** Supported stream modes */ +#define HT_STREAM_MODE_1X1 0x11 +#define HT_STREAM_MODE_2X2 0x22 + +/* Both 2.4G and 5G band selected */ +#define BAND_SELECT_BOTH 0 +/* Band 2.4G selected */ +#define BAND_SELECT_BG 1 +/* Band 5G selected */ +#define BAND_SELECT_A 2 + +/** Type definition of mlan_ds_11n_htcap_cfg for MLAN_OID_11N_HTCAP_CFG */ +typedef struct _mlan_ds_11n_htcap_cfg +{ + /** HT Capability information */ + t_u32 htcap; + /** Band selection */ + t_u32 misc_cfg; + /** Hardware HT cap information required */ + t_u32 hw_cap_req; +} mlan_ds_11n_htcap_cfg, *pmlan_ds_11n_htcap_cfg; + +/** Type definition of mlan_ds_11n_addba_param for MLAN_OID_11N_CFG_ADDBA_PARAM */ +typedef struct _mlan_ds_11n_addba_param +{ + /** Timeout */ + t_u32 timeout; + /** Buffer size for ADDBA request */ + t_u32 txwinsize; + /** Buffer size for ADDBA response */ + t_u32 rxwinsize; + /** amsdu for ADDBA request */ + t_u8 txamsdu; + /** amsdu for ADDBA response */ + t_u8 rxamsdu; +} mlan_ds_11n_addba_param, *pmlan_ds_11n_addba_param; + +/** Type definition of mlan_ds_11n_tx_cfg for MLAN_OID_11N_CFG_TX */ +typedef struct _mlan_ds_11n_tx_cfg +{ + /** HTTxCap */ + t_u16 httxcap; + /** HTTxInfo */ + t_u16 httxinfo; + /** Band selection */ + t_u32 misc_cfg; +} mlan_ds_11n_tx_cfg, *pmlan_ds_11n_tx_cfg; + +/** BF Global Configuration */ +#define BF_GLOBAL_CONFIGURATION 0x00 +/** Performs NDP sounding for PEER specified */ +#define TRIGGER_SOUNDING_FOR_PEER 0x01 +/** TX BF interval for channel sounding */ +#define SET_GET_BF_PERIODICITY 0x02 +/** Tell FW not to perform any sounding for peer */ +#define TX_BF_FOR_PEER_ENBL 0x03 +/** TX BF SNR threshold for peer */ +#define SET_SNR_THR_PEER 0x04 + +/* Maximum number of peer MAC and status/SNR tuples */ +#define MAX_PEER_MAC_TUPLES 10 + +/** Any new subcommand structure should be declare here */ + +/** bf global cfg args */ +typedef struct _mlan_bf_global_cfg_args +{ + /** Global enable/disable bf */ + t_u8 bf_enbl; + /** Global enable/disable sounding */ + t_u8 sounding_enbl; + /** FB Type */ + t_u8 fb_type; + /** SNR Threshold */ + t_u8 snr_threshold; + /** Sounding interval in milliseconds */ + t_u16 sounding_interval; + /** BF mode */ + t_u8 bf_mode; + /** Reserved */ + t_u8 reserved; +} mlan_bf_global_cfg_args; + +/** trigger sounding args */ +typedef struct _mlan_trigger_sound_args +{ + /** Peer MAC address */ + t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH]; + /** Status */ + t_u8 status; +} mlan_trigger_sound_args; + +/** bf periodicity args */ +typedef struct _mlan_bf_periodicity_args +{ + /** Peer MAC address */ + t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH]; + /** Current Tx BF Interval in milliseconds */ + t_u16 interval; + /** Status */ + t_u8 status; +} mlan_bf_periodicity_args; + +/** tx bf peer args */ +typedef struct _mlan_tx_bf_peer_args +{ + /** Peer MAC address */ + t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH]; + /** Reserved */ + t_u16 reserved; + /** Enable/Disable Beamforming */ + t_u8 bf_enbl; + /** Enable/Disable sounding */ + t_u8 sounding_enbl; + /** FB Type */ + t_u8 fb_type; +} mlan_tx_bf_peer_args; + +/** SNR threshold args */ +typedef struct _mlan_snr_thr_args +{ + /** Peer MAC address */ + t_u8 peer_mac[MLAN_MAC_ADDR_LENGTH]; + /** SNR for peer */ + t_u8 snr; +} mlan_snr_thr_args; + +/** Type definition of mlan_ds_11n_tx_bf_cfg for MLAN_OID_11N_CFG_TX_BF_CFG */ +typedef struct _mlan_ds_11n_tx_bf_cfg +{ + /** BF Action */ + t_u16 bf_action; + /** Action */ + t_u16 action; + /** Number of peers */ + t_u32 no_of_peers; + union + { + mlan_bf_global_cfg_args bf_global_cfg; + mlan_trigger_sound_args bf_sound[MAX_PEER_MAC_TUPLES]; + mlan_bf_periodicity_args bf_periodicity[MAX_PEER_MAC_TUPLES]; + mlan_tx_bf_peer_args tx_bf_peer[MAX_PEER_MAC_TUPLES]; + mlan_snr_thr_args bf_snr[MAX_PEER_MAC_TUPLES]; + } body; +} mlan_ds_11n_tx_bf_cfg, *pmlan_ds_11n_tx_bf_cfg; + +/** Type definition of mlan_ds_11n_amsdu_aggr_ctrl for + * MLAN_OID_11N_AMSDU_AGGR_CTRL*/ +typedef struct _mlan_ds_11n_amsdu_aggr_ctrl +{ + /** Enable/Disable */ + t_u16 enable; + /** Current AMSDU size valid */ + t_u16 curr_buf_size; +} mlan_ds_11n_amsdu_aggr_ctrl, *pmlan_ds_11n_amsdu_aggr_ctrl; + +/** Type definition of mlan_ds_11n_aggr_prio_tbl for MLAN_OID_11N_CFG_AGGR_PRIO_TBL */ +typedef struct _mlan_ds_11n_aggr_prio_tbl +{ + /** ampdu priority table */ + t_u8 ampdu[MAX_NUM_TID]; + /** amsdu priority table */ + t_u8 amsdu[MAX_NUM_TID]; +} mlan_ds_11n_aggr_prio_tbl, *pmlan_ds_11n_aggr_prio_tbl; + +/** Type definition of mlan_ds_11n_cfg for MLAN_IOCTL_11N_CFG */ +typedef struct _mlan_ds_11n_cfg +{ + /** Sub-command */ + t_u32 sub_command; + /** 802.11n configuration parameter */ + union + { + /** Tx param for 11n for MLAN_OID_11N_CFG_TX */ + mlan_ds_11n_tx_cfg tx_cfg; + /** Aggr priority table for MLAN_OID_11N_CFG_AGGR_PRIO_TBL */ + mlan_ds_11n_aggr_prio_tbl aggr_prio_tbl; + /** Add BA param for MLAN_OID_11N_CFG_ADDBA_PARAM */ + mlan_ds_11n_addba_param addba_param; + /** Add BA Reject paramters for MLAN_OID_11N_CFG_ADDBA_REJECT */ + t_u8 addba_reject[MAX_NUM_TID]; + /** Tx buf size for MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE */ + t_u32 tx_buf_size; + /** HT cap info configuration for MLAN_OID_11N_HTCAP_CFG */ + mlan_ds_11n_htcap_cfg htcap_cfg; + /** Tx param for 11n for MLAN_OID_11N_AMSDU_AGGR_CTRL */ + mlan_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl; + /** Supported MCS Set field */ + t_u8 supported_mcs_set[NUM_MCS_FIELD]; + /** Transmit Beamforming Capabilities field */ + t_u32 tx_bf_cap; + /** Transmit Beamforming configuration */ + mlan_ds_11n_tx_bf_cfg tx_bf; + /** HT stream configuration */ + t_u32 stream_cfg; + } param; +} mlan_ds_11n_cfg, *pmlan_ds_11n_cfg; + +/** Country code length */ +#define COUNTRY_CODE_LEN 3 + +/*-----------------------------------------------------------------*/ +/** 802.11d Configuration Group */ +/*-----------------------------------------------------------------*/ +/** Maximum subbands for 11d */ +#define MRVDRV_MAX_SUBBAND_802_11D 83 + +#ifdef STA_SUPPORT +/** Data structure for subband set */ +typedef struct _mlan_ds_subband_set_t +{ + /** First channel */ + t_u8 first_chan; + /** Number of channels */ + t_u8 no_of_chan; + /** Maximum Tx power in dBm */ + t_u8 max_tx_pwr; +} mlan_ds_subband_set_t; + +/** Domain regulatory information */ +typedef struct _mlan_ds_11d_domain_info +{ + /** Country Code */ + t_u8 country_code[COUNTRY_CODE_LEN]; + /** Band that channels in sub_band belong to */ + t_u8 band; + /** No. of subband in below */ + t_u8 no_of_sub_band; + /** Subband data to send/last sent */ + mlan_ds_subband_set_t sub_band[MRVDRV_MAX_SUBBAND_802_11D]; +} mlan_ds_11d_domain_info; +#endif + +/** Type definition of mlan_ds_11d_cfg for MLAN_IOCTL_11D_CFG */ +typedef struct _mlan_ds_11d_cfg +{ + /** Sub-command */ + t_u32 sub_command; + /** 802.11d configuration parameter */ + union + { +#ifdef STA_SUPPORT + /** Enable for MLAN_OID_11D_CFG_ENABLE */ + t_u32 enable_11d; + /** Domain info for MLAN_OID_11D_DOMAIN_INFO */ + mlan_ds_11d_domain_info domain_info; +#endif /* STA_SUPPORT */ +#ifdef UAP_SUPPORT + /** tlv data for MLAN_OID_11D_DOMAIN_INFO */ + t_u8 domain_tlv[MAX_IE_SIZE]; +#endif /* UAP_SUPPORT */ + } param; +} mlan_ds_11d_cfg, *pmlan_ds_11d_cfg; + +/*-----------------------------------------------------------------*/ +/** Register Memory Access Group */ +/*-----------------------------------------------------------------*/ +/** Enumeration for register type */ +enum _mlan_reg_type +{ + MLAN_REG_MAC = 1, + MLAN_REG_BBP, + MLAN_REG_RF, + MLAN_REG_CAU = 5, +}; + +/** Type definition of mlan_ds_reg_rw for MLAN_OID_REG_RW */ +typedef struct _mlan_ds_reg_rw +{ + /** Register type */ + t_u32 type; + /** Offset */ + t_u32 offset; + /** Value */ + t_u32 value; +} mlan_ds_reg_rw; + +/** Maximum EEPROM data */ +#define MAX_EEPROM_DATA 256 + +/** Type definition of mlan_ds_read_eeprom for MLAN_OID_EEPROM_RD */ +typedef struct _mlan_ds_read_eeprom +{ + /** Multiples of 4 */ + t_u16 offset; + /** Number of bytes */ + t_u16 byte_count; + /** Value */ + t_u8 value[MAX_EEPROM_DATA]; +} mlan_ds_read_eeprom; + +/** Type definition of mlan_ds_mem_rw for MLAN_OID_MEM_RW */ +typedef struct _mlan_ds_mem_rw +{ + /** Address */ + t_u32 addr; + /** Value */ + t_u32 value; +} mlan_ds_mem_rw; + +/** Type definition of mlan_ds_reg_mem for MLAN_IOCTL_REG_MEM */ +typedef struct _mlan_ds_reg_mem +{ + /** Sub-command */ + t_u32 sub_command; + /** Register memory access parameter */ + union + { + /** Register access for MLAN_OID_REG_RW */ + mlan_ds_reg_rw reg_rw; + /** EEPROM access for MLAN_OID_EEPROM_RD */ + mlan_ds_read_eeprom rd_eeprom; + /** Memory access for MLAN_OID_MEM_RW */ + mlan_ds_mem_rw mem_rw; + } param; +} mlan_ds_reg_mem, *pmlan_ds_reg_mem; + +/*-----------------------------------------------------------------*/ +/** Multi-Radio Configuration Group */ +/*-----------------------------------------------------------------*/ + +/*-----------------------------------------------------------------*/ +/** 802.11h Configuration Group */ +/*-----------------------------------------------------------------*/ +#if defined(DFS_TESTING_SUPPORT) +/** Type definition of mlan_ds_11h_dfs_testing for MLAN_OID_11H_DFS_TESTING */ +typedef struct _mlan_ds_11h_dfs_testing +{ + /** User-configured CAC period in milliseconds, 0 to use default */ + t_u16 usr_cac_period_msec; + /** User-configured NOP period in seconds, 0 to use default */ + t_u16 usr_nop_period_sec; + /** User-configured skip channel change, 0 to disable */ + t_u8 usr_no_chan_change; + /** User-configured fixed channel to change to, 0 to use random channel */ + t_u8 usr_fixed_new_chan; +} mlan_ds_11h_dfs_testing, *pmlan_ds_11h_dfs_testing; +#endif + +/** Type definition of mlan_ds_11h_cfg for MLAN_IOCTL_11H_CFG */ +typedef struct _mlan_ds_11h_cfg +{ + /** Sub-command */ + t_u32 sub_command; + union + { + /** Local power constraint for MLAN_OID_11H_LOCAL_POWER_CONSTRAINT */ + t_s8 usr_local_power_constraint; +#if defined(DFS_TESTING_SUPPORT) + /** User-configuation for MLAN_OID_11H_DFS_TESTING */ + mlan_ds_11h_dfs_testing dfs_testing; +#endif + } param; +} mlan_ds_11h_cfg, *pmlan_ds_11h_cfg; + +/*-----------------------------------------------------------------*/ +/** Miscellaneous Configuration Group */ +/*-----------------------------------------------------------------*/ + +/** CMD buffer size */ +#define MLAN_SIZE_OF_CMD_BUFFER 2048 + +/** LDO Internal */ +#define LDO_INTERNAL 0 +/** LDO External */ +#define LDO_EXTERNAL 1 + +/** Enumeration for IE type */ +enum _mlan_ie_type +{ + MLAN_IE_TYPE_GEN_IE = 0, +#ifdef STA_SUPPORT + MLAN_IE_TYPE_ARP_FILTER, +#endif /* STA_SUPPORT */ +}; + +/** Type definition of mlan_ds_misc_gen_ie for MLAN_OID_MISC_GEN_IE */ +typedef struct _mlan_ds_misc_gen_ie +{ + /** IE type */ + t_u32 type; + /** IE length */ + t_u32 len; + /** IE buffer */ + t_u8 ie_data[MAX_IE_SIZE]; +} mlan_ds_misc_gen_ie; + +#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR) +/** Type definition of mlan_ds_misc_sdio_mpa_ctrl for MLAN_OID_MISC_SDIO_MPA_CTRL */ +typedef struct _mlan_ds_misc_sdio_mpa_ctrl +{ + /** SDIO MP-A TX enable/disable */ + t_u16 tx_enable; + /** SDIO MP-A RX enable/disable */ + t_u16 rx_enable; + /** SDIO MP-A TX buf size */ + t_u16 tx_buf_size; + /** SDIO MP-A RX buf size */ + t_u16 rx_buf_size; + /** SDIO MP-A TX Max Ports */ + t_u16 tx_max_ports; + /** SDIO MP-A RX Max Ports */ + t_u16 rx_max_ports; +} mlan_ds_misc_sdio_mpa_ctrl; +#endif + +/** Type definition of mlan_ds_misc_cmd for MLAN_OID_MISC_HOST_CMD */ +typedef struct _mlan_ds_misc_cmd +{ + /** Command length */ + t_u32 len; + /** Command buffer */ + t_u8 cmd[MLAN_SIZE_OF_CMD_BUFFER]; +} mlan_ds_misc_cmd; + +/** Maximum number of system clocks */ +#define MLAN_MAX_CLK_NUM 16 + +/** Clock type : Configurable */ +#define MLAN_CLK_CONFIGURABLE 0 +/** Clock type : Supported */ +#define MLAN_CLK_SUPPORTED 1 + +/** Type definition of mlan_ds_misc_sys_clock for MLAN_OID_MISC_SYS_CLOCK */ +typedef struct _mlan_ds_misc_sys_clock +{ + /** Current system clock */ + t_u16 cur_sys_clk; + /** Clock type */ + t_u16 sys_clk_type; + /** Number of clocks */ + t_u16 sys_clk_num; + /** System clocks */ + t_u16 sys_clk[MLAN_MAX_CLK_NUM]; +} mlan_ds_misc_sys_clock; + +/** Enumeration for function init/shutdown */ +enum _mlan_func_cmd +{ + MLAN_FUNC_INIT = 1, + MLAN_FUNC_SHUTDOWN, +}; + +/** Type definition of mlan_ds_misc_tx_datapause for MLAN_OID_MISC_TX_DATAPAUSE */ +typedef struct _mlan_ds_misc_tx_datapause +{ + /** Tx data pause flag */ + t_u16 tx_pause; + /** Max number of Tx buffers for all PS clients */ + t_u16 tx_buf_cnt; +} mlan_ds_misc_tx_datapause; + +/** IP address length */ +#define IPADDR_LEN (16) +/** Max number of ip */ +#define MAX_IPADDR (4) +/** IP address type - IPv4*/ +#define IPADDR_TYPE_IPV4 (1) +/** IP operation remove */ +#define MLAN_IPADDR_OP_IP_REMOVE (0) +/** IP operation ARP filter */ +#define MLAN_IPADDR_OP_ARP_FILTER MBIT(0) +/** IP operation ARP response */ +#define MLAN_IPADDR_OP_AUTO_ARP_RESP MBIT(1) + +/** Type definition of mlan_ds_misc_ipaddr_cfg for MLAN_OID_MISC_IP_ADDR */ +typedef struct _mlan_ds_misc_ipaddr_cfg +{ + /** Operation code */ + t_u32 op_code; + /** IP address type */ + t_u32 ip_addr_type; + /** Number of IP */ + t_u32 ip_addr_num; + /** IP address */ + t_u8 ip_addr[MAX_IPADDR][IPADDR_LEN]; +} mlan_ds_misc_ipaddr_cfg; + +/* MEF configuration disable */ +#define MEF_CFG_DISABLE 0 +/* MEF configuration Rx filter enable */ +#define MEF_CFG_RX_FILTER_ENABLE 1 +/* MEF configuration auto ARP response */ +#define MEF_CFG_AUTO_ARP_RESP 2 +/* MEF configuration host command */ +#define MEF_CFG_HOSTCMD 0xFFFF + +/** Type definition of mlan_ds_misc_mef_cfg for MLAN_OID_MISC_MEF_CFG */ +typedef struct _mlan_ds_misc_mef_cfg +{ + /** Sub-ID for operation */ + t_u32 sub_id; + /** Parameter according to sub-ID */ + union + { + /** MEF command buffer for MEF_CFG_HOSTCMD */ + mlan_ds_misc_cmd cmd_buf; + } param; +} mlan_ds_misc_mef_cfg; + +/** Type definition of mlan_ds_misc_cfp_code for MLAN_OID_MISC_CFP_CODE */ +typedef struct _mlan_ds_misc_cfp_code +{ + /** CFP table code for 2.4GHz */ + t_u32 cfp_code_bg; + /** CFP table code for 5GHz */ + t_u32 cfp_code_a; +} mlan_ds_misc_cfp_code; + +/** Type definition of mlan_ds_misc_country_code for MLAN_OID_MISC_COUNTRY_CODE */ +typedef struct _mlan_ds_misc_country_code +{ + /** Country Code */ + t_u8 country_code[COUNTRY_CODE_LEN]; +} mlan_ds_misc_country_code; + +/** BITMAP for subscribe event rssi low */ +#define SUBSCRIBE_EVT_RSSI_LOW MBIT(0) +/** BITMAP for subscribe event snr low */ +#define SUBSCRIBE_EVT_SNR_LOW MBIT(1) +/** BITMAP for subscribe event max fail */ +#define SUBSCRIBE_EVT_MAX_FAIL MBIT(2) +/** BITMAP for subscribe event beacon missed */ +#define SUBSCRIBE_EVT_BEACON_MISSED MBIT(3) +/** BITMAP for subscribe event rssi high */ +#define SUBSCRIBE_EVT_RSSI_HIGH MBIT(4) +/** BITMAP for subscribe event snr high */ +#define SUBSCRIBE_EVT_SNR_HIGH MBIT(5) +/** BITMAP for subscribe event data rssi low */ +#define SUBSCRIBE_EVT_DATA_RSSI_LOW MBIT(6) +/** BITMAP for subscribe event data snr low */ +#define SUBSCRIBE_EVT_DATA_SNR_LOW MBIT(7) +/** BITMAP for subscribe event data rssi high */ +#define SUBSCRIBE_EVT_DATA_RSSI_HIGH MBIT(8) +/** BITMAP for subscribe event data snr high */ +#define SUBSCRIBE_EVT_DATA_SNR_HIGH MBIT(9) +/** BITMAP for subscribe event link quality */ +#define SUBSCRIBE_EVT_LINK_QUALITY MBIT(10) +/** BITMAP for subscribe event pre_beacon_lost */ +#define SUBSCRIBE_EVT_PRE_BEACON_LOST MBIT(11) +/** default PRE_BEACON_MISS_COUNT */ +#define DEFAULT_PRE_BEACON_MISS 30 + +/** Type definition of mlan_ds_subscribe_evt for MLAN_OID_MISC_CFP_CODE */ +typedef struct _mlan_ds_subscribe_evt +{ + /** bitmap for subscribe event */ + t_u16 evt_bitmap; + /** Absolute value of RSSI threshold value (dBm) */ + t_u8 low_rssi; + /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */ + t_u8 low_rssi_freq; + /** SNR threshold value (dB) */ + t_u8 low_snr; + /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */ + t_u8 low_snr_freq; + /** Failure count threshold */ + t_u8 failure_count; + /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */ + t_u8 failure_count_freq; + /** num of missed beacons */ + t_u8 beacon_miss; + /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */ + t_u8 beacon_miss_freq; + /** Absolute value of RSSI threshold value (dBm) */ + t_u8 high_rssi; + /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */ + t_u8 high_rssi_freq; + /** SNR threshold value (dB) */ + t_u8 high_snr; + /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */ + t_u8 high_snr_freq; + /** Absolute value of data RSSI threshold value (dBm) */ + t_u8 data_low_rssi; + /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */ + t_u8 data_low_rssi_freq; + /** Absolute value of data SNR threshold value (dBm) */ + t_u8 data_low_snr; + /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */ + t_u8 data_low_snr_freq; + /** Absolute value of data RSSI threshold value (dBm) */ + t_u8 data_high_rssi; + /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */ + t_u8 data_high_rssi_freq; + /** Absolute value of data SNR threshold value (dBm) */ + t_u8 data_high_snr; + /** 0--report once, 1--report everytime happen, N -- report only happend > N consecutive times */ + t_u8 data_high_snr_freq; + /* Link SNR threshold (dB) */ + t_u16 link_snr; + /* Link SNR frequency */ + t_u16 link_snr_freq; + /* Second minimum rate value as per the rate table below */ + t_u16 link_rate; + /* Second minimum rate frequency */ + t_u16 link_rate_freq; + /* Tx latency value (us) */ + t_u16 link_tx_latency; + /* Tx latency frequency */ + t_u16 link_tx_lantency_freq; + /* Number of pre missed beacons */ + t_u8 pre_beacon_miss; +} mlan_ds_subscribe_evt; + +/** Max OTP user data length */ +#define MAX_OTP_USER_DATA_LEN 252 + +/** Type definition of mlan_ds_misc_otp_user_data for MLAN_OID_MISC_OTP_USER_DATA */ +typedef struct _mlan_ds_misc_otp_user_data +{ + /** Reserved */ + t_u16 reserved; + /** OTP user data length */ + t_u16 user_data_length; + /** User data buffer */ + t_u8 user_data[MAX_OTP_USER_DATA_LEN]; +} mlan_ds_misc_otp_user_data; + +/** Type definition of mlan_ds_misc_cfg for MLAN_IOCTL_MISC_CFG */ +typedef struct _mlan_ds_misc_cfg +{ + /** Sub-command */ + t_u32 sub_command; + /** Miscellaneous configuration parameter */ + union + { + /** Generic IE for MLAN_OID_MISC_GEN_IE */ + mlan_ds_misc_gen_ie gen_ie; + /** Region code for MLAN_OID_MISC_REGION */ + t_u32 region_code; +#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR) + /** SDIO MP-A Ctrl command for MLAN_OID_MISC_SDIO_MPA_CTRL */ + mlan_ds_misc_sdio_mpa_ctrl mpa_ctrl; +#endif + /** Hostcmd for MLAN_OID_MISC_HOST_CMD */ + mlan_ds_misc_cmd hostcmd; + /** System clock for MLAN_OID_MISC_SYS_CLOCK */ + mlan_ds_misc_sys_clock sys_clock; + /** WWS set/get for MLAN_OID_MISC_WWS */ + t_u32 wws_cfg; + /** Function init/shutdown for MLAN_OID_MISC_INIT_SHUTDOWN */ + t_u32 func_init_shutdown; + /** Custom IE for MLAN_OID_MISC_CUSTOM_IE */ + mlan_ds_misc_custom_ie cust_ie; + /** Tx data pause for MLAN_OID_MISC_TX_DATAPAUSE */ + mlan_ds_misc_tx_datapause tx_datapause; + /** IP address configuration */ + mlan_ds_misc_ipaddr_cfg ipaddr_cfg; + /** MAC control for MLAN_OID_MISC_MAC_CONTROL */ + t_u32 mac_ctrl; + /** MEF configuration for MLAN_OID_MISC_MEF_CFG */ + mlan_ds_misc_mef_cfg mef_cfg; + /** CFP code for MLAN_OID_MISC_CFP_CODE */ + mlan_ds_misc_cfp_code cfp_code; + /** Country code for MLAN_OID_MISC_COUNTRY_CODE */ + mlan_ds_misc_country_code country_code; + /** Thermal reading for MLAN_OID_MISC_THERMAL */ + t_u32 thermal; + /** Mgmt subtype mask for MLAN_OID_MISC_RX_MGMT_IND */ + t_u32 mgmt_subtype_mask; + /** subscribe event for MLAN_OID_MISC_SUBSCRIBE_EVENT */ + mlan_ds_subscribe_evt subscribe_event; +#ifdef DEBUG_LEVEL1 + /** Driver debug bit masks */ + t_u32 drvdbg; +#endif + mlan_ds_misc_otp_user_data otp_user_data; + } param; +} mlan_ds_misc_cfg, *pmlan_ds_misc_cfg; + +#endif /* !_MLAN_IOCTL_H_ */ diff --git a/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c b/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c index 1b04db6b4da0..6b2a01f5c218 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.c @@ -163,6 +163,19 @@ woal_get_wiphy_priv(struct wiphy *wiphy) return (void *) (*(unsigned long *) wiphy_priv(wiphy)); } +/** + * @brief Get the private structure from net device + * + * @param wiphy A pointer to net_device structure + * + * @return Pointer to moal_private + */ +void * +woal_get_netdev_priv(struct net_device *dev) +{ + return (void *) netdev_priv(dev); +} + /** * @brief Set/Enable encryption key * @@ -270,8 +283,12 @@ woal_cfg80211_set_key(moal_private * priv, t_u8 is_enable_wep, } } } else { - sec->param.encrypt_key.key_remove = MTRUE; - sec->param.encrypt_key.key_index = key_index; + if (key_index == KEY_INDEX_CLEAR_ALL) + sec->param.encrypt_key.key_disable = MTRUE; + else { + sec->param.encrypt_key.key_remove = MTRUE; + sec->param.encrypt_key.key_index = key_index; + } sec->param.encrypt_key.key_flags = KEY_FLAG_REMOVE_KEY; if (addr) memcpy(sec->param.encrypt_key.mac_addr, addr, ETH_ALEN); @@ -343,96 +360,30 @@ static int woal_cfg80211_bss_role_cfg(moal_private * priv, t_u16 action, t_u8 * bss_role) { int ret = 0; - mlan_ds_bss *bss = NULL; - mlan_ioctl_req *req = NULL; - struct net_device *dev = priv->netdev; ENTER(); - req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); - if (req == NULL) { - ret = -ENOMEM; - goto done; - } - bss = (mlan_ds_bss *) req->pbuf; - bss->sub_command = MLAN_OID_BSS_ROLE; - req->req_id = MLAN_IOCTL_BSS; - req->action = action; - bss->param.bss_role = *bss_role; - - if (req->action == MLAN_ACT_SET) { + if (action == MLAN_ACT_SET) { /* Reset interface */ woal_reset_intf(priv, MOAL_IOCTL_WAIT, MFALSE); } - if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + + if (MLAN_STATUS_SUCCESS != + woal_bss_role_cfg(priv, action, MOAL_IOCTL_WAIT, bss_role)) { ret = -EFAULT; goto done; } - if (req->action == MLAN_ACT_GET) { - *bss_role = bss->param.bss_role; - } else { - /* Update moal_private */ - priv->bss_role = *bss_role; - if (priv->bss_type == MLAN_BSS_TYPE_UAP) - priv->bss_type = MLAN_BSS_TYPE_STA; - else if (priv->bss_type == MLAN_BSS_TYPE_STA) - priv->bss_type = MLAN_BSS_TYPE_UAP; - + if (action == MLAN_ACT_SET) { /* Initialize private structures */ woal_init_priv(priv, MOAL_IOCTL_WAIT); - if (*bss_role == MLAN_BSS_ROLE_UAP) { - /* Switch: STA -> uAP */ - /* Setup the OS Interface to our functions */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) - dev->do_ioctl = woal_uap_do_ioctl; - dev->set_multicast_list = woal_uap_set_multicast_list; -#else - dev->netdev_ops = &woal_uap_netdev_ops; -#endif -#ifdef WIRELESS_EXT -#ifdef UAP_WEXT - if (IS_UAP_WEXT(cfg80211_wext)) { -#if WIRELESS_EXT < 21 - dev->get_wireless_stats = woal_get_uap_wireless_stats; -#endif - dev->wireless_handlers = - (struct iw_handler_def *) &woal_uap_handler_def; - init_waitqueue_head(&priv->w_stats_wait_q); - } -#endif /* UAP_WEXT */ -#endif /* WIRELESS_EXT */ - } else if (*bss_role == MLAN_BSS_ROLE_STA) { - /* Switch: uAP -> STA */ - /* Setup the OS Interface to our functions */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) - dev->do_ioctl = woal_do_ioctl; - dev->set_multicast_list = woal_set_multicast_list; -#else - dev->netdev_ops = &woal_netdev_ops; -#endif -#ifdef WIRELESS_EXT -#ifdef STA_WEXT - if (IS_STA_WEXT(cfg80211_wext)) { -#if WIRELESS_EXT < 21 - dev->get_wireless_stats = woal_get_wireless_stats; -#endif - dev->wireless_handlers = - (struct iw_handler_def *) &woal_handler_def; - init_waitqueue_head(&priv->w_stats_wait_q); - } -#endif /* STA_WEXT */ -#endif - } /* Enable interfaces */ - netif_device_attach(dev); - woal_start_queue(dev); + netif_device_attach(priv->netdev); + woal_start_queue(priv->netdev); } done: - if (req) - kfree(req); LEAVE(); return ret; } @@ -478,8 +429,7 @@ woal_cfg80211_init_p2p_client(moal_private * priv) wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE; if (MLAN_STATUS_SUCCESS != - woal_cfg80211_wifi_direct_mode_cfg(priv, - MLAN_ACT_SET, &wifi_direct_mode)) { + woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) { ret = -EFAULT; goto done; } @@ -487,8 +437,7 @@ woal_cfg80211_init_p2p_client(moal_private * priv) /* first, init wifi direct to listen mode */ wifi_direct_mode = WIFI_DIRECT_MODE_LISTEN; if (MLAN_STATUS_SUCCESS != - woal_cfg80211_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, - &wifi_direct_mode)) { + woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) { ret = -EFAULT; goto done; } @@ -496,8 +445,7 @@ woal_cfg80211_init_p2p_client(moal_private * priv) /* second, init wifi direct client */ wifi_direct_mode = WIFI_DIRECT_MODE_CLIENT; if (MLAN_STATUS_SUCCESS != - woal_cfg80211_wifi_direct_mode_cfg(priv, - MLAN_ACT_SET, &wifi_direct_mode)) { + woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) { ret = -EFAULT; goto done; } @@ -531,8 +479,7 @@ woal_cfg80211_init_p2p_go(moal_private * priv) wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE; if (MLAN_STATUS_SUCCESS != - woal_cfg80211_wifi_direct_mode_cfg(priv, - MLAN_ACT_SET, &wifi_direct_mode)) { + woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) { ret = -EFAULT; goto done; } @@ -540,8 +487,7 @@ woal_cfg80211_init_p2p_go(moal_private * priv) /* first, init wifi direct to listen mode */ wifi_direct_mode = WIFI_DIRECT_MODE_LISTEN; if (MLAN_STATUS_SUCCESS != - woal_cfg80211_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, - &wifi_direct_mode)) { + woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) { ret = -EFAULT; goto done; } @@ -549,8 +495,7 @@ woal_cfg80211_init_p2p_go(moal_private * priv) /* second, init wifi direct to GO mode */ wifi_direct_mode = WIFI_DIRECT_MODE_GO; if (MLAN_STATUS_SUCCESS != - woal_cfg80211_wifi_direct_mode_cfg(priv, - MLAN_ACT_SET, &wifi_direct_mode)) { + woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) { ret = -EFAULT; goto done; } @@ -603,8 +548,7 @@ woal_cfg80211_deinit_p2p(moal_private * priv) /* cancel previous remain on channel */ if (priv->phandle->remain_on_channel) { if (woal_cfg80211_remain_on_channel_cfg - (priv->wdev->wiphy, MOAL_IOCTL_WAIT, MTRUE, &channel_status, NULL, - 0, 0)) { + (priv, MOAL_IOCTL_WAIT, MTRUE, &channel_status, NULL, 0, 0)) { PRINTM(MERROR, "Fail to cancel remain on channel\n"); ret = -EFAULT; goto done; @@ -640,8 +584,7 @@ woal_cfg80211_deinit_p2p(moal_private * priv) wifi_direct_mode = WIFI_DIRECT_MODE_DISABLE; if (MLAN_STATUS_SUCCESS != - woal_cfg80211_wifi_direct_mode_cfg(priv, - MLAN_ACT_SET, &wifi_direct_mode)) { + woal_wifi_direct_mode_cfg(priv, MLAN_ACT_SET, &wifi_direct_mode)) { ret = -EFAULT; goto done; } @@ -670,7 +613,7 @@ woal_cfg80211_change_virtual_intf(struct wiphy *wiphy, struct vif_params *params) { int ret = 0; - moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + moal_private *priv = (moal_private *) woal_get_netdev_priv(dev); mlan_ds_bss *bss = NULL; mlan_ioctl_req *req = NULL; @@ -687,7 +630,7 @@ woal_cfg80211_change_virtual_intf(struct wiphy *wiphy, if (priv->phandle->remain_on_channel) { t_u8 channel_status; if (woal_cfg80211_remain_on_channel_cfg - (wiphy, MOAL_IOCTL_WAIT, MTRUE, &channel_status, NULL, 0, 0)) { + (priv, MOAL_IOCTL_WAIT, MTRUE, &channel_status, NULL, 0, 0)) { PRINTM(MERROR, "Fail to cancel remain on channel\n"); ret = -EFAULT; goto done; @@ -908,7 +851,7 @@ woal_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev, #endif const t_u8 * mac_addr, struct key_params *params) { - moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + moal_private *priv = (moal_private *) woal_get_netdev_priv(netdev); ENTER(); @@ -945,7 +888,7 @@ woal_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev, #endif const t_u8 * mac_addr) { - moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + moal_private *priv = (moal_private *) woal_get_netdev_priv(netdev); ENTER(); @@ -981,7 +924,7 @@ woal_cfg80211_set_default_key(struct wiphy *wiphy, ) { int ret = 0; - moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + moal_private *priv = (moal_private *) woal_get_netdev_priv(netdev); mlan_bss_info bss_info; ENTER(); @@ -1019,9 +962,15 @@ woal_cfg80211_set_channel(struct wiphy *wiphy, enum nl80211_channel_type channel_type) { int ret = 0; - moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + moal_private *priv = NULL; ENTER(); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) || defined(COMPAT_WIRELESS) + if (dev) + priv = woal_get_netdev_priv(dev); + else +#endif + priv = (moal_private *) woal_get_wiphy_priv(wiphy); #ifdef STA_CFG80211 #ifdef STA_SUPPORT if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) { @@ -1031,7 +980,7 @@ woal_cfg80211_set_channel(struct wiphy *wiphy, LEAVE(); return -EINVAL; } - ret = woal_set_rf_channel(wiphy, chan, channel_type); + ret = woal_set_rf_channel(priv, chan, channel_type); } #endif #endif @@ -1055,7 +1004,7 @@ woal_cfg80211_mgmt_frame_register(struct wiphy *wiphy, struct net_device *dev, u16 frame_type, bool reg) { - moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + moal_private *priv = (moal_private *) woal_get_netdev_priv(dev); mlan_status status = MLAN_STATUS_SUCCESS; t_u32 mgmt_subtype_mask = 0x0; static t_u32 last_mgmt_subtype_mask = 0x0; @@ -1112,7 +1061,7 @@ woal_cfg80211_mgmt_tx(struct wiphy *wiphy, #endif u64 * cookie) { - moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + moal_private *priv = (moal_private *) woal_get_netdev_priv(dev); int ret = 0; pmlan_buffer pmbuf = NULL; mlan_status status = MLAN_STATUS_SUCCESS; @@ -1151,7 +1100,7 @@ woal_cfg80211_mgmt_tx(struct wiphy *wiphy, /** cancel previous remain on channel */ if (priv->phandle->remain_on_channel) { if (woal_cfg80211_remain_on_channel_cfg - (wiphy, MOAL_IOCTL_WAIT, MTRUE, &channel_status, NULL, 0, 0)) { + (priv, MOAL_IOCTL_WAIT, MTRUE, &channel_status, NULL, 0, 0)) { PRINTM(MERROR, "Fail to cancel remain on channel\n"); ret = -EFAULT; goto done; @@ -1171,13 +1120,13 @@ woal_cfg80211_mgmt_tx(struct wiphy *wiphy, duration = MGMT_TX_DEFAULT_WAIT_TIME; if (channel_type_valid) ret = - woal_cfg80211_remain_on_channel_cfg(wiphy, MOAL_IOCTL_WAIT, + woal_cfg80211_remain_on_channel_cfg(priv, MOAL_IOCTL_WAIT, MFALSE, &channel_status, chan, channel_type, duration); else ret = - woal_cfg80211_remain_on_channel_cfg(wiphy, MOAL_IOCTL_WAIT, + woal_cfg80211_remain_on_channel_cfg(priv, MOAL_IOCTL_WAIT, MFALSE, &channel_status, chan, 0, duration); if (ret) { @@ -1261,3 +1210,478 @@ woal_cfg80211_mgmt_tx(struct wiphy *wiphy, LEAVE(); return ret; } + +/** + * @brief Look up specific IE in a buf + * + * @param ie Pointer to IEs + * @param len Total length of ie + * @param id Element id to lookup + * + * @return Pointer of the specific IE -- success, NULL -- fail + */ +const t_u8 * +woal_parse_ie_tlv(const t_u8 * ie, int len, t_u8 id) +{ + int left_len = len; + const t_u8 *pos = ie; + int length; + + /* IE format: | u8 | id | | u8 | len | | var | data | */ + while (left_len >= 2) { + length = *(pos + 1); + if ((*pos == id) && (length + 2) <= left_len) + return pos; + pos += (length + 2); + left_len -= (length + 2); + } + + return NULL; +} + +/** + * @brief This function returns priv + * based on mgmt ie index + * + * @param handle A pointer to moal_handle + * @param index mgmt ie index + * + * @return Pointer to moal_private + */ +static moal_private * +woal_get_priv_by_mgmt_index(moal_handle * handle, t_u16 index) +{ + int i; + + for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) { + if (handle->priv[i]) { + if (handle->priv[i]->probereq_index == index) + return (handle->priv[i]); + } + } + return NULL; +} + +/** + * @brief Add custom ie to mgmt frames. + * + * @param priv A pointer to moal private structure + * @param beacon_ies_data Beacon ie + * @param beacon_index The index for beacon when auto index + * @param proberesp_ies_data Probe resp ie + * @param proberesp_index The index for probe resp when auto index + * @param assocresp_ies_data Assoc resp ie + * @param assocresp_index The index for assoc resp when auto index + * @param probereq_ies_data Probe req ie + * @param probereq_index The index for probe req when auto index * + * + * @return 0 -- success, otherwise fail + */ +static int +woal_cfg80211_custom_ie(moal_private * priv, + custom_ie * beacon_ies_data, t_u16 * beacon_index, + custom_ie * proberesp_ies_data, t_u16 * proberesp_index, + custom_ie * assocresp_ies_data, t_u16 * assocresp_index, + custom_ie * probereq_ies_data, t_u16 * probereq_index) +{ + mlan_ioctl_req *ioctl_req = NULL; + mlan_ds_misc_cfg *misc = NULL; + mlan_ds_misc_custom_ie *custom_ie = NULL; + t_u8 *pos = NULL; + t_u16 len = 0; + int ret = 0; + + ENTER(); + + if (!(custom_ie = kmalloc(sizeof(mlan_ds_misc_custom_ie), GFP_KERNEL))) { + ret = -ENOMEM; + goto done; + } + + memset(custom_ie, 0x00, sizeof(mlan_ds_misc_custom_ie)); + custom_ie->type = TLV_TYPE_MGMT_IE; + + pos = (t_u8 *) custom_ie->ie_data_list; + if (beacon_ies_data) { + len = sizeof(*beacon_ies_data) - MAX_IE_SIZE + + beacon_ies_data->ie_length; + memcpy(pos, beacon_ies_data, len); + pos += len; + custom_ie->len += len; + } + + if (proberesp_ies_data) { + len = sizeof(*proberesp_ies_data) - MAX_IE_SIZE + + proberesp_ies_data->ie_length; + memcpy(pos, proberesp_ies_data, len); + pos += len; + custom_ie->len += len; + } + + if (assocresp_ies_data) { + len = sizeof(*assocresp_ies_data) - MAX_IE_SIZE + + assocresp_ies_data->ie_length; + memcpy(pos, assocresp_ies_data, len); + custom_ie->len += len; + } + + if (probereq_ies_data) { + len = sizeof(*probereq_ies_data) - MAX_IE_SIZE + + probereq_ies_data->ie_length; + memcpy(pos, probereq_ies_data, len); + pos += len; + custom_ie->len += len; + } + + ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (ioctl_req == NULL) { + ret = -ENOMEM; + goto done; + } + + misc = (mlan_ds_misc_cfg *) ioctl_req->pbuf; + misc->sub_command = MLAN_OID_MISC_CUSTOM_IE; + ioctl_req->req_id = MLAN_IOCTL_MISC_CFG; + ioctl_req->action = MLAN_ACT_SET; + + memcpy(&misc->param.cust_ie, custom_ie, sizeof(mlan_ds_misc_custom_ie)); + + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + /* get the assigned index */ + pos = (t_u8 *) (&misc->param.cust_ie.ie_data_list[0].ie_index); + if (beacon_ies_data && beacon_ies_data->ie_length + && beacon_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) { + /* save beacon ie index after auto-indexing */ + *beacon_index = misc->param.cust_ie.ie_data_list[0].ie_index; + len = sizeof(*beacon_ies_data) - MAX_IE_SIZE + + beacon_ies_data->ie_length; + pos += len; + } + + if (proberesp_ies_data && proberesp_ies_data->ie_length + && proberesp_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) { + /* save probe resp ie index after auto-indexing */ + *proberesp_index = *((t_u16 *) pos); + len = sizeof(*proberesp_ies_data) - MAX_IE_SIZE + + proberesp_ies_data->ie_length; + pos += len; + } + + if (assocresp_ies_data && assocresp_ies_data->ie_length + && assocresp_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) { + /* save assoc resp ie index after auto-indexing */ + *assocresp_index = *((t_u16 *) pos); + len = sizeof(*assocresp_ies_data) - MAX_IE_SIZE + + assocresp_ies_data->ie_length; + pos += len; + } + if (probereq_ies_data && probereq_ies_data->ie_length + && probereq_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) { + /* save probe resp ie index after auto-indexing */ + *probereq_index = *((t_u16 *) pos); + len = sizeof(*probereq_ies_data) - MAX_IE_SIZE + + probereq_ies_data->ie_length; + pos += len; + } + + if (ioctl_req->status_code == MLAN_ERROR_IOCTL_FAIL) + ret = -EFAULT; + + done: + if (ioctl_req) + kfree(ioctl_req); + if (custom_ie) + kfree(custom_ie); + LEAVE(); + return ret; +} + +/** + * @brief Filter specific IE in ie buf + * + * @param ie Pointer to IEs + * @param len Total length of ie + * @param ie_out Pointer to out IE buf + * + * @return out IE length + */ +static t_u16 +woal_filter_beacon_ies(const t_u8 * ie, int len, t_u8 * ie_out) +{ + int left_len = len; + const t_u8 *pos = ie; + int length; + t_u8 id = 0; + t_u16 out_len = 0; + + /* ERP_INFO and RSN IE will be fileter out */ + while (left_len >= 2) { + length = *(pos + 1); + id = *pos; + if ((length + 2) > left_len) + break; + switch (id) { + case WLAN_EID_ERP_INFO: + case RSN_IE: + break; + default: + memcpy(ie_out + out_len, pos, length + 2); + out_len += length + 2; + break; + } + pos += (length + 2); + left_len -= (length + 2); + } + return out_len; +} + +/** + * @brief config AP or GO for mgmt frame ies. + * + * @param priv A pointer to moal private structure + * @param beacon_ies A pointer to beacon ies + * @param beacon_ies_len Beacon ies length + * @param proberesp_ies A pointer to probe resp ies + * @param proberesp_ies_len Probe resp ies length + * @param assocresp_ies A pointer to probe resp ies + * @param assocresp_ies_len Assoc resp ies length + * @param probereq_ies A pointer to probe req ies + * @param probereq_ies_len Probe req ies length * + * @param mask Mgmt frame mask + * + * @return 0 -- success, otherwise fail + */ +int +woal_cfg80211_mgmt_frame_ie(moal_private * priv, + const t_u8 * beacon_ies, size_t beacon_ies_len, + const t_u8 * proberesp_ies, + size_t proberesp_ies_len, + const t_u8 * assocresp_ies, + size_t assocresp_ies_len, const t_u8 * probereq_ies, + size_t probereq_ies_len, t_u16 mask) +{ + int ret = 0; + t_u8 *pos = NULL; + custom_ie *beacon_ies_data = NULL; + custom_ie *proberesp_ies_data = NULL; + custom_ie *assocresp_ies_data = NULL; + custom_ie *probereq_ies_data = NULL; + + /* static variables for mgmt frame ie auto-indexing */ + static t_u16 beacon_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; + static t_u16 proberesp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; + static t_u16 assocresp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; + static t_u16 probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; + moal_private *pmpriv = NULL; + static t_u16 rsn_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; + const t_u8 *rsn_ie; + + ENTER(); + + if (mask & MGMT_MASK_BEACON) { + if (!(beacon_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) { + ret = -ENOMEM; + goto done; + } + if (beacon_ies && beacon_ies_len) { + rsn_ie = + woal_parse_ie_tlv((t_u8 *) beacon_ies, (int) beacon_ies_len, + RSN_IE); + if (rsn_ie) { + beacon_ies_data->ie_index = rsn_index; + beacon_ies_data->mgmt_subtype_mask = + MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP | + MGMT_MASK_ASSOC_RESP; + beacon_ies_data->ie_length = rsn_ie[1] + 2; + memcpy(beacon_ies_data->ie_buffer, rsn_ie, rsn_ie[1] + 2); + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_custom_ie(priv, beacon_ies_data, &rsn_index, + NULL, &proberesp_index, NULL, + &assocresp_index, NULL, + &probereq_index)) { + ret = -EFAULT; + goto done; + } + } + } else { + /* clear rsn_ie */ + if (rsn_index <= MAX_MGMT_IE_INDEX) { + beacon_ies_data->ie_index = rsn_index; + beacon_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK; + beacon_ies_data->ie_length = 0; + rsn_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_custom_ie(priv, beacon_ies_data, &rsn_index, + NULL, &proberesp_index, NULL, + &assocresp_index, NULL, + &probereq_index)) { + ret = -EFAULT; + goto done; + } + } + } + } + + if (mask & MGMT_MASK_PROBE_RESP) { + if (!(proberesp_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) { + ret = -ENOMEM; + goto done; + } + } + + if (mask & MGMT_MASK_ASSOC_RESP) { + if (!(assocresp_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) { + ret = -ENOMEM; + goto done; + } + } + if (mask & MGMT_MASK_PROBE_REQ) { + if (!(probereq_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) { + ret = -ENOMEM; + goto done; + } + } + + if (beacon_ies_data) { + memset(beacon_ies_data, 0x00, sizeof(custom_ie)); + if (beacon_ies && beacon_ies_len) { + /* set the beacon ies */ + beacon_ies_data->ie_index = beacon_index; + beacon_ies_data->mgmt_subtype_mask = MGMT_MASK_BEACON; + beacon_ies_data->mgmt_subtype_mask |= MGMT_MASK_ASSOC_RESP; + beacon_ies_data->ie_length = woal_filter_beacon_ies(beacon_ies, + beacon_ies_len, + beacon_ies_data-> + ie_buffer); + } else { + /* clear the beacon ies */ + if (beacon_index > MAX_MGMT_IE_INDEX) { + PRINTM(MERROR, "Invalid beacon index for mgmt frame ie.\n"); + goto done; + } + + beacon_ies_data->ie_index = beacon_index; + beacon_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK; + beacon_ies_data->ie_length = 0; + beacon_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; + } + } + + if (proberesp_ies_data) { + memset(proberesp_ies_data, 0x00, sizeof(custom_ie)); + if (proberesp_ies && proberesp_ies_len) { + /* set the probe response ies */ + // proberesp_ies_data->ie_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; + proberesp_ies_data->ie_index = proberesp_index; + proberesp_ies_data->mgmt_subtype_mask = MGMT_MASK_PROBE_RESP; + proberesp_ies_data->ie_length = proberesp_ies_len; + pos = proberesp_ies_data->ie_buffer; + memcpy(pos, proberesp_ies, proberesp_ies_len); + } else { + /* clear the probe response ies */ + if (proberesp_index > MAX_MGMT_IE_INDEX) { + PRINTM(MERROR, "Invalid probe resp index for mgmt frame ie.\n"); + goto done; + } + + proberesp_ies_data->ie_index = proberesp_index; + proberesp_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK; + proberesp_ies_data->ie_length = 0; + proberesp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; + } + } + if (assocresp_ies_data) { + memset(assocresp_ies_data, 0x00, sizeof(custom_ie)); + if (assocresp_ies && assocresp_ies_len) { + /* set the assoc response ies */ + assocresp_ies_data->ie_index = assocresp_index; + assocresp_ies_data->mgmt_subtype_mask = MGMT_MASK_ASSOC_RESP; + assocresp_ies_data->ie_length = assocresp_ies_len; + pos = assocresp_ies_data->ie_buffer; + memcpy(pos, assocresp_ies, assocresp_ies_len); + } else { + /* clear the assoc response ies */ + if (assocresp_index > MAX_MGMT_IE_INDEX) { + PRINTM(MERROR, "Invalid assoc resp index for mgmt frame ie.\n"); + goto done; + } + + assocresp_ies_data->ie_index = assocresp_index; + assocresp_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK; + assocresp_ies_data->ie_length = 0; + assocresp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; + } + } + + if (probereq_ies_data) { + memset(probereq_ies_data, 0x00, sizeof(custom_ie)); + if ((probereq_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK) && + (priv->probereq_index != probereq_index)) { + pmpriv = woal_get_priv_by_mgmt_index(priv->phandle, probereq_index); + if (pmpriv) { + probereq_ies_data->ie_index = probereq_index; + probereq_ies_data->mgmt_subtype_mask = + MLAN_CUSTOM_IE_DELETE_MASK; + probereq_ies_data->ie_length = 0; + probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; + pmpriv->probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_custom_ie(pmpriv, NULL, &beacon_index, + NULL, &proberesp_index, + NULL, &assocresp_index, + probereq_ies_data, + &probereq_index)) { + ret = -EFAULT; + goto done; + } + memset(probereq_ies_data, 0x00, sizeof(custom_ie)); + } + } + if (probereq_ies && probereq_ies_len) { + /* set the probe req ies */ + probereq_ies_data->ie_index = probereq_index; + probereq_ies_data->mgmt_subtype_mask = MGMT_MASK_PROBE_REQ; + probereq_ies_data->ie_length = probereq_ies_len; + pos = probereq_ies_data->ie_buffer; + memcpy(pos, probereq_ies, probereq_ies_len); + } else { + /* clear the probe req ies */ + if (probereq_index > MAX_MGMT_IE_INDEX) { + PRINTM(MERROR, "Invalid probe resp index for mgmt frame ie.\n"); + goto done; + } + probereq_ies_data->ie_index = probereq_index; + probereq_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK; + probereq_ies_data->ie_length = 0; + probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; + } + } + + if (MLAN_STATUS_SUCCESS != + woal_cfg80211_custom_ie(priv, beacon_ies_data, &beacon_index, + proberesp_ies_data, &proberesp_index, + assocresp_ies_data, &assocresp_index, + probereq_ies_data, &probereq_index)) { + ret = -EFAULT; + goto done; + } + if (probereq_ies_data) + priv->probereq_index = probereq_index; + + done: + if (beacon_ies_data) + kfree(beacon_ies_data); + if (proberesp_ies_data) + kfree(proberesp_ies_data); + if (assocresp_ies_data) + kfree(assocresp_ies_data); + + LEAVE(); + + return ret; +} diff --git a/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.h b/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.h index e1683ed08a89..f58fc18829fa 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.h +++ b/drivers/net/wireless/sd8797/mlinux/moal_cfg80211.h @@ -24,8 +24,11 @@ #include "moal_main.h" +/* Clear all key indexes */ +#define KEY_INDEX_CLEAR_ALL (0x0000000F) + /** RTS/FRAG disabled value */ -#define MLAN_FRAG_RTS_DISABLED (0xFFFFFFFF) +#define MLAN_FRAG_RTS_DISABLED (0xFFFFFFFF) #ifndef WLAN_CIPHER_SUITE_WAPI #define WLAN_CIPHER_SUITE_WAPI 0x00000020 @@ -55,6 +58,9 @@ static const void *const mrvl_wiphy_privid = &mrvl_wiphy_privid; /* Get the private structure from wiphy */ void *woal_get_wiphy_priv(struct wiphy *wiphy); +/* Get the private structure from net device */ +void *woal_get_netdev_priv(struct net_device *dev); + int woal_cfg80211_change_virtual_intf(struct wiphy *wiphy, struct net_device *dev, enum nl80211_iftype type, @@ -78,7 +84,7 @@ int woal_cfg80211_del_key(struct wiphy *wiphy, #ifdef STA_CFG80211 #ifdef STA_SUPPORT -int woal_set_rf_channel(struct wiphy *wiphy, +int woal_set_rf_channel(moal_private * priv, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type); mlan_status woal_inform_bss_from_scan_result(moal_private * priv, @@ -149,7 +155,7 @@ int woal_cfg80211_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev); #if defined(WIFI_DIRECT_SUPPORT) /** Define kernel version for wifi direct */ #if !defined(COMPAT_WIRELESS) -#define WIFI_DIRECT_KERNEL_VERSION KERNEL_VERSION(3,0,0) +#define WIFI_DIRECT_KERNEL_VERSION KERNEL_VERSION(2,6,39) #else #define WIFI_DIRECT_KERNEL_VERSION KERNEL_VERSION(2,6,33) #endif /* COMPAT_WIRELESS */ @@ -173,7 +179,7 @@ int woal_cfg80211_init_p2p_go(moal_private * priv); int woal_cfg80211_deinit_p2p(moal_private * priv); -int woal_cfg80211_remain_on_channel_cfg(struct wiphy *wiphy, +int woal_cfg80211_remain_on_channel_cfg(moal_private * priv, t_u8 wait_option, t_u8 remove, t_u8 * status, struct ieee80211_channel *chan, @@ -184,6 +190,8 @@ int woal_uap_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, #endif /* KERNEL_VERSION */ #endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */ +const t_u8 *woal_parse_ie_tlv(const t_u8 * ie, int len, t_u8 id); + int woal_cfg80211_mgmt_frame_ie(moal_private * priv, const t_u8 * beacon_ies, size_t beacon_ies_len, const t_u8 * proberesp_ies, diff --git a/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c b/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c index 2282216f7d55..31040a29ceec 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.c @@ -50,10 +50,29 @@ Change log: #define PRIV_CMD_BANDCFG "bandcfg" /** Private command: Host cmd */ #define PRIV_CMD_HOSTCMD "hostcmd" +/** Private command: Custom IE config*/ +#define PRIV_CMD_CUSTOMIE "customie" /** Private command: HT Tx Cfg */ #define PRIV_CMD_HTTXCFG "httxcfg" #define PRIV_CMD_DATARATE "getdatarate" #define PRIV_CMD_TXRATECFG "txratecfg" +#define PRIV_CMD_ESUPPMODE "esuppmode" +#define PRIV_CMD_PASSPHRASE "passphrase" +#define PRIV_CMD_DEAUTH "deauth" +#if defined(WIFI_DIRECT_SUPPORT) +#if defined(STA_SUPPORT) && defined(UAP_SUPPORT) +#define PRIV_CMD_BSSROLE "bssrole" +#endif +#endif +#ifdef STA_SUPPORT +#define PRIV_CMD_SETUSERSCAN "setuserscan" +#endif +#define PRIV_CMD_DEEPSLEEP "deepsleep" +#define PRIV_CMD_IPADDR "ipaddr" +#define PRIV_CMD_WPSSESSION "wpssession" +#define PRIV_CMD_OTPUSERDATA "otpuserdata" +#define PRIV_CMD_COUNTRYCODE "countrycode" +#define PRIV_CMD_TCPACKENH "tcpackenh" /** Bands supported in Infra mode */ static t_u8 SupportedInfraBand[] = { @@ -76,6 +95,17 @@ static t_u8 SupportedAdhocBand[] = { /******************************************************** Global Variables ********************************************************/ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) +#ifdef UAP_SUPPORT +/** Network device handlers for uAP */ +extern const struct net_device_ops woal_uap_netdev_ops; +#endif +#ifdef STA_SUPPORT +/** Network device handlers for STA */ +extern const struct net_device_ops woal_netdev_ops; +#endif +#endif +extern int cfg80211_wext; /******************************************************** Local Functions @@ -85,7 +115,7 @@ static t_u8 SupportedAdhocBand[] = { * * @param pos Pointer to the arguments string * @param data Pointer to the arguments buffer - * @param len Pointer to the number of arguments extracted + * @param user_data_len Pointer to the number of arguments extracted * * @return MLAN_STATUS_SUCCESS * @@ -246,7 +276,6 @@ woal_get_priv_driver_version(moal_private * priv, t_u8 * respbuf, return ret; } -#ifdef WIFI_DIRECT_SUPPORT /** * @brief Hostcmd interface from application * @@ -296,8 +325,12 @@ woal_priv_hostcmd(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen) ret = -EFAULT; goto error; } - sprintf(respbuf, "OK"); - ret = 3; + memcpy(data_ptr + sizeof(buf_len), misc_cfg->param.hostcmd.cmd, + misc_cfg->param.hostcmd.len); + ret = + misc_cfg->param.hostcmd.len + sizeof(buf_len) + strlen(CMD_MARVELL) + + strlen(PRIV_CMD_HOSTCMD); + memcpy(data_ptr, (t_u8 *) & ret, sizeof(t_u32)); error: if (req) @@ -306,7 +339,65 @@ woal_priv_hostcmd(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen) LEAVE(); return ret; } -#endif + +/** + * @brief Custom IE setting + * + * @param priv A pointer to moal_private structure + * @param respbuf A pointer to response buffer + * @param respbuflen Available length of response buffer + * + * @return Number of bytes written, negative for failure. + */ +int +woal_priv_customie(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen) +{ + int ret = 0; + t_u8 *data_ptr; + mlan_ioctl_req *ioctl_req = NULL; + mlan_ds_misc_cfg *misc = NULL; + mlan_ds_misc_custom_ie *custom_ie = NULL; + + ENTER(); + data_ptr = respbuf + (strlen(CMD_MARVELL) + strlen(PRIV_CMD_CUSTOMIE)); + + custom_ie = (mlan_ds_misc_custom_ie *) data_ptr; + ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (ioctl_req == NULL) { + ret = -ENOMEM; + goto done; + } + + misc = (mlan_ds_misc_cfg *) ioctl_req->pbuf; + misc->sub_command = MLAN_OID_MISC_CUSTOM_IE; + ioctl_req->req_id = MLAN_IOCTL_MISC_CFG; + if ((custom_ie->len == 0) || + (custom_ie->len == sizeof(custom_ie->ie_data_list[0].ie_index))) + ioctl_req->action = MLAN_ACT_GET; + else + ioctl_req->action = MLAN_ACT_SET; + + memcpy(&misc->param.cust_ie, custom_ie, sizeof(mlan_ds_misc_custom_ie)); + + if (MLAN_STATUS_SUCCESS != + woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + custom_ie = (mlan_ds_misc_custom_ie *) data_ptr; + memcpy(custom_ie, &misc->param.cust_ie, sizeof(mlan_ds_misc_custom_ie)); + ret = sizeof(mlan_ds_misc_custom_ie); + if (ioctl_req->status_code == MLAN_ERROR_IOCTL_FAIL) { + /* send a separate error code to indicate error from driver */ + ret = EFAULT; + } + done: + if (ioctl_req) { + kfree(ioctl_req); + } + LEAVE(); + return ret; +} /** * @brief Set/Get Band and Adhoc-band setting @@ -728,129 +819,1042 @@ woal_setget_priv_txratecfg(moal_private * priv, t_u8 * respbuf, } /** - * @brief Set priv command for Android - * @param dev A pointer to net_device structure - * @param req A pointer to ifreq structure + * @brief Set/Get esupplicant mode configurations * - * @return 0 --success, otherwise fail + * @param priv A pointer to moal_private structure + * @param respbuf A pointer to response buffer + * @param respbuflen Available length of response buffer + * + * @return Number of bytes written, negative for failure. */ int -woal_android_priv_cmd(struct net_device *dev, struct ifreq *req) +woal_setget_priv_esuppmode(moal_private * priv, t_u8 * respbuf, + t_u32 respbuflen) { + t_u32 data[3]; + mlan_ioctl_req *req = NULL; + mlan_ds_sec_cfg *sec = NULL; + woal_esuppmode_cfg *esupp_mode = NULL; int ret = 0; - android_wifi_priv_cmd priv_cmd; - moal_private *priv = (moal_private *) netdev_priv(dev); - char *buf = NULL; - char *pdata; -#ifdef STA_SUPPORT - int power_mode = 0; - int band = 0; - char *pband = NULL; - mlan_bss_info bss_info; - mlan_ds_get_signal signal; - mlan_rate_cfg_t rate; - t_u8 country_code[COUNTRY_CODE_LEN]; -#endif - int len = 0; + int user_data_len = 0; ENTER(); - if (copy_from_user(&priv_cmd, req->ifr_data, sizeof(android_wifi_priv_cmd))) { - ret = -EFAULT; + + if (strlen(respbuf) == (strlen(CMD_MARVELL) + strlen(PRIV_CMD_ESUPPMODE))) { + /* GET operation */ + user_data_len = 0; + } else { + /* SET operation */ + memset((char *) data, 0, sizeof(data)); + parse_arguments(respbuf + strlen(CMD_MARVELL) + + strlen(PRIV_CMD_ESUPPMODE), data, &user_data_len); + } + + if (user_data_len >= 4 || user_data_len == 1 || user_data_len == 2) { + PRINTM(MERROR, "Invalid number of arguments\n"); + ret = -EINVAL; goto done; } - buf = kzalloc(priv_cmd.total_len, GFP_KERNEL); - if (!buf) { - PRINTM(MERROR, "%s: failed to allocate memory\n", __FUNCTION__); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg)); + if (req == NULL) { ret = -ENOMEM; goto done; } - if (copy_from_user(buf, priv_cmd.buf, priv_cmd.total_len)) { + + req->req_id = MLAN_IOCTL_SEC_CFG; + sec = (mlan_ds_sec_cfg *) req->pbuf; + sec->sub_command = MLAN_OID_SEC_CFG_ESUPP_MODE; + + if (user_data_len == 0) { + /* Get operation */ + req->action = MLAN_ACT_GET; + } else { + /* Set operation */ + req->action = MLAN_ACT_SET; + /* RSN mode */ + sec->param.esupp_mode.rsn_mode = data[0]; + /* Pairwise cipher */ + sec->param.esupp_mode.act_paircipher = (data[1] & 0xFF); + /* Group cipher */ + sec->param.esupp_mode.act_groupcipher = (data[2] & 0xFF); + } + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { ret = -EFAULT; goto done; } - PRINTM(MIOCTL, "Android priv cmd: [%s] on [%s]\n", buf, req->ifr_name); + esupp_mode = (woal_esuppmode_cfg *) respbuf; + esupp_mode->rsn_mode = (t_u16) ((sec->param.esupp_mode.rsn_mode) & 0xFFFF); + esupp_mode->pairwise_cipher = + (t_u8) ((sec->param.esupp_mode.act_paircipher) & 0xFF); + esupp_mode->group_cipher = + (t_u8) ((sec->param.esupp_mode.act_groupcipher) & 0xFF); - if (strncmp(buf, CMD_MARVELL, strlen(CMD_MARVELL)) == 0) { - /* This command has come from mlanutl app */ + ret = sizeof(woal_esuppmode_cfg); + done: + if (req) + kfree(req); + LEAVE(); + return ret; - /* Check command */ - if (strnicmp - (buf + strlen(CMD_MARVELL), PRIV_CMD_VERSION, - strlen(PRIV_CMD_VERSION)) == 0) { - /* Get version */ - len = woal_get_priv_driver_version(priv, buf, priv_cmd.total_len); - goto handled; - } else - if (strnicmp - (buf + strlen(CMD_MARVELL), PRIV_CMD_BANDCFG, - strlen(PRIV_CMD_BANDCFG)) == 0) { - /* Set/Get band configuration */ - len = woal_setget_priv_bandcfg(priv, buf, priv_cmd.total_len); - goto handled; -#ifdef WIFI_DIRECT_SUPPORT - } else - if (strnicmp - (buf + strlen(CMD_MARVELL), PRIV_CMD_HOSTCMD, - strlen(PRIV_CMD_HOSTCMD)) == 0) { - /* hostcmd configuration */ - len = woal_priv_hostcmd(priv, buf, priv_cmd.total_len); - goto handled; -#endif - } else - if (strnicmp - (buf + strlen(CMD_MARVELL), PRIV_CMD_HTTXCFG, - strlen(PRIV_CMD_HTTXCFG)) == 0) { - /* Set/Get HT Tx configuration */ - len = woal_setget_priv_httxcfg(priv, buf, priv_cmd.total_len); - goto handled; - } else - if (strnicmp - (buf + strlen(CMD_MARVELL), PRIV_CMD_DATARATE, - strlen(PRIV_CMD_DATARATE)) == 0) { - /* Get data rate */ - len = woal_get_priv_datarate(priv, buf, priv_cmd.total_len); - goto handled; - } else - if (strnicmp - (buf + strlen(CMD_MARVELL), PRIV_CMD_TXRATECFG, - strlen(PRIV_CMD_TXRATECFG)) == 0) { - /* Set/Get tx rate cfg */ - len = woal_setget_priv_txratecfg(priv, buf, priv_cmd.total_len); - goto handled; - } else { - /* Fall through, after stripping off the custom header */ - buf += strlen(CMD_MARVELL); - } +} + +/** + * @brief Set/Get esupplicant passphrase configurations + * + * @param priv A pointer to moal_private structure + * @param respbuf A pointer to response buffer + * @param respbuflen Available length of response buffer + * + * @return Number of bytes written, negative for failure. + */ +int +woal_setget_priv_passphrase(moal_private * priv, t_u8 * respbuf, + t_u32 respbuflen) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_sec_cfg *sec = NULL; + int ret = 0, action = -1, i = 0; + char *begin, *end, *opt; + t_u16 len = 0; + t_u8 zero_mac[] = { 0, 0, 0, 0, 0, 0 }; + t_u8 *mac = NULL; + + ENTER(); + + if (strlen(respbuf) == (strlen(CMD_MARVELL) + strlen(PRIV_CMD_PASSPHRASE))) { + PRINTM(MERROR, "No arguments provided\n"); + ret = -EINVAL; + goto done; } -#ifdef STA_SUPPORT - if (strncmp(buf, "RSSI", strlen("RSSI")) == 0) { - if (MLAN_STATUS_SUCCESS != woal_get_bss_info(priv, - MOAL_IOCTL_WAIT, - &bss_info)) { - ret = -EFAULT; - goto done; - } - if (bss_info.media_connected) { - if (MLAN_STATUS_SUCCESS != woal_get_signal_info(priv, - MOAL_IOCTL_WAIT, - &signal)) { + + /* Parse the buf to get the cmd_action */ + begin = respbuf + strlen(CMD_MARVELL) + strlen(PRIV_CMD_PASSPHRASE); + end = woal_strsep(&begin, ';', '/'); + if (end) + action = woal_atox(end); + if (action < 0 || action > 2 || end[1] != '\0') { + PRINTM(MERROR, "Invalid action argument %s\n", end); + ret = -EINVAL; + goto done; + } + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + req->req_id = MLAN_IOCTL_SEC_CFG; + sec = (mlan_ds_sec_cfg *) req->pbuf; + sec->sub_command = MLAN_OID_SEC_CFG_PASSPHRASE; + if (action == 0) + req->action = MLAN_ACT_GET; + else + req->action = MLAN_ACT_SET; + + while (begin) { + end = woal_strsep(&begin, ';', '/'); + opt = woal_strsep(&end, '=', '/'); + if (!opt || !end || !end[0]) { + PRINTM(MERROR, "Invalid option\n"); + ret = -EINVAL; + break; + } else if (!strnicmp(opt, "ssid", strlen(opt))) { + if (strlen(end) > MLAN_MAX_SSID_LENGTH) { + PRINTM(MERROR, "SSID length exceeds max length\n"); ret = -EFAULT; - goto done; + break; } - len = sprintf(buf, "%s rssi %d\n", bss_info.ssid.ssid, - signal.bcn_rssi_avg) + 1; + sec->param.passphrase.ssid.ssid_len = strlen(end); + strncpy((char *) sec->param.passphrase.ssid.ssid, end, strlen(end)); + PRINTM(MINFO, "ssid=%s, len=%d\n", sec->param.passphrase.ssid.ssid, + (int) sec->param.passphrase.ssid.ssid_len); + } else if (!strnicmp(opt, "bssid", strlen(opt))) { + woal_mac2u8((t_u8 *) & sec->param.passphrase.bssid, end); + } else if (!strnicmp(opt, "psk", strlen(opt)) && + req->action == MLAN_ACT_SET) { + if (strlen(end) != MLAN_PMK_HEXSTR_LENGTH) { + PRINTM(MERROR, "Invalid PMK length\n"); + ret = -EINVAL; + break; + } + woal_ascii2hex((t_u8 *) (sec->param.passphrase.psk.pmk.pmk), end, + MLAN_PMK_HEXSTR_LENGTH / 2); + sec->param.passphrase.psk_type = MLAN_PSK_PMK; + } else if (!strnicmp(opt, "passphrase", strlen(opt)) && + req->action == MLAN_ACT_SET) { + if (strlen(end) < MLAN_MIN_PASSPHRASE_LENGTH || + strlen(end) > MLAN_MAX_PASSPHRASE_LENGTH) { + PRINTM(MERROR, "Invalid length for passphrase\n"); + ret = -EINVAL; + break; + } + sec->param.passphrase.psk_type = MLAN_PSK_PASSPHRASE; + strncpy(sec->param.passphrase.psk.passphrase.passphrase, end, + sizeof(sec->param.passphrase.psk.passphrase.passphrase)); + sec->param.passphrase.psk.passphrase.passphrase_len = strlen(end); + PRINTM(MINFO, "passphrase=%s, len=%d\n", + sec->param.passphrase.psk.passphrase.passphrase, + (int) sec->param.passphrase.psk.passphrase.passphrase_len); } else { - len = sprintf(buf, "OK\n") + 1; + PRINTM(MERROR, "Invalid option %s\n", opt); + ret = -EINVAL; + break; } - } else if (strncmp(buf, "LINKSPEED", strlen("LINKSPEED")) == 0) { - if (MLAN_STATUS_SUCCESS != woal_set_get_data_rate(priv, MLAN_ACT_GET, - &rate)) { + } + if (ret) + goto done; + + if (action == 2) + sec->param.passphrase.psk_type = MLAN_PSK_CLEAR; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + memset(respbuf, 0, respbuflen); + if (sec->param.passphrase.ssid.ssid_len) { + len += sprintf(respbuf + len, "ssid:"); + memcpy(respbuf + len, sec->param.passphrase.ssid.ssid, + sec->param.passphrase.ssid.ssid_len); + len += sec->param.passphrase.ssid.ssid_len; + len += sprintf(respbuf + len, " "); + } + if (memcmp(&sec->param.passphrase.bssid, zero_mac, sizeof(zero_mac))) { + mac = (t_u8 *) & sec->param.passphrase.bssid; + len += sprintf(respbuf + len, "bssid:"); + for (i = 0; i < ETH_ALEN - 1; ++i) + len += sprintf(respbuf + len, "%02x:", mac[i]); + len += sprintf(respbuf + len, "%02x ", mac[i]); + } + if (sec->param.passphrase.psk_type == MLAN_PSK_PMK) { + len += sprintf(respbuf + len, "psk:"); + for (i = 0; i < MLAN_MAX_KEY_LENGTH; ++i) + len += + sprintf(respbuf + len, "%02x", + sec->param.passphrase.psk.pmk.pmk[i]); + len += sprintf(respbuf + len, "\n"); + } + if (sec->param.passphrase.psk_type == MLAN_PSK_PASSPHRASE) { + len += + sprintf(respbuf + len, "passphrase:%s \n", + sec->param.passphrase.psk.passphrase.passphrase); + } + + ret = len; + done: + if (req) + kfree(req); + LEAVE(); + return ret; + +} + +/** + * @brief Deauthenticate + * + * @param priv A pointer to moal_private structure + * @param respbuf A pointer to response buffer + * @param respbuflen Available length of response buffer + * + * @return Number of bytes written, negative for failure. + */ +int +woal_priv_deauth(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen) +{ + mlan_ioctl_req *req = NULL; + int ret = 0; + t_u8 mac[ETH_ALEN]; + + ENTER(); + + if (strlen(respbuf) > (strlen(CMD_MARVELL) + strlen(PRIV_CMD_DEAUTH))) { + /* Deauth mentioned BSSID */ + woal_mac2u8(mac, + respbuf + strlen(CMD_MARVELL) + strlen(PRIV_CMD_DEAUTH)); + if (MLAN_STATUS_SUCCESS != woal_disconnect(priv, MOAL_IOCTL_WAIT, mac)) { ret = -EFAULT; goto done; } - PRINTM(MIOCTL, "tx rate=%d\n", (int) rate.rate); - len = + } else { + if (MLAN_STATUS_SUCCESS != woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL)) + ret = -EFAULT; + } + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +#if defined(WIFI_DIRECT_SUPPORT) +#if defined(STA_SUPPORT) && defined(UAP_SUPPORT) +/** + * @brief Set/Get BSS role + * + * @param priv A pointer to moal_private structure + * @param respbuf A pointer to response buffer + * @param respbuflen Available length of response buffer + * + * @return Number of bytes written, negative for failure. + */ +int +woal_priv_bssrole(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen) +{ + t_u32 data[1]; + int ret = 0; + int user_data_len = 0; + t_u8 action = MLAN_ACT_GET; + + ENTER(); + + if (strlen(respbuf) == (strlen(CMD_MARVELL) + strlen(PRIV_CMD_BSSROLE))) { + /* GET operation */ + user_data_len = 0; + } else { + /* SET operation */ + memset((char *) data, 0, sizeof(data)); + parse_arguments(respbuf + strlen(CMD_MARVELL) + + strlen(PRIV_CMD_BSSROLE), data, &user_data_len); + } + + if (user_data_len >= 2) { + PRINTM(MERROR, "Invalid number of arguments\n"); + ret = -EINVAL; + goto error; + } + + if (user_data_len == 0) { + action = MLAN_ACT_GET; + } else { + if ((data[0] != MLAN_BSS_ROLE_STA && + data[0] != MLAN_BSS_ROLE_UAP) || + priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) { + PRINTM(MWARN, "Invalid BSS role\n"); + ret = -EINVAL; + goto error; + } + if (data[0] == GET_BSS_ROLE(priv)) { + PRINTM(MWARN, "Already BSS is in desired role\n"); + goto done; + } + action = MLAN_ACT_SET; + /* Reset interface */ + woal_reset_intf(priv, MOAL_IOCTL_WAIT, MFALSE); + } + + if (MLAN_STATUS_SUCCESS != woal_bss_role_cfg(priv, + action, MOAL_IOCTL_WAIT, + (t_u8 *) data)) { + ret = -EFAULT; + goto error; + } + + if (user_data_len) { + /* Initialize private structures */ + woal_init_priv(priv, MOAL_IOCTL_WAIT); + /* Enable interfaces */ + netif_device_attach(priv->netdev); + woal_start_queue(priv->netdev); + } + + done: + memset(respbuf, 0, respbuflen); + respbuf[0] = (t_u8) data[0]; + ret = 1; + + error: + LEAVE(); + return ret; +} +#endif /* STA_SUPPORT && UAP_SUPPORT */ +#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */ + +#ifdef STA_SUPPORT +/** + * @brief Set user scan + * + * @param priv A pointer to moal_private structure + * @param respbuf A pointer to response buffer + * @param respbuflen Available length of response buffer + * + * @return Number of bytes written, negative for failure. + */ +int +woal_priv_setuserscan(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen) +{ + wlan_user_scan_cfg scan_cfg; + int ret = 0; + + ENTER(); + + /* Create the scan_cfg structure */ + memset(&scan_cfg, 0, sizeof(scan_cfg)); + + /* We expect the scan_cfg structure to be passed in respbuf */ + memcpy((char *) &scan_cfg, + respbuf + strlen(CMD_MARVELL) + strlen(PRIV_CMD_SETUSERSCAN), + sizeof(wlan_user_scan_cfg)); + + /* Call for scan */ + if (MLAN_STATUS_FAILURE == woal_do_scan(priv, &scan_cfg)) + ret = -EFAULT; + + LEAVE(); + return ret; +} +#endif + +/** + * @brief Set/Get deep sleep mode configurations + * + * @param priv A pointer to moal_private structure + * @param respbuf A pointer to response buffer + * @param respbuflen Available length of response buffer + * + * @return Number of bytes written, negative for failure. + */ +int +woal_priv_setgetdeepsleep(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen) +{ + t_u32 data[2]; + int ret = 0; + int user_data_len = 0; + + ENTER(); + + if (strlen(respbuf) == (strlen(CMD_MARVELL) + strlen(PRIV_CMD_DEEPSLEEP))) { + /* GET operation */ + user_data_len = 0; + } else { + /* SET operation */ + memset((char *) data, 0, sizeof(data)); + parse_arguments(respbuf + strlen(CMD_MARVELL) + + strlen(PRIV_CMD_DEEPSLEEP), data, &user_data_len); + } + + if (user_data_len >= 3) { + PRINTM(MERROR, "Invalid number of arguments\n"); + ret = -EINVAL; + goto done; + } + + if (user_data_len == 0) { + if (MLAN_STATUS_SUCCESS != woal_get_deep_sleep(priv, data)) { + ret = -EFAULT; + goto done; + } + sprintf(respbuf, "%d %d", data[0], data[1]); + ret = strlen(respbuf) + 1; + } else { + if (data[0] == DEEP_SLEEP_OFF) { + PRINTM(MINFO, "Exit Deep Sleep Mode\n"); + ret = woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MFALSE, 0); + if (ret != MLAN_STATUS_SUCCESS) { + ret = -EINVAL; + goto done; + } + } else if (data[0] == DEEP_SLEEP_ON) { + PRINTM(MINFO, "Enter Deep Sleep Mode\n"); + if (user_data_len != 2) + data[1] = 0; + ret = woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MTRUE, data[1]); + if (ret != MLAN_STATUS_SUCCESS) { + ret = -EINVAL; + goto done; + } + } else { + PRINTM(MERROR, "Unknown option = %u\n", data[0]); + ret = -EINVAL; + goto done; + } + ret = sprintf(respbuf, "OK\n") + 1; + } + + done: + LEAVE(); + return ret; + +} + +/** + * @brief Set/Get IP address configurations + * + * @param priv A pointer to moal_private structure + * @param respbuf A pointer to response buffer + * @param respbuflen Available length of response buffer + * + * @return Number of bytes written, negative for failure. + */ +int +woal_priv_setgetipaddr(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_misc_cfg *misc = NULL; + int ret = 0, op_code = 0, data_length = 0, header = 0; + + ENTER(); + + header = strlen(CMD_MARVELL) + strlen(PRIV_CMD_IPADDR); + data_length = strlen(respbuf) - header; + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + misc = (mlan_ds_misc_cfg *) req->pbuf; + + if (data_length < 1) { /* GET */ + req->action = MLAN_ACT_GET; + } else { + /* Make sure we have the operation argument */ + if (data_length > 2 && respbuf[header + 1] != ';') { + PRINTM(MERROR, "No operation argument. Separate with ';'\n"); + ret = -EINVAL; + goto done; + } else { + respbuf[header + 1] = '\0'; + } + req->action = MLAN_ACT_SET; + + /* Only one IP is supported in current firmware */ + memset(misc->param.ipaddr_cfg.ip_addr[0], 0, IPADDR_LEN); + in4_pton(&respbuf[header + 2], + MIN((IPADDR_MAX_BUF - 3), (data_length - 2)), + misc->param.ipaddr_cfg.ip_addr[0], ' ', NULL); + misc->param.ipaddr_cfg.ip_addr_num = 1; + misc->param.ipaddr_cfg.ip_addr_type = IPADDR_TYPE_IPV4; + + if (woal_atoi(&op_code, &respbuf[header]) != MLAN_STATUS_SUCCESS) { + ret = -EINVAL; + goto done; + } + misc->param.ipaddr_cfg.op_code = (t_u32) op_code; + } + + req->req_id = MLAN_IOCTL_MISC_CFG; + misc->sub_command = MLAN_OID_MISC_IP_ADDR; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + if (req->action == MLAN_ACT_GET) { + snprintf(respbuf, IPADDR_MAX_BUF, "%d;%d.%d.%d.%d", + misc->param.ipaddr_cfg.op_code, + misc->param.ipaddr_cfg.ip_addr[0][0], + misc->param.ipaddr_cfg.ip_addr[0][1], + misc->param.ipaddr_cfg.ip_addr[0][2], + misc->param.ipaddr_cfg.ip_addr[0][3]); + ret = IPADDR_MAX_BUF + 1; + } else { + ret = sprintf(respbuf, "OK\n") + 1; + } + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Set/Get WPS session configurations + * + * @param priv A pointer to moal_private structure + * @param respbuf A pointer to response buffer + * @param respbuflen Available length of response buffer + * + * @return Number of bytes written, negative for failure. + */ +int +woal_priv_setwpssession(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_wps_cfg *pwps = NULL; + t_u32 data[1]; + int ret = 0; + int user_data_len = 0; + + ENTER(); + + if (strlen(respbuf) == (strlen(CMD_MARVELL) + strlen(PRIV_CMD_WPSSESSION))) { + /* GET operation */ + user_data_len = 0; + } else { + /* SET operation */ + memset((char *) data, 0, sizeof(data)); + parse_arguments(respbuf + strlen(CMD_MARVELL) + + strlen(PRIV_CMD_WPSSESSION), data, &user_data_len); + } + + if (user_data_len != 1) { + PRINTM(MERROR, "Invalid number of arguments\n"); + ret = -EINVAL; + goto done; + } + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wps_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + pwps = (mlan_ds_wps_cfg *) req->pbuf; + + req->req_id = MLAN_IOCTL_WPS_CFG; + req->action = MLAN_ACT_SET; + pwps->sub_command = MLAN_OID_WPS_CFG_SESSION; + + if (data[0] == 1) + pwps->param.wps_session = MLAN_WPS_CFG_SESSION_START; + else + pwps->param.wps_session = MLAN_WPS_CFG_SESSION_END; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + + ret = sprintf(respbuf, "OK\n") + 1; + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Get OTP user data + * + * @param priv A pointer to moal_private structure + * @param respbuf A pointer to response buffer + * @param respbuflen Available length of response buffer + * + * @return Number of bytes written, negative for failure. + */ +int +woal_priv_otpuserdata(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen) +{ + int data[1]; + int user_data_len = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_misc_cfg *misc = NULL; + mlan_ds_misc_otp_user_data *otp = NULL; + int ret = 0; + + ENTER(); + + memset((char *) data, 0, sizeof(data)); + parse_arguments(respbuf + strlen(CMD_MARVELL) + + strlen(PRIV_CMD_OTPUSERDATA), data, &user_data_len); + + if (user_data_len > 1) { + PRINTM(MERROR, "Too many arguments\n"); + LEAVE(); + return -EINVAL; + } + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + req->action = MLAN_ACT_GET; + req->req_id = MLAN_IOCTL_MISC_CFG; + + misc = (mlan_ds_misc_cfg *) req->pbuf; + misc->sub_command = MLAN_OID_MISC_OTP_USER_DATA; + misc->param.otp_user_data.user_data_length = data[0]; + + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + otp = (mlan_ds_misc_otp_user_data *) req->pbuf; + + if (req->action == MLAN_ACT_GET) { + ret = MIN(otp->user_data_length, data[0]); + memcpy(respbuf, otp->user_data, ret); + } + + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} + +/** + * @brief Set / Get country code + * + * @param priv A pointer to moal_private structure + * @param respbuf A pointer to response buffer + * @param respbuflen Available length of response buffer + * + * @return Number of bytes written, negative for failure. + */ +int +woal_priv_set_get_countrycode(moal_private * priv, t_u8 * respbuf, + t_u32 respbuflen) +{ + int ret = 0; + // char data[COUNTRY_CODE_LEN] = {0, 0, 0}; + int header = 0, data_length = 0; // wrq->u.data.length; + mlan_ioctl_req *req = NULL; + mlan_ds_misc_cfg *pcfg_misc = NULL; + mlan_ds_misc_country_code *country_code = NULL; + + ENTER(); + + header = strlen(CMD_MARVELL) + strlen(PRIV_CMD_COUNTRYCODE); + data_length = strlen(respbuf) - header; + + if (data_length > COUNTRY_CODE_LEN) { + PRINTM(MERROR, "Invalid argument!\n"); + ret = -EINVAL; + goto done; + } + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + pcfg_misc = (mlan_ds_misc_cfg *) req->pbuf; + country_code = &pcfg_misc->param.country_code; + pcfg_misc->sub_command = MLAN_OID_MISC_COUNTRY_CODE; + req->req_id = MLAN_IOCTL_MISC_CFG; + + if (data_length <= 1) { + req->action = MLAN_ACT_GET; + } else { + memset(country_code->country_code, 0, COUNTRY_CODE_LEN); + memcpy(country_code->country_code, respbuf + header, COUNTRY_CODE_LEN); + req->action = MLAN_ACT_SET; + } + + /* Send IOCTL request to MLAN */ + if (woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT) != MLAN_STATUS_SUCCESS) { + ret = -EFAULT; + goto done; + } + + if (req->action == MLAN_ACT_GET) { + ret = data_length = COUNTRY_CODE_LEN; + memset(respbuf + header, 0, COUNTRY_CODE_LEN); + memcpy(respbuf, country_code->country_code, COUNTRY_CODE_LEN); + } + + done: + if (req) + kfree(req); + + LEAVE(); + return ret; +} + +/** + * @brief Set/Get TCP Ack enhancement configurations + * + * @param priv A pointer to moal_private structure + * @param respbuf A pointer to response buffer + * @param respbuflen Available length of response buffer + * + * @return Number of bytes written, negative for failure. + */ +int +woal_priv_setgettcpackenh(moal_private * priv, t_u8 * respbuf, t_u32 respbuflen) +{ + t_u32 data[1]; + int ret = 0; + int user_data_len = 0; + struct list_head *link = NULL; + struct tcp_sess *tcp_sess = NULL; + + ENTER(); + + if (strlen(respbuf) == (strlen(CMD_MARVELL) + strlen(PRIV_CMD_TCPACKENH))) { + /* GET operation */ + user_data_len = 0; + } else { + /* SET operation */ + memset((char *) data, 0, sizeof(data)); + parse_arguments(respbuf + strlen(CMD_MARVELL) + + strlen(PRIV_CMD_TCPACKENH), data, &user_data_len); + } + + if (user_data_len >= 2) { + PRINTM(MERROR, "Invalid number of arguments\n"); + ret = -EINVAL; + goto done; + } + + if (user_data_len == 0) { + /* get operation */ + respbuf[0] = priv->enable_tcp_ack_enh; + } else { + /* set operation */ + if (data[0] == MTRUE) { + PRINTM(MINFO, "Enabling TCP Ack enhancement\n"); + priv->enable_tcp_ack_enh = MTRUE; + } else if (data[0] == MFALSE) { + PRINTM(MINFO, "Disabling TCP Ack enhancement\n"); + priv->enable_tcp_ack_enh = MFALSE; + /* release the tcp sessions if any */ + while (!list_empty(&priv->tcp_sess_queue)) { + link = priv->tcp_sess_queue.next; + tcp_sess = list_entry(link, struct tcp_sess, link); + PRINTM(MINFO, + "Disable TCP ACK Enh: release a tcp session in dl. (src: ipaddr 0x%08x, port: %d. dst: ipaddr 0x%08x, port: %d\n", + tcp_sess->src_ip_addr, tcp_sess->src_tcp_port, + tcp_sess->dst_ip_addr, tcp_sess->dst_tcp_port); + list_del(link); + kfree(tcp_sess); + } + } else { + PRINTM(MERROR, "Unknown option = %u\n", data[0]); + ret = -EINVAL; + goto done; + } + respbuf[0] = priv->enable_tcp_ack_enh; + } + ret = 1; + + done: + LEAVE(); + return ret; + +} + +/** + * @brief Set priv command for Android + * @param dev A pointer to net_device structure + * @param req A pointer to ifreq structure + * + * @return 0 --success, otherwise fail + */ +int +woal_android_priv_cmd(struct net_device *dev, struct ifreq *req) +{ + int ret = 0; + android_wifi_priv_cmd priv_cmd; + moal_private *priv = (moal_private *) netdev_priv(dev); + char *buf = NULL; + char *pdata; +#ifdef STA_SUPPORT + int power_mode = 0; + int band = 0; + char *pband = NULL; + mlan_bss_info bss_info; + mlan_ds_get_signal signal; + mlan_rate_cfg_t rate; + t_u8 country_code[COUNTRY_CODE_LEN]; +#endif + int len = 0; + + ENTER(); + if (copy_from_user(&priv_cmd, req->ifr_data, sizeof(android_wifi_priv_cmd))) { + ret = -EFAULT; + goto done; + } + buf = kzalloc(priv_cmd.total_len, GFP_KERNEL); + if (!buf) { + PRINTM(MERROR, "%s: failed to allocate memory\n", __FUNCTION__); + ret = -ENOMEM; + goto done; + } + if (copy_from_user(buf, priv_cmd.buf, priv_cmd.total_len)) { + ret = -EFAULT; + goto done; + } + + PRINTM(MIOCTL, "Android priv cmd: [%s] on [%s]\n", buf, req->ifr_name); + + if (strncmp(buf, CMD_MARVELL, strlen(CMD_MARVELL)) == 0) { + /* This command has come from mlanutl app */ + + /* Check command */ + if (strnicmp + (buf + strlen(CMD_MARVELL), PRIV_CMD_VERSION, + strlen(PRIV_CMD_VERSION)) == 0) { + /* Get version */ + len = woal_get_priv_driver_version(priv, buf, priv_cmd.total_len); + goto handled; + } else + if (strnicmp + (buf + strlen(CMD_MARVELL), PRIV_CMD_BANDCFG, + strlen(PRIV_CMD_BANDCFG)) == 0) { + /* Set/Get band configuration */ + len = woal_setget_priv_bandcfg(priv, buf, priv_cmd.total_len); + goto handled; + } else + if (strnicmp + (buf + strlen(CMD_MARVELL), PRIV_CMD_HOSTCMD, + strlen(PRIV_CMD_HOSTCMD)) == 0) { + /* hostcmd configuration */ + len = woal_priv_hostcmd(priv, buf, priv_cmd.total_len); + goto handled; + } else + if (strnicmp + (buf + strlen(CMD_MARVELL), PRIV_CMD_HTTXCFG, + strlen(PRIV_CMD_HTTXCFG)) == 0) { + /* Set/Get HT Tx configuration */ + len = woal_setget_priv_httxcfg(priv, buf, priv_cmd.total_len); + goto handled; + } else + if (strnicmp + (buf + strlen(CMD_MARVELL), PRIV_CMD_DATARATE, + strlen(PRIV_CMD_DATARATE)) == 0) { + /* Get data rate */ + len = woal_get_priv_datarate(priv, buf, priv_cmd.total_len); + goto handled; + } else + if (strnicmp + (buf + strlen(CMD_MARVELL), PRIV_CMD_TXRATECFG, + strlen(PRIV_CMD_TXRATECFG)) == 0) { + /* Set/Get tx rate cfg */ + len = woal_setget_priv_txratecfg(priv, buf, priv_cmd.total_len); + goto handled; + } else + if (strnicmp + (buf + strlen(CMD_MARVELL), PRIV_CMD_CUSTOMIE, + strlen(PRIV_CMD_CUSTOMIE)) == 0) { + /* Custom IE configuration */ + len = woal_priv_customie(priv, buf, priv_cmd.total_len); + goto handled; + } else + if (strnicmp + (buf + strlen(CMD_MARVELL), PRIV_CMD_ESUPPMODE, + strlen(PRIV_CMD_ESUPPMODE)) == 0) { + /* Esupplicant mode configuration */ + len = woal_setget_priv_esuppmode(priv, buf, priv_cmd.total_len); + goto handled; + } else + if (strnicmp + (buf + strlen(CMD_MARVELL), PRIV_CMD_PASSPHRASE, + strlen(PRIV_CMD_PASSPHRASE)) == 0) { + /* Esupplicant passphrase configuration */ + len = woal_setget_priv_passphrase(priv, buf, priv_cmd.total_len); + goto handled; + } else + if (strnicmp + (buf + strlen(CMD_MARVELL), PRIV_CMD_DEAUTH, + strlen(PRIV_CMD_DEAUTH)) == 0) { + /* Deauth */ + len = woal_priv_deauth(priv, buf, priv_cmd.total_len); + goto handled; +#if defined(WIFI_DIRECT_SUPPORT) +#if defined(STA_SUPPORT) && defined(UAP_SUPPORT) + } else + if (strnicmp + (buf + strlen(CMD_MARVELL), PRIV_CMD_BSSROLE, + strlen(PRIV_CMD_BSSROLE)) == 0) { + /* BSS Role */ + len = woal_priv_bssrole(priv, buf, priv_cmd.total_len); + goto handled; +#endif +#endif +#ifdef STA_SUPPORT + } else + if (strnicmp + (buf + strlen(CMD_MARVELL), PRIV_CMD_SETUSERSCAN, + strlen(PRIV_CMD_SETUSERSCAN)) == 0) { + /* Set user scan */ + len = woal_priv_setuserscan(priv, buf, priv_cmd.total_len); + goto handled; +#endif + } else + if (strnicmp + (buf + strlen(CMD_MARVELL), PRIV_CMD_DEEPSLEEP, + strlen(PRIV_CMD_DEEPSLEEP)) == 0) { + /* Deep sleep */ + len = woal_priv_setgetdeepsleep(priv, buf, priv_cmd.total_len); + goto handled; + } else + if (strnicmp + (buf + strlen(CMD_MARVELL), PRIV_CMD_IPADDR, + strlen(PRIV_CMD_IPADDR)) == 0) { + /* IP address */ + len = woal_priv_setgetipaddr(priv, buf, priv_cmd.total_len); + goto handled; + } else + if (strnicmp + (buf + strlen(CMD_MARVELL), PRIV_CMD_WPSSESSION, + strlen(PRIV_CMD_WPSSESSION)) == 0) { + /* WPS Session */ + len = woal_priv_setwpssession(priv, buf, priv_cmd.total_len); + goto handled; + } else + if (strnicmp + (buf + strlen(CMD_MARVELL), PRIV_CMD_OTPUSERDATA, + strlen(PRIV_CMD_OTPUSERDATA)) == 0) { + /* OTP user data */ + len = woal_priv_otpuserdata(priv, buf, priv_cmd.total_len); + goto handled; + } else + if (strnicmp + (buf + strlen(CMD_MARVELL), PRIV_CMD_COUNTRYCODE, + strlen(PRIV_CMD_COUNTRYCODE)) == 0) { + /* OTP user data */ + len = woal_priv_set_get_countrycode(priv, buf, priv_cmd.total_len); + goto handled; + } else + if (strnicmp + (buf + strlen(CMD_MARVELL), PRIV_CMD_TCPACKENH, + strlen(PRIV_CMD_TCPACKENH)) == 0) { + /* OTP user data */ + len = woal_priv_setgettcpackenh(priv, buf, priv_cmd.total_len); + goto handled; + } else { + /* Fall through, after stripping off the custom header */ + buf += strlen(CMD_MARVELL); + } + } +#ifdef STA_SUPPORT + if (strncmp(buf, "RSSILOW-THRESHOLD", strlen("RSSILOW-THRESHOLD")) == 0) { + pdata = buf + strlen("RSSILOW-THRESHOLD") + 1; + if (MLAN_STATUS_SUCCESS != woal_set_rssi_low_threshold(priv, pdata)) { + ret = -EFAULT; + goto done; + } + len = sprintf(buf, "OK\n") + 1; + } else if (strncmp(buf, "RSSI", strlen("RSSI")) == 0) { + if (MLAN_STATUS_SUCCESS != woal_get_bss_info(priv, + MOAL_IOCTL_WAIT, + &bss_info)) { + ret = -EFAULT; + goto done; + } + if (bss_info.media_connected) { + if (MLAN_STATUS_SUCCESS != woal_get_signal_info(priv, + MOAL_IOCTL_WAIT, + &signal)) { + ret = -EFAULT; + goto done; + } + len = sprintf(buf, "%s rssi %d\n", bss_info.ssid.ssid, + signal.bcn_rssi_avg) + 1; + } else { + len = sprintf(buf, "OK\n") + 1; + } + } else if (strncmp(buf, "LINKSPEED", strlen("LINKSPEED")) == 0) { + if (MLAN_STATUS_SUCCESS != woal_set_get_data_rate(priv, MLAN_ACT_GET, + &rate)) { + ret = -EFAULT; + goto done; + } + PRINTM(MIOCTL, "tx rate=%d\n", (int) rate.rate); + len = sprintf(buf, "LinkSpeed %d\n", (int) (rate.rate * 500000 / 1000000)) + 1; } else @@ -983,12 +1987,14 @@ woal_android_priv_cmd(struct net_device *dev, struct ifreq *req) priv->bg_scan_reported = MFALSE; len = sprintf(buf, "OK\n") + 1; } else if (strncmp(buf, "BGSCAN-STOP", strlen("BGSCAN-STOP")) == 0) { - if (MLAN_STATUS_SUCCESS != woal_stop_bg_scan(priv)) { - ret = -EFAULT; - goto done; + if (priv->bg_scan_start && !priv->scan_cfg.rssi_threshold) { + if (MLAN_STATUS_SUCCESS != woal_stop_bg_scan(priv)) { + ret = -EFAULT; + goto done; + } + priv->bg_scan_start = MFALSE; + priv->bg_scan_reported = MFALSE; } - priv->bg_scan_start = MFALSE; - priv->bg_scan_reported = MFALSE; len = sprintf(buf, "OK\n") + 1; } else if (strncmp(buf, "RXFILTER-START", strlen("RXFILTER-START")) == 0) { #ifdef MEF_CFG_RX_FILTER @@ -1004,7 +2010,19 @@ woal_android_priv_cmd(struct net_device *dev, struct ifreq *req) } #endif len = sprintf(buf, "OK\n") + 1; - } else if (strncmp(buf, "RXFILTER-ADD", strlen("RXFILTER-ADD")) == 0) { + } +#ifdef STA_CFG80211 + else if (strncmp(buf, "GET_RSSI_STATUS", strlen("GET_RSSI_STATUS")) == 0) { + if (priv->rssi_status == MLAN_EVENT_ID_FW_BCN_RSSI_LOW) + len = sprintf(buf, "EVENT=BEACON_RSSI_LOW\n"); + else if (priv->rssi_status == MLAN_EVENT_ID_FW_PRE_BCN_LOST) + len = sprintf(buf, "EVENT=PRE_BEACON_LOST\n"); + else + len = sprintf(buf, "OK\n") + 1; + priv->rssi_status = 0; + } +#endif + else if (strncmp(buf, "RXFILTER-ADD", strlen("RXFILTER-ADD")) == 0) { pdata = buf + strlen("RXFILTER-ADD") + 1; if (MLAN_STATUS_SUCCESS != woal_add_rxfilter(priv, pdata)) { ret = -EFAULT; @@ -1071,10 +2089,20 @@ woal_android_priv_cmd(struct net_device *dev, struct ifreq *req) if (len > 0) { priv_cmd.used_len = len; - if (copy_to_user(priv_cmd.buf, buf, len)) { + if (priv_cmd.used_len < priv_cmd.total_len) + memset(priv_cmd.buf + priv_cmd.used_len, 0, + priv_cmd.total_len - priv_cmd.used_len); + if (copy_to_user(priv_cmd.buf, buf, priv_cmd.used_len)) { PRINTM(MERROR, "%s: failed to copy data to user buffer\n", __FUNCTION__); ret = -EFAULT; + goto done; + } + if (copy_to_user + (req->ifr_data, &priv_cmd, sizeof(android_wifi_priv_cmd))) { + PRINTM(MERROR, "%s: failed to copy command header to user buffer\n", + __FUNCTION__); + ret = -EFAULT; } } else { ret = len; diff --git a/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.h b/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.h index a1481e88ff21..a68991694a9d 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.h +++ b/drivers/net/wireless/sd8797/mlinux/moal_eth_ioctl.h @@ -44,12 +44,23 @@ Change log: /** Private command ID to get BSS type */ #define WOAL_GET_BSS_TYPE (SIOCDEVPRIVATE + 15) -int woal_do_ioctl(struct net_device *dev, struct ifreq *req, int i); +int woal_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd); +/* + * For android private commands, fixed value of ioctl is used. + * Internally commands are differentiated using strings. + * + * application needs to specify "total_len" of data for copy_from_user + * kernel updates "used_len" during copy_to_user + */ +/** Private command structure from app */ typedef struct _android_wifi_priv_cmd { + /** Buffer pointer */ char *buf; + /** buffer updated by driver */ int used_len; + /** buffer sent by application */ int total_len; } android_wifi_priv_cmd; @@ -62,6 +73,16 @@ typedef struct woal_priv_tx_rate_cfg t_u32 rate_index; } woal_tx_rate_cfg; +typedef struct woal_priv_esuppmode_cfg +{ + /* RSN mode */ + t_u16 rsn_mode; + /* Pairwise cipher */ + t_u8 pairwise_cipher; + /* Group cipher */ + t_u8 group_cipher; +} woal_esuppmode_cfg; + mlan_status woal_set_ap_wps_p2p_ie(moal_private * priv, t_u8 * ie, size_t len); int woal_android_priv_cmd(struct net_device *dev, struct ifreq *req); diff --git a/drivers/net/wireless/sd8797/mlinux/moal_ioctl.c b/drivers/net/wireless/sd8797/mlinux/moal_ioctl.c index efe6e7ddcea1..94fe7e11669e 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_ioctl.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_ioctl.c @@ -2,7 +2,7 @@ * * @brief This file contains ioctl function to MLAN * - * Copyright (C) 2008-2011, Marvell International Ltd. + * Copyright (C) 2008-2012, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 @@ -792,7 +792,7 @@ woal_set_get_retry(moal_private * priv, t_u32 action, #ifdef STA_CFG80211 /* If set is invoked from other than iw i.e iwconfig, wiphy retry count should be updated as well */ - if (IS_STA_CFG80211(cfg80211_wext) && + if (IS_STA_CFG80211(cfg80211_wext) && priv->wdev && priv->wdev->wiphy && (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && (action == MLAN_ACT_SET)) { priv->wdev->wiphy->retry_long = (t_u8) * value; priv->wdev->wiphy->retry_short = (t_u8) * value; @@ -854,7 +854,7 @@ woal_set_get_rts(moal_private * priv, t_u32 action, #ifdef STA_CFG80211 /* If set is invoked from other than iw i.e iwconfig, wiphy RTS threshold should be updated as well */ - if (IS_STA_CFG80211(cfg80211_wext) && + if (IS_STA_CFG80211(cfg80211_wext) && priv->wdev && priv->wdev->wiphy && (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && (action == MLAN_ACT_SET)) priv->wdev->wiphy->rts_threshold = *value; #endif @@ -914,7 +914,7 @@ woal_set_get_frag(moal_private * priv, t_u32 action, #ifdef STA_CFG80211 /* If set is invoked from other than iw i.e iwconfig, wiphy fragment threshold should be updated as well */ - if (IS_STA_CFG80211(cfg80211_wext) && + if (IS_STA_CFG80211(cfg80211_wext) && priv->wdev && priv->wdev->wiphy && (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && (action == MLAN_ACT_SET)) priv->wdev->wiphy->frag_threshold = *value; #endif @@ -1096,7 +1096,7 @@ woal_set_get_power_mgmt(moal_private * priv, #ifdef STA_CFG80211 /* If set is invoked from other than iw i.e iwconfig, wiphy IEEE power save mode should be updated */ - if (IS_STA_CFG80211(cfg80211_wext) && + if (IS_STA_CFG80211(cfg80211_wext) && priv->wdev && (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) && (action == MLAN_ACT_SET)) { if (*disabled) priv->wdev->ps = MFALSE; @@ -1780,20 +1780,22 @@ woal_get_bss_type(struct net_device *dev, struct ifreq *req) #if defined(STA_SUPPORT) && defined(UAP_SUPPORT) #if defined(STA_WEXT) || defined(UAP_WEXT) /** - * @brief Set/Get BSS role + * @brief Swithces BSS role of WFD interface * - * @param priv A pointer to moal_private structure - * @param wrq A pointer to iwreq structure + * @param priv A pointer to moal_private structure + * @param action Action: set or get + * @param wait_option Wait option (MOAL_WAIT or MOAL_NO_WAIT) + * @param bss_role A pointer to bss role * * @return 0 --success, otherwise fail */ -int -woal_set_get_bss_role(moal_private * priv, struct iwreq *wrq) +mlan_status +woal_bss_role_cfg(moal_private * priv, t_u8 action, + t_u8 wait_option, t_u8 * bss_role) { int ret = 0; mlan_ds_bss *bss = NULL; mlan_ioctl_req *req = NULL; - int bss_role = 0; struct net_device *dev = priv->netdev; ENTER(); @@ -1812,55 +1814,26 @@ woal_set_get_bss_role(moal_private * priv, struct iwreq *wrq) bss = (mlan_ds_bss *) req->pbuf; bss->sub_command = MLAN_OID_BSS_ROLE; req->req_id = MLAN_IOCTL_BSS; - if (wrq->u.data.length) { - if (copy_from_user(&bss_role, wrq->u.data.pointer, sizeof(int))) { - PRINTM(MERROR, "Copy from user failed\n"); - ret = -EFAULT; - goto done; - } - if (bss_role != MLAN_BSS_ROLE_STA && bss_role != MLAN_BSS_ROLE_UAP) { - PRINTM(MWARN, "Invalid BSS role\n"); - ret = -EINVAL; - goto done; - } - if (bss_role == GET_BSS_ROLE(priv)) { - PRINTM(MWARN, "Already BSS is in desired role\n"); - ret = -EINVAL; - goto done; - } - req->action = MLAN_ACT_SET; - bss->param.bss_role = (t_u8) bss_role; - } else { - req->action = MLAN_ACT_GET; - } - - if (req->action == MLAN_ACT_SET) { - /* Reset interface */ - woal_reset_intf(priv, MOAL_IOCTL_WAIT, MFALSE); + req->action = action; + if (action == MLAN_ACT_SET) { + bss->param.bss_role = *bss_role; } - if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, wait_option)) { ret = -EFAULT; goto done; } - if (!wrq->u.data.length) { - bss_role = (int) bss->param.bss_role; - if (copy_to_user(wrq->u.data.pointer, &bss_role, sizeof(int))) { - ret = -EFAULT; - goto done; - } - wrq->u.data.length = 1; + + if (action == MLAN_ACT_GET) { + *bss_role = bss->param.bss_role; } else { /* Update moal_private */ - priv->bss_role = bss_role; + priv->bss_role = *bss_role; if (priv->bss_type == MLAN_BSS_TYPE_UAP) priv->bss_type = MLAN_BSS_TYPE_STA; else if (priv->bss_type == MLAN_BSS_TYPE_STA) priv->bss_type = MLAN_BSS_TYPE_UAP; - /* Initialize private structures */ - woal_init_priv(priv, MOAL_IOCTL_WAIT); - - if (bss_role == MLAN_BSS_ROLE_UAP) { + if (*bss_role == MLAN_BSS_ROLE_UAP) { /* Switch: STA -> uAP */ /* Setup the OS Interface to our functions */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) @@ -1881,7 +1854,7 @@ woal_set_get_bss_role(moal_private * priv, struct iwreq *wrq) init_waitqueue_head(&priv->w_stats_wait_q); } #endif /* UAP_WEXT */ - } else if (bss_role == MLAN_BSS_ROLE_STA) { + } else if (*bss_role == MLAN_BSS_ROLE_STA) { /* Switch: uAP -> STA */ /* Setup the OS Interface to our functions */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) @@ -1903,9 +1876,6 @@ woal_set_get_bss_role(moal_private * priv, struct iwreq *wrq) } #endif /* STA_WEXT */ } - /* Enable interfaces */ - netif_device_attach(dev); - woal_start_queue(dev); } done: @@ -1914,8 +1884,75 @@ woal_set_get_bss_role(moal_private * priv, struct iwreq *wrq) LEAVE(); return ret; } -#endif -#endif + +/** + * @brief Set/Get BSS role + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +int +woal_set_get_bss_role(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + int bss_role = 0; + t_u8 action = MLAN_ACT_GET; + + ENTER(); + + if (wrq->u.data.length) { + if (copy_from_user(&bss_role, wrq->u.data.pointer, sizeof(int))) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + if ((bss_role != MLAN_BSS_ROLE_STA && + bss_role != MLAN_BSS_ROLE_UAP) || + (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT)) { + PRINTM(MWARN, "Invalid BSS role\n"); + ret = -EINVAL; + goto done; + } + if (bss_role == GET_BSS_ROLE(priv)) { + PRINTM(MWARN, "Already BSS is in desired role\n"); + ret = -EINVAL; + goto done; + } + action = MLAN_ACT_SET; + /* Reset interface */ + woal_reset_intf(priv, MOAL_IOCTL_WAIT, MFALSE); + } + + if (MLAN_STATUS_SUCCESS != woal_bss_role_cfg(priv, + action, MOAL_IOCTL_WAIT, + (t_u8 *) & bss_role)) { + ret = -EFAULT; + goto done; + } + + if (!wrq->u.data.length) { + if (copy_to_user(wrq->u.data.pointer, &bss_role, sizeof(int))) { + ret = -EFAULT; + goto done; + } + wrq->u.data.length = 1; + } else { + /* Initialize private structures */ + woal_init_priv(priv, MOAL_IOCTL_WAIT); + + /* Enable interfaces */ + netif_device_attach(priv->netdev); + woal_start_queue(priv->netdev); + } + + done: + LEAVE(); + return ret; +} +#endif /* STA_WEXT || UAP_WEXT */ +#endif /* STA_SUPPORT && UAP_SUPPORT */ #endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */ /** @@ -1993,6 +2030,7 @@ woal_cancel_hs(moal_private * priv, t_u8 wait_option) return ret; } +#if defined(SDIO_SUSPEND_RESUME) /** @brief This function enables the host sleep * * @param priv A Pointer to the moal_private structure @@ -2074,6 +2112,7 @@ woal_enable_hs(moal_private * priv) LEAVE(); return hs_actived; } +#endif /** * @brief This function send soft_reset command to firmware @@ -2524,6 +2563,48 @@ woal_get_pm_info(moal_private * priv, mlan_ds_ps_info * pm_info) return ret; } +/** + * @brief Get Deep Sleep + * + * @param priv Pointer to the moal_private driver data struct + * @param data Pointer to return deep_sleep setting + * + * @return 0 --success, otherwise fail + */ +int +woal_get_deep_sleep(moal_private * priv, t_u32 * data) +{ + int ret = 0; + mlan_ioctl_req *req = NULL; + mlan_ds_pm_cfg *pm = NULL; + + ENTER(); + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg)); + if (req == NULL) { + LEAVE(); + return -ENOMEM; + } + pm = (mlan_ds_pm_cfg *) req->pbuf; + pm->sub_command = MLAN_OID_PM_CFG_DEEP_SLEEP; + req->req_id = MLAN_IOCTL_PM_CFG; + + req->action = MLAN_ACT_GET; + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + *data = pm->param.auto_deep_sleep.auto_ds; + *(data + 1) = pm->param.auto_deep_sleep.idletime; + + done: + if (req) + kfree(req); + + LEAVE(); + return ret; +} + /** * @brief Set Deep Sleep * @@ -2665,8 +2746,7 @@ woal_11h_channel_check_ioctl(moal_private * priv) * @return MLAN_STATUS_SUCCESS -- success, otherwise fail */ mlan_status -woal_cfg80211_wifi_direct_mode_cfg(moal_private * priv, t_u16 action, - t_u16 * mode) +woal_wifi_direct_mode_cfg(moal_private * priv, t_u16 action, t_u16 * mode) { mlan_status ret = MLAN_STATUS_SUCCESS; mlan_ioctl_req *req = NULL; @@ -3640,6 +3720,13 @@ woal_set_bg_scan(moal_private * priv, char *buf, int length) ptr += 2; buf_left -= 2; break; + case WEXT_BGSCAN_REPEAT_SECTION: + priv->scan_cfg.repeat_count = (t_u16) ptr[1]; + PRINTM(MIOCTL, "BG scan: repeat_count=%d\n", + (int) priv->scan_cfg.repeat_count); + ptr += 2; + buf_left -= 2; + break; case WEXT_BGSCAN_INTERVAL_SECTION: priv->scan_cfg.scan_interval = (ptr[2] << 8 | ptr[1]) * 1000; PRINTM(MIOCTL, "BG scan: scan_interval=%d\n", @@ -3728,7 +3815,7 @@ woal_reconfig_bgscan(moal_handle * handle) * @brief set rssi low threshold * * @param priv A pointer to moal_private structure - * @param scan_type MLAN_SCAN_TYPE_ACTIVE/MLAN_SCAN_TYPE_PASSIVE + * @param rssi A pointer to low rssi * * @return MLAN_STATUS_SUCCESS -- success, otherwise fail */ @@ -3754,10 +3841,16 @@ woal_set_rssi_low_threshold(moal_private * priv, char *rssi) misc->sub_command = MLAN_OID_MISC_SUBSCRIBE_EVENT; req->action = MLAN_ACT_SET; misc->param.subscribe_event.evt_bitmap = SUBSCRIBE_EVT_RSSI_LOW; + misc->param.subscribe_event.evt_bitmap |= SUBSCRIBE_EVT_PRE_BEACON_LOST; + misc->param.subscribe_event.pre_beacon_miss = DEFAULT_PRE_BEACON_MISS; + if (MLAN_STATUS_SUCCESS != woal_atoi(&low_rssi, rssi)) { ret = -EFAULT; goto done; } +#ifdef STA_CFG80211 + priv->mrvl_rssi_low = low_rssi; +#endif misc->param.subscribe_event.low_rssi = low_rssi; misc->param.subscribe_event.low_rssi_freq = 0; if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { @@ -3771,6 +3864,69 @@ woal_set_rssi_low_threshold(moal_private * priv, char *rssi) return ret; } +#ifdef STA_CFG80211 +/** + * @brief set rssi low threshold + * + * @param priv A pointer to moal_private structure + * @param event_id event id. + * + * @return MLAN_STATUS_SUCCESS -- success, otherwise fail + */ +mlan_status +woal_set_rssi_threshold(moal_private * priv, t_u32 event_id) +{ + mlan_status ret = MLAN_STATUS_SUCCESS; + mlan_ioctl_req *req = NULL; + mlan_ds_misc_cfg *misc = NULL; + + ENTER(); + if (priv->media_connected == MFALSE) + goto done; + if (priv->mrvl_rssi_low) + goto done; + if (event_id == MLAN_EVENT_ID_FW_BCN_RSSI_LOW) { + if (priv->last_rssi_low < 100) + priv->last_rssi_low += priv->cqm_rssi_hyst; + priv->last_rssi_high = abs(priv->cqm_rssi_thold); + } else if (event_id == MLAN_EVENT_ID_FW_BCN_RSSI_HIGH) { + priv->last_rssi_low = abs(priv->cqm_rssi_thold); + if (priv->last_rssi_high > priv->cqm_rssi_hyst) + priv->last_rssi_high -= priv->cqm_rssi_hyst; + } else { + priv->last_rssi_low = abs(priv->cqm_rssi_thold); + priv->last_rssi_high = abs(priv->cqm_rssi_thold); + } + + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + misc = (mlan_ds_misc_cfg *) req->pbuf; + req->req_id = MLAN_IOCTL_MISC_CFG; + misc->sub_command = MLAN_OID_MISC_SUBSCRIBE_EVENT; + req->action = MLAN_ACT_SET; + misc->param.subscribe_event.evt_bitmap = + SUBSCRIBE_EVT_RSSI_LOW | SUBSCRIBE_EVT_RSSI_HIGH; + misc->param.subscribe_event.low_rssi_freq = 0; + misc->param.subscribe_event.low_rssi = priv->last_rssi_low; + misc->param.subscribe_event.high_rssi_freq = 0; + misc->param.subscribe_event.high_rssi = priv->last_rssi_high; + PRINTM(MIOCTL, "rssi_low=%d, rssi_high=%d\n", (int) priv->last_rssi_low, + (int) priv->last_rssi_high); + if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { + ret = -EFAULT; + goto done; + } + done: + if (req) + kfree(req); + LEAVE(); + return ret; +} +#endif + /** * @brief Get power mode * diff --git a/drivers/net/wireless/sd8797/mlinux/moal_main.c b/drivers/net/wireless/sd8797/mlinux/moal_main.c index eac248b70129..d5bed42fa73d 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_main.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_main.c @@ -47,6 +47,11 @@ Change log: #include #include "moal_eth_ioctl.h" +#include +#include +#include +#include + /******************************************************** Local Variables ********************************************************/ @@ -205,7 +210,7 @@ int woal_close(struct net_device *dev); int woal_set_mac_address(struct net_device *dev, void *addr); void woal_tx_timeout(struct net_device *dev); struct net_device_stats *woal_get_stats(struct net_device *dev); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) u16 woal_select_queue(struct net_device *dev, struct sk_buff *skb); #endif @@ -404,7 +409,7 @@ woal_init_sw(moal_handle * handle) /* PnP and power profile */ handle->surprise_removed = MFALSE; init_waitqueue_head(&handle->init_wait_q); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) spin_lock_init(&handle->queue_lock); #endif @@ -1215,9 +1220,7 @@ const struct net_device_ops woal_netdev_ops = { #else .ndo_set_multicast_list = woal_set_multicast_list, #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) .ndo_select_queue = woal_select_queue, -#endif }; #endif @@ -1292,9 +1295,7 @@ const struct net_device_ops woal_uap_netdev_ops = { #else .ndo_set_multicast_list = woal_uap_set_multicast_list, #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) .ndo_select_queue = woal_select_queue, -#endif }; #endif @@ -1373,7 +1374,7 @@ woal_add_interface(moal_handle * handle, t_u8 bss_index, t_u8 bss_type) moal_private *priv = NULL; ENTER(); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) #define MAX_WMM_QUEUE 4 /* Allocate an Ethernet device */ if (!(dev = alloc_etherdev_mq(sizeof(moal_private), MAX_WMM_QUEUE))) { @@ -1420,11 +1421,8 @@ woal_add_interface(moal_handle * handle, t_u8 bss_index, t_u8 bss_type) else if (bss_type == MLAN_BSS_TYPE_WIFIDIRECT) priv->bss_role = MLAN_BSS_ROLE_STA; #endif -#if defined(STA_CFG80211) || defined(UAP_CFG80211) - priv->probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; -#endif -#ifdef STA_SUPPORT -#endif + + INIT_LIST_HEAD(&priv->tcp_sess_queue); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24) SET_MODULE_OWNER(dev); @@ -1448,7 +1446,7 @@ woal_add_interface(moal_handle * handle, t_u8 bss_index, t_u8 bss_type) if ((priv->bss_role == MLAN_BSS_ROLE_STA) && IS_STA_CFG80211(cfg80211_wext)) { if (bss_type == MLAN_BSS_TYPE_STA #if defined(WIFI_DIRECT_SUPPORT) -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) || defined(COMPAT_WIRELESS) +#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION || bss_type == MLAN_BSS_TYPE_WIFIDIRECT #endif #endif @@ -1883,7 +1881,14 @@ woal_close(struct net_device *dev) moal_private *priv = (moal_private *) netdev_priv(dev); ENTER(); - +#ifdef STA_SUPPORT +#ifdef STA_CFG80211 + if (IS_STA_CFG80211(cfg80211_wext) && priv->scan_request) { + cfg80211_scan_done(priv->scan_request, MTRUE); + priv->scan_request = NULL; + } +#endif +#endif woal_stop_queue(priv->netdev); MODULE_PUT; @@ -2066,7 +2071,7 @@ woal_get_stats(struct net_device *dev) return &priv->stats; } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) /** * @brief This function handles wmm queue select * @@ -2108,6 +2113,233 @@ woal_select_queue(struct net_device * dev, struct sk_buff * skb) } #endif +/** + * @brief This function gets tcp session from the tcp session queue + * + * @param priv A pointer to moal_private structure + * @param src_ip IP address of the device + * @param src_port TCP port of the device + * @param dst_ip IP address of the client + * @param src_port TCP port of the client + * + * @return A pointer to the tcp session data structure, if found. + * Otherwise, null + */ +struct tcp_sess * +woal_get_tcp_sess(moal_private * priv, + t_u32 src_ip, t_u16 src_port, t_u32 dst_ip, t_u16 dst_port) +{ + struct tcp_sess *tcp_sess = NULL; + ENTER(); + + list_for_each_entry(tcp_sess, &priv->tcp_sess_queue, link) { + if ((tcp_sess->src_ip_addr == src_ip) && + (tcp_sess->src_tcp_port == src_port) && + (tcp_sess->dst_ip_addr == dst_ip) && + (tcp_sess->dst_tcp_port == dst_port)) { + LEAVE(); + return tcp_sess; + } + } + LEAVE(); + return NULL; +} + +/** + * @brief This function checks received tcp packet for FIN + * and release the tcp session if received + * + * @param priv A pointer to moal_private structure + * @param skb A pointer to sk_buff structure + * + * @return None + */ +void +woal_check_tcp_fin(moal_private * priv, struct sk_buff *skb) +{ + struct ethhdr *ethh = NULL; + struct iphdr *iph = NULL; + struct tcphdr *tcph = NULL; + struct tcp_sess *tcp_sess = NULL; + + ENTER(); + + ethh = eth_hdr(skb); + if (ntohs(ethh->h_proto) == ETH_P_IP) { + iph = (struct iphdr *) ((t_u8 *) ethh + sizeof(struct ethhdr)); + if (iph->protocol == IPPROTO_TCP) { + tcph = (struct tcphdr *) ((t_u8 *) iph + iph->ihl * 4); + if (tcph->fin) { + tcp_sess = woal_get_tcp_sess(priv, iph->daddr, + tcph->dest, iph->saddr, + tcph->source); + if (tcp_sess != NULL) { + PRINTM(MINFO, + "TX: release a tcp session in dl. (src: ipaddr 0x%08x, port: %d. dst: ipaddr 0x%08x, port: %d\n", + iph->daddr, tcph->dest, iph->saddr, tcph->source); + /* remove the tcp session from the queue */ + list_del(&tcp_sess->link); + kfree(tcp_sess); + } else { + PRINTM(MINFO, "Tx: released TCP session is not found.\n "); + } + } + } + } + LEAVE(); +} + +/** + * @brief This function process tcp ack packets + * + * @param priv A pointer to moal_private structure + * @param pmbuf A pointer to the mlan buffer associated with the skb + * + * @return 1, if a tcp ack packet has been dropped. Otherwise, 0. + */ +int +woal_process_tcp_ack(moal_private * priv, mlan_buffer * pmbuf) +{ + int ret = 0; + struct ethhdr *ethh = NULL; + struct iphdr *iph = NULL; + struct tcphdr *tcph = NULL; + struct tcp_sess *tcp_sess = NULL; + struct sk_buff *skb = NULL; + t_u32 ack_seq = 0; + t_u32 len = 0; + t_u8 opt = 0; + t_u8 opt_len = 0; + t_u8 *pos = NULL; + t_u32 win_size = 0; + +#define TCP_ACK_DELAY 3 +#define TCP_ACK_INIT_WARMING_UP 1000 /* initial */ +#define TCP_ACK_RECV_WARMING_UP 1000 /* recovery */ + + ENTER(); + + /** check the tcp packet */ + ethh = (struct ethhdr *) (pmbuf->pbuf + pmbuf->data_offset); + if (ntohs(ethh->h_proto) != ETH_P_IP) { + return 0; + } + iph = (struct iphdr *) ((t_u8 *) ethh + sizeof(struct ethhdr)); + if (iph->protocol != IPPROTO_TCP) { + return 0; + } + tcph = (struct tcphdr *) ((t_u8 *) iph + iph->ihl * 4); + + if (tcph->syn & tcph->ack) { + /* respond to a TCP request. create a tcp session */ + if (!(tcp_sess = kmalloc(sizeof(struct tcp_sess), GFP_ATOMIC))) { + PRINTM(MERROR, "Fail to allocate tcp_sess.\n"); + return 0; + } + memset(tcp_sess, 0, sizeof(struct tcp_sess)); + tcp_sess->src_ip_addr = iph->saddr; /* my ip addr */ + tcp_sess->dst_ip_addr = iph->daddr; + tcp_sess->src_tcp_port = tcph->source; + tcp_sess->dst_tcp_port = tcph->dest; + tcp_sess->start_cnt = TCP_ACK_INIT_WARMING_UP; + + INIT_LIST_HEAD(&tcp_sess->link); + list_add_tail(&tcp_sess->link, &priv->tcp_sess_queue); + PRINTM(MINFO, + "create a tcp session. (src: ipaddr 0x%08x, port: %d. dst: ipaddr 0x%08x, port: %d\n", + iph->saddr, tcph->source, iph->daddr, tcph->dest); + + /* parse tcp options for the window scale */ + len = (tcph->doff * 4) - sizeof(struct tcphdr); + pos = (t_u8 *) (tcph + 1); + while (len > 0) { + opt = *pos++; + switch (opt) { + case TCPOPT_EOL: + len = 0; + continue; + case TCPOPT_NOP: + len--; + continue; + case TCPOPT_WINDOW: + opt_len = *pos++; + if (opt_len == TCPOLEN_WINDOW) { + tcp_sess->rx_win_scale = *pos; + tcp_sess->rx_win_opt = 1; + if (tcp_sess->rx_win_scale > 14) + tcp_sess->rx_win_scale = 14; + PRINTM(MINFO, "TCP Window Scale: %d \n", + tcp_sess->rx_win_scale); + } + break; + default: + opt_len = *pos++; + } + len -= opt_len; + pos += opt_len - 2; + } + } else if (tcph->ack && !(tcph->syn) && + (ntohs(iph->tot_len) == (iph->ihl * 4 + tcph->doff * 4))) { + /** it is an ack packet, not a piggyback ack */ + tcp_sess = woal_get_tcp_sess(priv, iph->saddr, tcph->source, + iph->daddr, tcph->dest); + if (tcp_sess == NULL) { + return 0; + } + /** do not drop the ack packets initially */ + if (tcp_sess->start_cnt) { + tcp_sess->start_cnt--; + return 0; + } + + /* check the window size. */ + win_size = ntohs(tcph->window); + if (tcp_sess->rx_win_opt) { + win_size <<= tcp_sess->rx_win_scale; + /* Note: it may depend on the rtd */ + if ((win_size > 1500 * (TCP_ACK_DELAY + 5)) && + (tcp_sess->ack_cnt < TCP_ACK_DELAY)) { + /* if windiow is big enough, drop the ack packet */ + if (tcp_sess->ack_seq != ntohl(tcph->ack_seq)) { + ack_seq = tcp_sess->ack_seq; + tcp_sess->ack_seq = ntohl(tcph->ack_seq); + tcp_sess->ack_cnt++; + skb = (struct sk_buff *) pmbuf->pdesc; + if (skb) + dev_kfree_skb_any(skb); + ret = 1; + } else { + /* the ack packet is retransmitted. thus, stop dropping + the ack packets */ + tcp_sess->start_cnt = TCP_ACK_RECV_WARMING_UP; + PRINTM(MINFO, "Recover the TCP session.\n "); + } + } else { + /* send the current ack pacekt */ + ack_seq = tcp_sess->ack_seq; + tcp_sess->ack_seq = ntohl(tcph->ack_seq); + tcp_sess->ack_cnt = 0; + ret = 0; + } + } + } else if (tcph->fin) { + tcp_sess = woal_get_tcp_sess(priv, iph->saddr, tcph->source, + iph->daddr, tcph->dest); + if (tcp_sess != NULL) { + /* remove the tcp session from the queue */ + PRINTM(MINFO, + "Rx: release a tcp session in ul. (src: ipaddr 0x%08x, port: %d. dst: ipaddr 0x%08x, port: %d\n", + iph->saddr, tcph->source, iph->daddr, tcph->dest); + list_del(&tcp_sess->link); + kfree(tcp_sess); + } else { + PRINTM(MINFO, "released TCP session is not found.\n "); + } + } + LEAVE(); + return ret; +} + /** * @brief This function handles packet transmission * @@ -2165,6 +2397,13 @@ woal_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) memset((t_u8 *) pmbuf, 0, sizeof(mlan_buffer)); pmbuf->bss_index = priv->bss_index; woal_fill_mlan_buffer(priv, pmbuf, skb); + if (priv->enable_tcp_ack_enh == MTRUE) { + if (woal_process_tcp_ack(priv, pmbuf)) { + /* the ack packet has been dropped */ + goto done; + } + } + status = mlan_send_packet(priv->phandle->pmlan_adapter, pmbuf); switch (status) { case MLAN_STATUS_PENDING: @@ -2394,6 +2633,8 @@ woal_set_multicast_list(struct net_device *dev) void woal_init_priv(moal_private * priv, t_u8 wait_option) { + struct list_head *link = NULL; + struct tcp_sess *tcp_sess = NULL; ENTER(); #ifdef STA_SUPPORT if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) { @@ -2414,7 +2655,7 @@ woal_init_priv(moal_private * priv, t_u8 wait_option) if (IS_STA_CFG80211(cfg80211_wext)) { if (priv->bss_type == MLAN_BSS_TYPE_STA #if defined(WIFI_DIRECT_SUPPORT) -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) || defined(COMPAT_WIRELESS) +#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION || priv->bss_type == MLAN_BSS_TYPE_WIFIDIRECT #endif #endif @@ -2434,6 +2675,25 @@ woal_init_priv(moal_private * priv, t_u8 wait_option) } #endif priv->media_connected = MFALSE; + +#if defined(STA_CFG80211) || defined(UAP_CFG80211) + priv->probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; +#endif +#ifdef STA_SUPPORT +#endif + + priv->enable_tcp_ack_enh = MTRUE; + while (!list_empty(&priv->tcp_sess_queue)) { + link = priv->tcp_sess_queue.next; + tcp_sess = list_entry(link, struct tcp_sess, link); + PRINTM(MINFO, + "warm reset: release a tcp session in dl. (src: ipaddr 0x%08x, port: %d. dst: ipaddr 0x%08x, port: %d\n", + tcp_sess->src_ip_addr, tcp_sess->src_tcp_port, + tcp_sess->dst_ip_addr, tcp_sess->dst_tcp_port); + list_del(link); + kfree(tcp_sess); + } + woal_request_get_fw_info(priv, wait_option, NULL); LEAVE(); @@ -2805,8 +3065,9 @@ woal_reassociation_thread(void *data) for (i = 0; i < handle->priv_num && (priv = handle->priv[i]); i++) { - if (priv->reassoc_required == MFALSE) + if (priv->reassoc_required == MFALSE) { continue; + } memset(&bss_info, 0x00, sizeof(bss_info)); @@ -2892,7 +3153,6 @@ woal_reassociation_thread(void *data) mlan_ioctl_req *req = NULL; reassoc_timer_req = MFALSE; - if (priv->rate_index != AUTO_RATE) { req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate)); @@ -2928,11 +3188,13 @@ woal_reassociation_thread(void *data) break; if (reassoc_timer_req == MTRUE) { - PRINTM(MEVENT, - "Reassoc: No AP found or assoc failed. " - "Restarting re-assoc Timer: %d\n", (int) timer_val); handle->is_reassoc_timer_set = MTRUE; - woal_mod_timer(&handle->reassoc_timer, timer_val); + { + PRINTM(MEVENT, + "Reassoc: No AP found or assoc failed. " + "Restarting re-assoc Timer: %d\n", (int) timer_val); + woal_mod_timer(&handle->reassoc_timer, timer_val); + } } } woal_deactivate_thread(pmoal_thread); @@ -3083,7 +3345,7 @@ woal_moal_debug_info(moal_private * priv, moal_handle * handle, u8 flag) { moal_handle *phandle = NULL; char buf[MLAN_MAX_VER_STR_LEN]; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) int i = 0; #endif @@ -3122,7 +3384,7 @@ woal_moal_debug_info(moal_private * priv, moal_handle * handle, u8 flag) MFALSE) ? "Disconnected" : "Connected")); PRINTM(MERROR, "carrier %s\n", ((netif_carrier_ok(priv->netdev)) ? "on" : "off")); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) for (i = 0; i < (priv->netdev->num_tx_queues); i++) { PRINTM(MERROR, "tx queue %d: %s\n", i, ((netif_tx_queue_stopped @@ -3599,11 +3861,11 @@ woal_init_module(void) /* Init mutex */ MOAL_INIT_SEMAPHORE(&AddRemoveCardSem); + wifi_add_dev(); + /* Register with bus */ ret = woal_bus_register(); - wifi_add_dev(); - LEAVE(); return ret; } @@ -3645,7 +3907,8 @@ woal_cleanup_module(void) if (handle->priv[i]->media_connected == MTRUE) woal_disconnect(handle->priv[i], MOAL_CMD_WAIT, NULL); #ifdef STA_CFG80211 - if (handle->priv[i]->scan_request) { + if (IS_STA_CFG80211(cfg80211_wext) && + handle->priv[i]->scan_request) { cfg80211_scan_done(handle->priv[i]->scan_request, MTRUE); handle->priv[i]->scan_request = NULL; } @@ -3681,13 +3944,13 @@ woal_cleanup_module(void) MOAL_CMD_WAIT); } - wifi_del_dev(); - exit: MOAL_REL_SEMAPHORE(&AddRemoveCardSem); exit_sem_err: /* Unregister from bus */ woal_bus_unregister(); + wifi_del_dev(); + LEAVE(); } @@ -3749,7 +4012,7 @@ module_param(init_cfg, charp, 0); MODULE_PARM_DESC(init_cfg, "Init config file name"); module_param(cal_data_cfg, charp, 0); MODULE_PARM_DESC(cal_data_cfg, "Calibration data file name"); -module_param(minicard_pwrup, int, 0); +module_param(minicard_pwrup, int, 1); MODULE_PARM_DESC(minicard_pwrup, "1: Driver load clears PDn/Rst, unload sets (default); 0: Don't do this."); module_param(cfg80211_wext, int, 0); diff --git a/drivers/net/wireless/sd8797/mlinux/moal_main.h b/drivers/net/wireless/sd8797/mlinux/moal_main.h index cd1fdd8244c1..32426a149779 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_main.h +++ b/drivers/net/wireless/sd8797/mlinux/moal_main.h @@ -2,7 +2,7 @@ * * @brief This file contains wlan driver specific defines etc. * - * Copyright (C) 2008-2011, Marvell International Ltd. + * Copyright (C) 2008-2012, Marvell International Ltd. * * This software file (the "File") is distributed by Marvell International * Ltd. under the terms of the GNU General Public License Version 2, June 1991 @@ -49,8 +49,9 @@ Change log: #include #include #include -#include -#include +#include +#include +#include #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) #include @@ -654,6 +655,24 @@ struct debug_data_priv /** IP address operation: Remove */ #define IPADDR_OP_REMOVE 0 +struct tcp_sess +{ + struct list_head link; + /** tcp session info */ + t_u32 src_ip_addr; + t_u32 dst_ip_addr; + t_u16 src_tcp_port; + t_u16 dst_tcp_port; + /** tcp window info */ + t_u8 rx_win_opt; + t_u32 rx_win_scale; + /** warming up counter */ + t_u32 start_cnt; + /** tx ack packet info */ + t_u32 ack_seq; + t_u32 ack_cnt; +}; + /** Private structure for MOAL */ struct _moal_private { @@ -715,6 +734,18 @@ struct _moal_private t_u8 cfg_bssid[ETH_ALEN]; /** Disconnect request from CFG80211 */ bool cfg_disconnect; + /** rssi_threshold */ + s32 cqm_rssi_thold; + /** rssi hysteresis */ + u32 cqm_rssi_hyst; + /** last rssi_low */ + u8 last_rssi_low; + /** last rssi_high */ + u8 last_rssi_high; + /** mrvl rssi threshold */ + u8 mrvl_rssi_low; + /** rssi status */ + u32 rssi_status; #endif /* STA_SUPPORT */ #endif /* STA_CFG80211 */ /** IOCTL wait queue */ @@ -779,6 +810,11 @@ struct _moal_private /** MLAN debug info */ struct debug_data_priv items_priv; #endif + + /** tcp session queue */ + struct list_head tcp_sess_queue; + /** TCP Ack enhance flag */ + t_u8 enable_tcp_ack_enh; }; /** Handle data structure for MOAL */ @@ -818,6 +854,7 @@ struct _moal_handle t_u16 init_wait_q_woken; /** Init wait queue */ wait_queue_head_t init_wait_q __ATTRIB_ALIGN__; +#if defined(SDIO_SUSPEND_RESUME) /** Device suspend flag */ BOOLEAN is_suspended; #ifdef SDIO_SUSPEND_RESUME @@ -830,6 +867,7 @@ struct _moal_handle t_u16 hs_activate_wait_q_woken; /** Host Sleep activated event wait queue */ wait_queue_head_t hs_activate_wait_q __ATTRIB_ALIGN__; +#endif /** Card pointer */ t_void *card; /** Rx pending in MLAN */ @@ -844,12 +882,14 @@ struct _moal_handle t_u32 lock_count; /** mlan buffer alloc count */ t_u32 mbufalloc_count; +#if defined(SDIO_SUSPEND_RESUME) /** hs skip count */ t_u32 hs_skip_count; /** hs force count */ t_u32 hs_force_count; /** suspend_fail flag */ BOOLEAN suspend_fail; +#endif #ifdef REASSOCIATION /** Re-association thread */ moal_thread reassoc_thread; @@ -923,7 +963,7 @@ struct _moal_handle t_u8 cmd52_reg; /** cmd52 value */ t_u8 cmd52_val; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) /** spinlock to stop_queue/wake_queue*/ spinlock_t queue_lock; #endif @@ -939,7 +979,7 @@ struct _moal_handle static inline void woal_set_trans_start(struct net_device *dev) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31) unsigned int i; for (i = 0; i < dev->num_tx_queues; i++) { netdev_get_tx_queue(dev, i)->trans_start = jiffies; @@ -958,7 +998,7 @@ woal_set_trans_start(struct net_device *dev) static inline void woal_start_queue(struct net_device *dev) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) netif_start_queue(dev); #else netif_tx_start_all_queues(dev); @@ -975,7 +1015,7 @@ woal_start_queue(struct net_device *dev) static inline void woal_stop_queue(struct net_device *dev) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) unsigned long flags; moal_private *priv = (moal_private *) netdev_priv(dev); spin_lock_irqsave(&priv->phandle->queue_lock, flags); @@ -1000,7 +1040,7 @@ woal_stop_queue(struct net_device *dev) static inline void woal_wake_queue(struct net_device *dev) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) unsigned long flags; moal_private *priv = (moal_private *) netdev_priv(dev); spin_lock_irqsave(&priv->phandle->queue_lock, flags); @@ -1217,6 +1257,8 @@ typedef struct _HostCmd_DS_802_11_CFG_DATA #define WEXT_BGSCAN_RSSI_SECTION 'R' /** BGSCAN SCAN INTERVAL SECTION */ #define WEXT_BGSCAN_INTERVAL_SECTION 'T' +/** BGSCAN REPEAT SECTION */ +#define WEXT_BGSCAN_REPEAT_SECTION 'E' /** band AUTO */ #define WIFI_FREQUENCY_BAND_AUTO 0 @@ -1316,11 +1358,15 @@ mlan_status woal_set_get_hs_params(moal_private * priv, t_u16 action, t_u8 wait_option, mlan_ds_hs_cfg * hscfg); /** Cancel Host Sleep configuration */ mlan_status woal_cancel_hs(moal_private * priv, t_u8 wait_option); +#if defined(SDIO_SUSPEND_RESUME) /** Enable Host Sleep configuration */ int woal_enable_hs(moal_private * priv); /** hs active timeout 2 second */ #define HS_ACTIVE_TIMEOUT (2 * HZ) +#endif +/** get deep sleep */ +int woal_get_deep_sleep(moal_private * priv, t_u32 * data); /** set deep sleep */ int woal_set_deep_sleep(moal_private * priv, t_u8 wait_option, BOOLEAN bdeep_sleep, t_u16 idletime); @@ -1431,6 +1477,8 @@ int woal_host_command(moal_private * priv, struct iwreq *wrq); #if defined(WIFI_DIRECT_SUPPORT) #if defined(STA_SUPPORT) && defined(UAP_SUPPORT) #if defined(STA_WEXT) || defined(UAP_WEXT) +mlan_status woal_bss_role_cfg(moal_private * priv, t_u8 action, + t_u8 wait_option, t_u8 * bss_role); int woal_set_get_bss_role(moal_private * priv, struct iwreq *wrq); #endif #endif @@ -1443,8 +1491,8 @@ int woal_hostcmd_ioctl(struct net_device *dev, struct ifreq *req); #if defined(WIFI_DIRECT_SUPPORT) mlan_status woal_set_remain_channel_ioctl(moal_private * priv, t_u8 wait_option, mlan_ds_remain_chan * pchan); -mlan_status woal_cfg80211_wifi_direct_mode_cfg(moal_private * priv, - t_u16 action, t_u16 * mode); +mlan_status woal_wifi_direct_mode_cfg(moal_private * priv, t_u16 action, + t_u16 * mode); #endif /* WIFI_DIRECT_SUPPORT */ #ifdef CONFIG_PROC_FS @@ -1502,9 +1550,15 @@ mlan_status woal_remove_rxfilter(moal_private * priv, char *rxfilter); mlan_status woal_set_qos_cfg(moal_private * priv, char *qos_cfg); int woal_set_sleeppd(moal_private * priv, char *psleeppd); mlan_status woal_set_rssi_low_threshold(moal_private * priv, char *rssi); +mlan_status woal_set_rssi_threshold(moal_private * priv, t_u32 event_id); mlan_status woal_set_bg_scan(moal_private * priv, char *buf, int length); mlan_status woal_stop_bg_scan(moal_private * priv); void woal_reconfig_bgscan(moal_handle * handle); #endif +struct tcp_sess *woal_get_tcp_sess(moal_private * priv, + t_u32 src_ip, t_u16 src_port, + t_u32 dst_ip, t_u16 dst_port); +void woal_check_tcp_fin(moal_private * priv, struct sk_buff *skb); + #endif /* _MOAL_MAIN_H */ diff --git a/drivers/net/wireless/sd8797/mlinux/moal_priv.c b/drivers/net/wireless/sd8797/mlinux/moal_priv.c index e3e4b844e11b..9a5173ddfb3f 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_priv.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_priv.c @@ -101,6 +101,13 @@ woal_warm_reset(moal_private * priv) moal_handle *handle = priv->phandle; mlan_ioctl_req *req = NULL; mlan_ds_misc_cfg *misc = NULL; +#if defined(WIFI_DIRECT_SUPPORT) +#if defined(STA_SUPPORT) && defined(UAP_SUPPORT) +#if defined(STA_WEXT) || defined(UAP_WEXT) + t_u8 bss_role = MLAN_BSS_ROLE_STA; +#endif +#endif +#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */ ENTER(); @@ -110,8 +117,24 @@ woal_warm_reset(moal_private * priv) ret = woal_reset_intf(priv, MOAL_IOCTL_WAIT, MTRUE); /* Initialize private structures */ - for (intf_num = 0; intf_num < handle->priv_num; intf_num++) + for (intf_num = 0; intf_num < handle->priv_num; intf_num++) { woal_init_priv(handle->priv[intf_num], MOAL_IOCTL_WAIT); +#if defined(WIFI_DIRECT_SUPPORT) +#if defined(STA_SUPPORT) && defined(UAP_SUPPORT) +#if defined(STA_WEXT) || defined(UAP_WEXT) + if (handle->priv[intf_num]->bss_type == MLAN_BSS_TYPE_WIFIDIRECT) { + if (MLAN_STATUS_SUCCESS != woal_bss_role_cfg(handle->priv[intf_num], + MLAN_ACT_SET, + MOAL_IOCTL_WAIT, + &bss_role)) { + ret = -EFAULT; + goto done; + } + } +#endif /* STA_WEXT || UAP_WEXT */ +#endif /* STA_SUPPORT && UAP_SUPPORT */ +#endif /* WIFI_DIRECT_SUPPORT && V14_FEATURE */ + } /* Restart the firmware */ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); @@ -333,48 +356,6 @@ woal_get_signal(moal_private * priv, struct iwreq *wrq) return ret; } -/** - * @brief Get Deep Sleep - * - * @param priv Pointer to the moal_private driver data struct - * @param deep_sleep Pointer to return deep_sleep setting - * - * @return 0 --success, otherwise fail - */ -static int -woal_get_deep_sleep(moal_private * priv, t_u32 * data) -{ - int ret = 0; - mlan_ioctl_req *req = NULL; - mlan_ds_pm_cfg *pm = NULL; - - ENTER(); - - req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg)); - if (req == NULL) { - LEAVE(); - return -ENOMEM; - } - pm = (mlan_ds_pm_cfg *) req->pbuf; - pm->sub_command = MLAN_OID_PM_CFG_DEEP_SLEEP; - req->req_id = MLAN_IOCTL_PM_CFG; - - req->action = MLAN_ACT_GET; - if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { - ret = -EFAULT; - goto done; - } - *data = pm->param.auto_deep_sleep.auto_ds; - *(data + 1) = pm->param.auto_deep_sleep.idletime; - - done: - if (req) - kfree(req); - - LEAVE(); - return ret; -} - /** * @brief Get/Set DeepSleep mode * @@ -3692,7 +3673,6 @@ static int woal_set_get_ip_addr(moal_private * priv, struct iwreq *wrq) { char buf[IPADDR_MAX_BUF]; - struct iwreq *wreq = (struct iwreq *) wrq; mlan_ioctl_req *ioctl_req = NULL; mlan_ds_misc_cfg *misc = NULL; int ret = 0, op_code = 0, data_length = wrq->u.data.length; @@ -3710,8 +3690,8 @@ woal_set_get_ip_addr(moal_private * priv, struct iwreq *wrq) if (data_length <= 1) { /* GET */ ioctl_req->action = MLAN_ACT_GET; } else { - if (copy_from_user(buf, wreq->u.data.pointer, - MIN(IPADDR_MAX_BUF - 1, wreq->u.data.length))) { + if (copy_from_user(buf, wrq->u.data.pointer, + MIN(IPADDR_MAX_BUF - 1, wrq->u.data.length))) { PRINTM(MERROR, "Copy from user failed\n"); ret = -EFAULT; goto done; @@ -3727,7 +3707,7 @@ woal_set_get_ip_addr(moal_private * priv, struct iwreq *wrq) ioctl_req->action = MLAN_ACT_SET; /* only one IP is supported in current firmware */ memset(misc->param.ipaddr_cfg.ip_addr[0], 0, IPADDR_LEN); - in4_pton(&buf[2], MIN((IPADDR_MAX_BUF - 3), (wreq->u.data.length - 2)), + in4_pton(&buf[2], MIN((IPADDR_MAX_BUF - 3), (wrq->u.data.length - 2)), misc->param.ipaddr_cfg.ip_addr[0], ' ', NULL); /* only one IP is supported in current firmware */ misc->param.ipaddr_cfg.ip_addr_num = 1; @@ -4524,6 +4504,34 @@ woal_get_scan_table_ioctl(moal_private * priv, struct iwreq *wrq) return status; } +/** + * @brief Set user scan ext -- Async mode, without wait + * + * @param priv A pointer to moal_private structure + * @param wrq A pointer to iwreq structure + * + * @return 0 -- success, otherwise fail + */ +static int +woal_set_user_scan_ext_ioctl(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + wlan_user_scan_cfg scan_req; + ENTER(); + memset(&scan_req, 0x00, sizeof(scan_req)); + if (copy_from_user + (&scan_req, wrq->u.data.pointer, + MIN(wrq->u.data.length, sizeof(scan_req)))) { + PRINTM(MINFO, "Copy from user failed\n"); + LEAVE(); + return -EFAULT; + } + if (MLAN_STATUS_FAILURE == woal_do_scan(priv, &scan_req)) + ret = -EFAULT; + LEAVE(); + return ret; +} + /** * @brief Set user scan * @@ -5911,6 +5919,86 @@ woal_mgmt_frame_passthru_ctrl(moal_private * priv, struct iwreq *wrq) return ret; } +/** + * @brief Set/Get CFP table codes + * + * @param priv Pointer to the moal_private driver data struct + * @param wrq A pointer to iwreq structure + * + * @return 0 --success, otherwise fail + */ +static int +woal_cfp_code(moal_private * priv, struct iwreq *wrq) +{ + int ret = 0; + int data[2]; + int data_length = wrq->u.data.length; + mlan_ioctl_req *req = NULL; + mlan_ds_misc_cfg *misc_cfg = NULL; + mlan_ds_misc_cfp_code *cfp_code = NULL; + + ENTER(); + + if (data_length > 2) { + PRINTM(MERROR, "Invalid number of argument!\n"); + ret = -EINVAL; + goto done; + } + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); + if (req == NULL) { + ret = -ENOMEM; + goto done; + } + + /* Fill request buffer */ + misc_cfg = (mlan_ds_misc_cfg *) req->pbuf; + cfp_code = &misc_cfg->param.cfp_code; + misc_cfg->sub_command = MLAN_OID_MISC_CFP_CODE; + req->req_id = MLAN_IOCTL_MISC_CFG; + + if (!data_length) { + req->action = MLAN_ACT_GET; + } else { + if (copy_from_user + (data, wrq->u.data.pointer, sizeof(int) * data_length)) { + PRINTM(MERROR, "Copy from user failed\n"); + ret = -EFAULT; + goto done; + } + cfp_code->cfp_code_bg = data[0]; + if (data_length == 2) + cfp_code->cfp_code_a = data[1]; + req->action = MLAN_ACT_SET; + } + + /* Send IOCTL request to MLAN */ + if (woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT) != MLAN_STATUS_SUCCESS) { + ret = -EFAULT; + goto done; + } + + if (!data_length) { + data[0] = cfp_code->cfp_code_bg; + data[1] = cfp_code->cfp_code_a; + data_length = 2; + if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int) * data_length)) { + PRINTM(MERROR, "Copy to user failed\n"); + ret = -EFAULT; + goto done; + } + wrq->u.data.length = data_length; + } + + done: + if (req) + kfree(req); + + LEAVE(); + return ret; +} + /** * @brief Set/Get Tx/Rx antenna * @@ -6183,6 +6271,9 @@ woal_wext_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd) case WOAL_MGMT_FRAME_CTRL: ret = woal_mgmt_frame_passthru_ctrl(priv, wrq); break; + case WOAL_CFP_CODE: + ret = woal_cfp_code(priv, wrq); + break; case WOAL_SET_GET_TX_RX_ANT: ret = woal_set_get_tx_rx_ant(priv, wrq); break; @@ -6296,6 +6387,9 @@ woal_wext_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd) case WOAL_GET_SCAN_TABLE: ret = woal_get_scan_table_ioctl(priv, wrq); break; + case WOAL_SET_USER_SCAN_EXT: + ret = woal_set_user_scan_ext_ioctl(priv, wrq); + break; case WOAL_WMM_ADDTS: ret = woal_wmm_addts_req_ioctl(priv, wrq); break; diff --git a/drivers/net/wireless/sd8797/mlinux/moal_priv.h b/drivers/net/wireless/sd8797/mlinux/moal_priv.h index de491f6d6a29..1c24f30502f6 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_priv.h +++ b/drivers/net/wireless/sd8797/mlinux/moal_priv.h @@ -115,6 +115,8 @@ Change log: /** Private command ID to set/get dfs testing settings */ #define WOAL_DFS_TESTING 33 #endif +/** Private command ID to set/get CFP table codes */ +#define WOAL_CFP_CODE 34 /** Private command ID to set/get tx/rx antenna */ #define WOAL_SET_GET_TX_RX_ANT 35 /** Private command ID to set/get management frame passthru mask */ @@ -226,6 +228,8 @@ Change log: #define WOAL_SET_USER_SCAN 3 /** Private command ID for getscantable */ #define WOAL_GET_SCAN_TABLE 4 +/** Private command ID for setuserscanext: async without wait */ +#define WOAL_SET_USER_SCAN_EXT 5 /** Private command ID to request ADDTS */ #define WOAL_WMM_ADDTS 7 @@ -525,6 +529,11 @@ static const struct iw_priv_args woal_private_args[] = { IW_PRIV_TYPE_INT | 16, IW_PRIV_TYPE_INT | 16, "mgmtframectrl"}, + { + WOAL_CFP_CODE, + IW_PRIV_TYPE_INT | 16, + IW_PRIV_TYPE_INT | 16, + "cfpcode"}, { WOAL_SET_GET_TX_RX_ANT, IW_PRIV_TYPE_INT | 16, @@ -655,6 +664,11 @@ static const struct iw_priv_args woal_private_args[] = { IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, "getscantable"}, + { + WOAL_SET_USER_SCAN_EXT, + IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, + IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, + "setuserscanext"}, { WOAL_WMM_ADDTS, IW_PRIV_TYPE_BYTE | WOAL_2K_BYTES, diff --git a/drivers/net/wireless/sd8797/mlinux/moal_proc.c b/drivers/net/wireless/sd8797/mlinux/moal_proc.c index e98803c2e3fb..fb7c63a29cab 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_proc.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_proc.c @@ -95,9 +95,9 @@ woal_info_proc_read(char *page, char **start, off_t offset, int mc_count = netdev_mc_count(netdev); #endif /* < 2.6.35 */ #else -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) int i = 0; -#endif /* >= 2.6.34 */ +#endif /* >= 2.6.29 */ #endif #ifdef UAP_SUPPORT mlan_ds_uap_stats ustats; @@ -199,7 +199,7 @@ woal_info_proc_read(char *page, char **start, off_t offset, p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors); p += sprintf(p, "carrier %s\n", ((netif_carrier_ok(priv->netdev)) ? "on" : "off")); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) for (i = 0; i < netdev->num_tx_queues; i++) { p += sprintf(p, "tx queue %d: %s\n", i, ((netif_tx_queue_stopped(netdev_get_tx_queue(netdev, 0))) ? diff --git a/drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c b/drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c index 96e3e971936f..f09f33e6435d 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_sdio_mmc.c @@ -315,6 +315,12 @@ woal_sdio_suspend(struct device *dev) } handle = cardp->handle; + if (handle->is_suspended == MTRUE) { + PRINTM(MWARN, "Device already suspended\n"); + LEAVE(); + return MLAN_STATUS_SUCCESS; + } + handle->suspend_fail = MFALSE; memset(&pm_info, 0, sizeof(pm_info)); if (MLAN_STATUS_SUCCESS == diff --git a/drivers/net/wireless/sd8797/mlinux/moal_shim.c b/drivers/net/wireless/sd8797/mlinux/moal_shim.c index e33a6e38067a..25cfdc549f3d 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_shim.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_shim.c @@ -745,6 +745,11 @@ moal_recv_packet(IN t_void * pmoal_handle, IN pmlan_buffer pmbuf) skb->dev = priv->netdev; skb->protocol = eth_type_trans(skb, priv->netdev); skb->ip_summed = CHECKSUM_NONE; + + if (priv->enable_tcp_ack_enh == MTRUE) { + woal_check_tcp_fin(priv, skb); + } + priv->stats.rx_bytes += skb->len; priv->stats.rx_packets++; if (in_interrupt()) @@ -950,6 +955,13 @@ moal_recv_event(IN t_void * pmoal_handle, IN pmlan_event pmevent) #endif } #endif /* STA_WEXT */ +#ifdef STA_CFG80211 + if (IS_STA_CFG80211(cfg80211_wext)) { + cfg80211_michael_mic_failure(priv->netdev, priv->cfg_bssid, + NL80211_KEYTYPE_PAIRWISE, -1, NULL, + GFP_KERNEL); + } +#endif break; case MLAN_EVENT_ID_FW_MIC_ERR_MUL: #ifdef STA_WEXT @@ -961,17 +973,47 @@ moal_recv_event(IN t_void * pmoal_handle, IN pmlan_event pmevent) #endif } #endif /* STA_WEXT */ +#ifdef STA_CFG80211 + if (IS_STA_CFG80211(cfg80211_wext)) { + cfg80211_michael_mic_failure(priv->netdev, priv->cfg_bssid, + NL80211_KEYTYPE_GROUP, -1, NULL, + GFP_KERNEL); + } +#endif break; case MLAN_EVENT_ID_FW_BCN_RSSI_LOW: #ifdef STA_WEXT if (IS_STA_WEXT(cfg80211_wext)) woal_send_iwevcustom_event(priv, CUS_EVT_BEACON_RSSI_LOW); +#endif +#ifdef STA_CFG80211 + if (IS_STA_CFG80211(cfg80211_wext)) { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) || defined(COMPAT_WIRELESS) + cfg80211_cqm_rssi_notify(priv->netdev, + NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW, + GFP_KERNEL); + priv->rssi_status = MLAN_EVENT_ID_FW_BCN_RSSI_LOW; +#endif + woal_set_rssi_threshold(priv, MLAN_EVENT_ID_FW_BCN_RSSI_LOW); + } #endif break; case MLAN_EVENT_ID_FW_BCN_RSSI_HIGH: #ifdef STA_WEXT if (IS_STA_WEXT(cfg80211_wext)) woal_send_iwevcustom_event(priv, CUS_EVT_BEACON_RSSI_HIGH); +#endif +#ifdef STA_CFG80211 + if (IS_STA_CFG80211(cfg80211_wext)) { + if (!priv->mrvl_rssi_low) { +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) || defined(COMPAT_WIRELESS) + cfg80211_cqm_rssi_notify(priv->netdev, + NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, + GFP_KERNEL); +#endif + woal_set_rssi_threshold(priv, MLAN_EVENT_ID_FW_BCN_RSSI_HIGH); + } + } #endif break; case MLAN_EVENT_ID_FW_BCN_SNR_LOW: @@ -1032,6 +1074,22 @@ moal_recv_event(IN t_void * pmoal_handle, IN pmlan_event pmevent) #ifdef STA_WEXT if (IS_STA_WEXT(cfg80211_wext)) woal_send_iwevcustom_event(priv, CUS_EVT_PRE_BEACON_LOST); +#endif +#ifdef STA_CFG80211 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) || defined(COMPAT_WIRELESS) + if (IS_STA_CFG80211(cfg80211_wext)) { + struct cfg80211_bss *bss = NULL; + bss = + cfg80211_get_bss(priv->wdev->wiphy, NULL, priv->cfg_bssid, NULL, + 0, WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); + if (bss) + cfg80211_unlink_bss(priv->wdev->wiphy, bss); + cfg80211_cqm_rssi_notify(priv->netdev, + NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW, + GFP_KERNEL); + priv->rssi_status = MLAN_EVENT_ID_FW_PRE_BCN_LOST; + } +#endif #endif break; case MLAN_EVENT_ID_FW_WMM_CONFIG_CHANGE: @@ -1069,10 +1127,21 @@ moal_recv_event(IN t_void * pmoal_handle, IN pmlan_event pmevent) priv->bg_scan_reported = MTRUE; #ifdef STA_WEXT if (IS_STA_WEXT(cfg80211_wext)) { - woal_send_iwevcustom_event(priv, CUS_EVT_BG_SCAN); memset(&wrqu, 0, sizeof(union iwreq_data)); wireless_send_event(priv->netdev, SIOCGIWSCAN, &wrqu, NULL); } +#endif +#ifdef STA_CFG80211 + if (IS_STA_CFG80211(cfg80211_wext)) { + woal_inform_bss_from_scan_result(priv, NULL); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) || defined(COMPAT_WIRELESS) + if (priv->mrvl_rssi_low) { + cfg80211_cqm_rssi_notify(priv->netdev, + NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH, + GFP_KERNEL); + } +#endif + } #endif break; case MLAN_EVENT_ID_FW_CHANNEL_SWITCH_ANN: @@ -1285,10 +1354,15 @@ moal_recv_event(IN t_void * pmoal_handle, IN pmlan_event pmevent) #endif /* UAP_WEXT */ break; case MLAN_EVENT_ID_DRV_MGMT_FRAME: +#ifdef UAP_WEXT + if (IS_UAP_WEXT(cfg80211_wext)) { + woal_broadcast_event(priv, pmevent->event_buf, pmevent->event_len); + } +#endif /* UAP_WEXT */ #ifdef WIFI_DIRECT_SUPPORT #if defined(STA_CFG80211) || defined(UAP_CFG80211) if (IS_STA_OR_UAP_CFG80211(cfg80211_wext)) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) || defined(COMPAT_WIRELESS) +#if LINUX_VERSION_CODE >= WIFI_DIRECT_KERNEL_VERSION if (priv->netdev && priv->netdev->ieee80211_ptr->wiphy->mgmt_stypes) { /* frmctl + durationid + addr1 + addr2 + addr3 + seqctl */ #define PACKET_ADDR4_POS (2 + 2 + 6 + 6 + 6 + 2) @@ -1310,11 +1384,6 @@ moal_recv_event(IN t_void * pmoal_handle, IN pmlan_event pmevent) } #endif /* STA_CFG80211 || UAP_CFG80211 */ #endif /* WIFI_DIRECT_SUPPORT */ -#ifdef UAP_WEXT - if (IS_UAP_WEXT(cfg80211_wext)) { - woal_broadcast_event(priv, pmevent->event_buf, pmevent->event_len); - } -#endif /* UAP_WEXT */ break; #endif /* UAP_SUPPORT */ case MLAN_EVENT_ID_DRV_PASSTHRU: diff --git a/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c b/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c index d6768a3bd647..ed44cdefe43b 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_sta_cfg80211.c @@ -44,6 +44,11 @@ static int woal_cfg80211_dump_station(struct wiphy *wiphy, static int woal_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, bool enabled, int timeout); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) || defined(COMPAT_WIRELESS) +static int woal_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy, + struct net_device *dev, + s32 rssi_thold, u32 rssi_hyst); +#endif static int woal_cfg80211_set_tx_power(struct wiphy *wiphy, #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) && !defined(COMPAT_WIRELESS) @@ -98,6 +103,9 @@ static struct cfg80211_ops woal_cfg80211_sta_ops = { .set_default_key = woal_cfg80211_set_default_key, .set_power_mgmt = woal_cfg80211_set_power_mgmt, .set_tx_power = woal_cfg80211_set_tx_power, +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) || defined(COMPAT_WIRELESS) + .set_cqm_rssi_config = woal_cfg80211_set_cqm_rssi_config, +#endif }; #if defined(WIFI_DIRECT_SUPPORT) @@ -518,14 +526,13 @@ woal_cfg80211_assoc_ies_cfg(moal_private * priv, t_u8 * ie, int ie_len) /** * @brief Send domain info command to FW * - * @param wiphy A pointer to wiphy structure + * @param priv A pointer to moal_private structure * * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE */ static mlan_status -woal_send_domain_info_cmd_fw(struct wiphy *wiphy) +woal_send_domain_info_cmd_fw(moal_private * priv) { - moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); mlan_status ret = MLAN_STATUS_SUCCESS; enum ieee80211_band band; struct ieee80211_supported_band *sband = NULL; @@ -540,6 +547,12 @@ woal_send_domain_info_cmd_fw(struct wiphy *wiphy) ENTER(); + if (!priv->wdev || !priv->wdev->wiphy) { + PRINTM(MERROR, "No wdev or wiphy in priv\n"); + ret = MLAN_STATUS_FAILURE; + goto done; + } + /* Allocate an IOCTL request buffer */ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg)); if (req == NULL) { @@ -556,7 +569,7 @@ woal_send_domain_info_cmd_fw(struct wiphy *wiphy) goto done; } band = woal_band_cfg_to_ieee_band(radio_cfg->param.band_cfg.config_bands); - if (!wiphy->bands[band]) { + if (!priv->wdev->wiphy->bands[band]) { PRINTM(MERROR, "11D: setting domain info in FW failed"); ret = MLAN_STATUS_FAILURE; goto done; @@ -580,7 +593,7 @@ woal_send_domain_info_cmd_fw(struct wiphy *wiphy) cfg_11d->param.domain_info.country_code[2] = ' '; cfg_11d->param.domain_info.band = band; - sband = wiphy->bands[band]; + sband = priv->wdev->wiphy->bands[band]; for (i = 0; (i < sband->n_channels) && (no_of_sub_band < MRVDRV_MAX_SUBBAND_802_11D); i++) { channel = &sband->channels[i]; @@ -641,18 +654,17 @@ woal_send_domain_info_cmd_fw(struct wiphy *wiphy) * @brief Request the driver to change the channel and * change domain info according to that channel * - * @param wiphy A pointer to wiphy structure + * @param priv A pointer to moal_private structure * @param chan A pointer to ieee80211_channel structure * @param channel_type Channel type of nl80211_channel_type * * @return 0 -- success, otherwise fail */ int -woal_set_rf_channel(struct wiphy *wiphy, +woal_set_rf_channel(moal_private * priv, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type) { - moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); int ret = 0; t_u32 mode, config_bands = 0; mlan_ioctl_req *req1 = NULL, *req2 = NULL; @@ -692,7 +704,7 @@ woal_set_rf_channel(struct wiphy *wiphy, ret = -EFAULT; goto done; } - woal_send_domain_info_cmd_fw(wiphy); + woal_send_domain_info_cmd_fw(priv); } PRINTM(MINFO, "Setting band %d, channel bandwidth %d and mode = %d\n", @@ -864,17 +876,15 @@ woal_inform_bss_from_scan_result(moal_private * priv, mlan_802_11_ssid * ssid) struct ieee80211_channel *chan; mlan_scan_resp scan_resp; BSSDescriptor_t *scan_table; - t_u8 *ie, *tmp, *ie_buf; - __le32 ie_len; t_u64 ts = 0; - t_u8 *cap; - t_u8 *beacon; - int beacon_size, i, j; - IEEEtypes_ElementId_e element_id; - t_u8 element_len; + u16 cap_info = 0; + int i = 0; struct cfg80211_bss *pub = NULL; - ENTER(); + if (!priv->wdev || !priv->wdev->wiphy) { + LEAVE(); + return MLAN_STATUS_FAILURE; + } memset(&scan_resp, 0, sizeof(scan_resp)); if (MLAN_STATUS_SUCCESS != woal_get_scan_table(priv, @@ -885,14 +895,6 @@ woal_inform_bss_from_scan_result(moal_private * priv, mlan_802_11_ssid * ssid) } if (scan_resp.num_in_scan_table) { -#define MAX_IE_BUF 2048 - ie_buf = kzalloc(MAX_IE_BUF, GFP_KERNEL); - if (ie_buf == NULL) { - PRINTM(MERROR, "%s: failed to allocate ie_buf\n", __func__); - ret = MLAN_STATUS_FAILURE; - goto done; - } - scan_table = (BSSDescriptor_t *) scan_resp.pscan_table; for (i = 0; i < scan_resp.num_in_scan_table; i++) { if (ssid) { @@ -905,105 +907,31 @@ woal_inform_bss_from_scan_result(moal_private * priv, mlan_802_11_ssid * ssid) (int) scan_table[i].channel); continue; } - memset(ie_buf, 0, MAX_IE_BUF); - ie_buf[0] = WLAN_EID_SSID; - ie_buf[1] = scan_table[i].ssid.ssid_len; - memcpy(&ie_buf[sizeof(IEEEtypes_Header_t)], - scan_table[i].ssid.ssid, ie_buf[1]); - - ie = ie_buf + ie_buf[1] + sizeof(IEEEtypes_Header_t); - ie_len = ie_buf[1] + sizeof(IEEEtypes_Header_t); - - ie[0] = WLAN_EID_SUPP_RATES; - - for (j = 0; j < sizeof(scan_table[i].supported_rates); j++) { - if (!scan_table[i].supported_rates[j]) - break; - else { - ie[j + sizeof(IEEEtypes_Header_t)] = - scan_table[i].supported_rates[j]; - } - } - - ie[1] = j; - ie_len += ie[1] + sizeof(IEEEtypes_Header_t); - - beacon = scan_table[i].pbeacon_buf; - beacon_size = scan_table[i].beacon_buf_size; - - /* Skip time stamp, beacon interval and capability */ - - if (beacon) { - beacon += sizeof(scan_table[i].beacon_period) - + sizeof(scan_table[i].time_stamp) + - +sizeof(scan_table[i].cap_info); - - beacon_size -= sizeof(scan_table[i].beacon_period) - + sizeof(scan_table[i].time_stamp) - + sizeof(scan_table[i].cap_info); - } - - while (beacon_size >= sizeof(IEEEtypes_Header_t)) { - ie = ie_buf + ie_len; - element_id = *beacon; - element_len = *(beacon + 1); - if (beacon_size < (int) element_len + - sizeof(IEEEtypes_Header_t)) { - PRINTM(MERROR, - "Get scan: Error in processing IE, " - "bytes left < IE length\n"); - break; - } - switch (element_id) { - case WLAN_EID_FH_PARAMS: - case WLAN_EID_DS_PARAMS: - case WLAN_EID_CF_PARAMS: - case WLAN_EID_IBSS_PARAMS: - case WLAN_EID_COUNTRY: - case WLAN_EID_PWR_CONSTRAINT: - case WLAN_EID_PWR_CAPABILITY: - case WLAN_EID_TPC_REQUEST: - case WLAN_EID_TPC_REPORT: - case WLAN_EID_CHANNEL_SWITCH: - case WLAN_EID_QUIET: - case WLAN_EID_IBSS_DFS: - case WLAN_EID_SUPPORTED_CHANNELS: - case WLAN_EID_ERP_INFO: - case WLAN_EID_EXT_SUPP_RATES: - case WLAN_EID_HT_CAPABILITY: - case WLAN_EID_HT_INFORMATION: - case EXT_CAPABILITY: // TODO: Replace when kernel macro - // available - case WLAN_EID_RSN: - case WAPI_IE: // TODO: Replace when kernel macro available - case WLAN_EID_VENDOR_SPECIFIC: - ie[0] = element_id; - ie[1] = element_len; - tmp = (t_u8 *) beacon; - memcpy(&ie[sizeof(IEEEtypes_Header_t)], - tmp + sizeof(IEEEtypes_Header_t), element_len); - ie_len += ie[1] + sizeof(IEEEtypes_Header_t); - break; - default: - break; - } - beacon += element_len + sizeof(IEEEtypes_Header_t); - beacon_size -= (element_len + sizeof(IEEEtypes_Header_t)); - } chan = ieee80211_get_channel(priv->wdev->wiphy, scan_table[i].freq); - cap = (t_u8 *) & scan_table[i].cap_info; + if (!chan) { + PRINTM(MERROR, + "Fail to get chan with freq: channel=%d freq=%d\n", + (int) scan_table[i].channel, (int) scan_table[i].freq); + continue; + } + memcpy(&ts, scan_table[i].time_stamp, sizeof(ts)); + memcpy(&cap_info, &scan_table[i].cap_info, sizeof(cap_info)); pub = cfg80211_inform_bss(priv->wdev->wiphy, chan, scan_table[i].mac_address, - ts, (__le16) (*cap), - scan_table[i].beacon_period, ie_buf, - ie_len, + ts, cap_info, + scan_table[i].beacon_period, + scan_table[i].pbeacon_buf + + WLAN_802_11_FIXED_IE_SIZE, + scan_table[i].beacon_buf_size - + WLAN_802_11_FIXED_IE_SIZE, -RSSI_DBM_TO_MDM(scan_table[i].rssi), GFP_KERNEL); - pub->len_information_elements = pub->len_beacon_ies; + if (pub) { + pub->len_information_elements = pub->len_beacon_ies; + cfg80211_put_bss(pub); + } } - kfree(ie_buf); } - done: LEAVE(); return ret; @@ -1044,6 +972,7 @@ woal_cfg80211_inform_ibss_bss(moal_private * priv, mlan_ds_get_signal signal; t_u8 ie_buf[MLAN_MAX_SSID_LENGTH + sizeof(IEEEtypes_Header_t)]; int ie_len = 0; + struct cfg80211_bss *bss = NULL; ENTER(); @@ -1068,11 +997,12 @@ woal_cfg80211_inform_ibss_bss(moal_private * priv, goto done; } - cfg80211_inform_bss(priv->wdev->wiphy, chan, - bss_info.bssid, 0, WLAN_CAPABILITY_IBSS, - beacon_interval, ie_buf, ie_len, signal.bcn_rssi_avg, - GFP_KERNEL); - + bss = cfg80211_inform_bss(priv->wdev->wiphy, chan, + bss_info.bssid, 0, WLAN_CAPABILITY_IBSS, + beacon_interval, ie_buf, ie_len, + signal.bcn_rssi_avg, GFP_KERNEL); + if (bss) + cfg80211_put_bss(bss); done: LEAVE(); return ret; @@ -1081,15 +1011,14 @@ woal_cfg80211_inform_ibss_bss(moal_private * priv, /** * @brief Request the driver for (re)association * - * @param wiphy A pointer to wiphy structure + * @param priv A pointer to moal_private structure * @param sme A pointer to connect parameters * * @return 0 -- success, otherwise fail */ static int -woal_cfg80211_assoc(struct wiphy *wiphy, void *sme) +woal_cfg80211_assoc(moal_private * priv, void *sme) { - moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); struct cfg80211_ibss_params *ibss_param = NULL; struct cfg80211_connect_params *conn_param = NULL; mlan_802_11_ssid req_ssid; @@ -1170,7 +1099,7 @@ woal_cfg80211_assoc(struct wiphy *wiphy, void *sme) ret = -EFAULT; goto done; } - if (MLAN_STATUS_SUCCESS != woal_set_rf_channel(wiphy, + if (MLAN_STATUS_SUCCESS != woal_set_rf_channel(priv, channel, woal_channel_to_nl80211_channel_type (radio_cfg->param. @@ -1188,8 +1117,9 @@ woal_cfg80211_assoc(struct wiphy *wiphy, void *sme) } if (MLAN_STATUS_SUCCESS != - woal_cfg80211_set_key(priv, 0, 0, NULL, 0, NULL, 0, 0, NULL, 1)) { - /* Disable keys */ + woal_cfg80211_set_key(priv, 0, 0, NULL, 0, NULL, 0, + KEY_INDEX_CLEAR_ALL, NULL, 1)) { + /* Disable keys and clear all previous security settings */ ret = -EFAULT; goto done; } @@ -1386,6 +1316,58 @@ woal_cfg80211_assoc(struct wiphy *wiphy, void *sme) return ret; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) || defined(COMPAT_WIRELESS) +/** + * @brief Set/Get DTIM period + * + * @param priv A pointer to moal_private structure + * @param action Action set or get + * @param wait_option Wait option + * @param value DTIM period + * + * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail + */ +static mlan_status +woal_set_get_dtim_period(moal_private * priv, + t_u32 action, t_u8 wait_option, t_u8 * value) +{ + mlan_ioctl_req *req = NULL; + mlan_ds_snmp_mib *mib = NULL; + mlan_status ret = MLAN_STATUS_SUCCESS; + + ENTER(); + + /* Allocate an IOCTL request buffer */ + req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib)); + if (req == NULL) { + ret = MLAN_STATUS_FAILURE; + goto done; + } + + /* Fill request buffer */ + mib = (mlan_ds_snmp_mib *) req->pbuf; + mib->sub_command = MLAN_OID_SNMP_MIB_DTIM_PERIOD; + req->req_id = MLAN_IOCTL_SNMP_MIB; + req->action = action; + + if (action == MLAN_ACT_SET) { + mib->param.dtim_period = *value; + } + + /* Send IOCTL request to MLAN */ + ret = woal_request_ioctl(priv, req, wait_option); + if (ret == MLAN_STATUS_SUCCESS && action == MLAN_ACT_GET) { + *value = (t_u8) mib->param.dtim_period; + } + + done: + if (req && (ret != MLAN_STATUS_PENDING)) + kfree(req); + LEAVE(); + return ret; +} +#endif + /** * @brief Request the driver to dump the station information * @@ -1397,10 +1379,14 @@ woal_cfg80211_assoc(struct wiphy *wiphy, void *sme) static mlan_status woal_cfg80211_dump_station_info(moal_private * priv, struct station_info *sinfo) { + mlan_status ret = MLAN_STATUS_SUCCESS; mlan_ds_get_signal signal; mlan_ioctl_req *req = NULL; mlan_ds_rate *rate = NULL; - mlan_status ret = MLAN_STATUS_SUCCESS; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) || defined(COMPAT_WIRELESS) + mlan_bss_info bss_info; + t_u8 dtim_period = 0; +#endif ENTER(); sinfo->filled = STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES | @@ -1443,6 +1429,28 @@ woal_cfg80211_dump_station_info(moal_private * priv, struct station_info *sinfo) sinfo->tx_packets = priv->stats.tx_packets; sinfo->signal = signal.bcn_rssi_avg; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0) || defined(COMPAT_WIRELESS) + /* Update BSS information */ + sinfo->filled |= STATION_INFO_BSS_PARAM; + sinfo->bss_param.flags = 0; + ret = woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info); + if (ret) + goto done; + if (bss_info.capability_info & WLAN_CAPABILITY_SHORT_PREAMBLE) + sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_PREAMBLE; + if (bss_info.capability_info & WLAN_CAPABILITY_SHORT_SLOT_TIME) + sinfo->bss_param.flags |= BSS_PARAM_FLAGS_SHORT_SLOT_TIME; + sinfo->bss_param.beacon_interval = bss_info.beacon_interval; + /* Get DTIM period */ + ret = woal_set_get_dtim_period(priv, MLAN_ACT_GET, + MOAL_IOCTL_WAIT, &dtim_period); + if (ret) { + PRINTM(MERROR, "Get DTIM period failed\n"); + goto done; + } + sinfo->bss_param.dtim_period = dtim_period; +#endif + done: if (req) kfree(req); @@ -1472,6 +1480,12 @@ woal_cfg80211_reg_notifier(struct wiphy *wiphy, ENTER(); + if (!priv) { + PRINTM(MFATAL, "Unable to get priv in %s()\n", __FUNCTION__); + LEAVE(); + return -EINVAL; + } + PRINTM(MINFO, "cfg80211 regulatory domain callback " "%c%c\n", request->alpha2[0], request->alpha2[1]); @@ -1496,7 +1510,7 @@ woal_cfg80211_reg_notifier(struct wiphy *wiphy, break; } - if (MLAN_STATUS_SUCCESS != woal_send_domain_info_cmd_fw(wiphy)) + if (MLAN_STATUS_SUCCESS != woal_send_domain_info_cmd_fw(priv)) ret = -EFAULT; LEAVE(); @@ -1519,7 +1533,7 @@ static int woal_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_scan_request *request) { - moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + moal_private *priv = (moal_private *) woal_get_netdev_priv(dev); wlan_user_scan_cfg scan_req; struct ieee80211_channel *chan; int ret = 0, i; @@ -1604,10 +1618,11 @@ static int woal_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_connect_params *sme) { - moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + moal_private *priv = (moal_private *) woal_get_netdev_priv(dev); int ret = 0; ENTER(); + PRINTM(MINFO, "Received association request on %s\n", dev->name); if (priv->wdev->iftype != NL80211_IFTYPE_STATION @@ -1645,7 +1660,7 @@ woal_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE) woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE); - ret = woal_cfg80211_assoc(wiphy, (void *) sme); + ret = woal_cfg80211_assoc(priv, (void *) sme); if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE) woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE); @@ -1680,7 +1695,7 @@ static int woal_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, t_u16 reason_code) { - moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + moal_private *priv = (moal_private *) woal_get_netdev_priv(dev); ENTER(); PRINTM(MINFO, "Received disassociation request on %s\n", dev->name); @@ -1729,7 +1744,7 @@ woal_cfg80211_get_station(struct wiphy *wiphy, t_u8 * mac, struct station_info *sinfo) { mlan_status ret = MLAN_STATUS_SUCCESS; - moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + moal_private *priv = (moal_private *) woal_get_netdev_priv(dev); ENTER(); @@ -1778,7 +1793,7 @@ woal_cfg80211_dump_station(struct wiphy *wiphy, t_u8 * mac, struct station_info *sinfo) { mlan_status ret = MLAN_STATUS_SUCCESS; - moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + moal_private *priv = (moal_private *) woal_get_netdev_priv(dev); ENTER(); @@ -1814,7 +1829,7 @@ static int woal_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_ibss_params *params) { - moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + moal_private *priv = (moal_private *) woal_get_netdev_priv(dev); int ret = 0; ENTER(); @@ -1826,7 +1841,7 @@ woal_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, return -EINVAL; } - ret = woal_cfg80211_assoc(wiphy, (void *) params); + ret = woal_cfg80211_assoc(priv, (void *) params); if (!ret) { cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, GFP_KERNEL); @@ -1852,7 +1867,7 @@ woal_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, static int woal_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) { - moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + moal_private *priv = (moal_private *) woal_get_netdev_priv(dev); ENTER(); @@ -1898,7 +1913,7 @@ woal_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, bool enabled, int timeout) { int ret = 0, disabled; - moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + moal_private *priv = (moal_private *) woal_get_netdev_priv(dev); ENTER(); @@ -1940,6 +1955,12 @@ woal_cfg80211_set_tx_power(struct wiphy *wiphy, ENTER(); + if (!priv) { + PRINTM(MFATAL, "Unable to get priv in %s()\n", __FUNCTION__); + LEAVE(); + return -EFAULT; + } + if (type) { power_cfg.is_power_auto = 0; power_cfg.power_level = dbm; @@ -1954,6 +1975,33 @@ woal_cfg80211_set_tx_power(struct wiphy *wiphy, return ret; } +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) || defined(COMPAT_WIRELESS) +/** + * CFG802.11 operation handler for connection quality monitoring. + * + * @param wiphy A pointer to wiphy structure + * @param dev A pointer to net_device structure + * @param rssi_thold rssi threshold + * @param rssi_hyst rssi hysteresis + */ +static int +woal_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy, + struct net_device *dev, + s32 rssi_thold, u32 rssi_hyst) +{ + moal_private *priv = (moal_private *) woal_get_netdev_priv(dev); + ENTER(); + priv->cqm_rssi_thold = rssi_thold; + priv->cqm_rssi_hyst = rssi_hyst; + + PRINTM(MIOCTL, "rssi_thold=%d rssi_hyst=%d\n", + (int) rssi_thold, (int) rssi_hyst); + woal_set_rssi_threshold(priv, 0); + LEAVE(); + return 0; +} +#endif + /** * @brief Sets up the CFG802.11 specific HT capability fields * with default values @@ -2010,7 +2058,7 @@ woal_cfg80211_setup_sta_ht_cap(struct ieee80211_sta_ht_cap *ht_info, /** * @brief remain on channel config * - * @param wiphy A pointer to wiphy structure + * @param priv A pointer to moal_private structure * @param wait_option Wait option * @param cancel cancel remain on channel flag * @param status A pointer to status, success, in process or reject @@ -2021,7 +2069,7 @@ woal_cfg80211_setup_sta_ht_cap(struct ieee80211_sta_ht_cap *ht_info, * @return 0 -- success, otherwise fail */ int -woal_cfg80211_remain_on_channel_cfg(struct wiphy *wiphy, +woal_cfg80211_remain_on_channel_cfg(moal_private * priv, t_u8 wait_option, t_u8 remove, t_u8 * status, struct ieee80211_channel *chan, @@ -2029,8 +2077,6 @@ woal_cfg80211_remain_on_channel_cfg(struct wiphy *wiphy, t_u32 duration) { mlan_ds_remain_chan chan_cfg; - moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); - int ret = 0; ENTER(); @@ -2042,10 +2088,6 @@ woal_cfg80211_remain_on_channel_cfg(struct wiphy *wiphy, chan_cfg.bandcfg = 0; else if (chan->band == IEEE80211_BAND_5GHZ) chan_cfg.bandcfg = 1; -/** secondary channel is below */ -#define SEC_CHAN_BELOW 0x30 -/** secondary channel is above */ -#define SEC_CHAN_ABOVE 0x10 switch (channel_type) { case NL80211_CHAN_HT40MINUS: chan_cfg.bandcfg |= SEC_CHANNEL_BELOW; @@ -2084,14 +2126,14 @@ static int woal_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, struct net_device *dev, u64 cookie) { - moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + moal_private *priv = (moal_private *) woal_get_netdev_priv(dev); int ret = 0; t_u8 status = 1; ENTER(); if (priv->phandle->remain_on_channel) { - if (woal_cfg80211_remain_on_channel_cfg(priv->wdev->wiphy, + if (woal_cfg80211_remain_on_channel_cfg(priv, MOAL_IOCTL_WAIT, MTRUE, &status, NULL, 0, 0)) { PRINTM(MERROR, "Fail to cancel remain on channel\n"); @@ -2133,7 +2175,7 @@ woal_cfg80211_remain_on_channel(struct wiphy *wiphy, enum nl80211_channel_type channel_type, unsigned int duration, u64 * cookie) { - moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + moal_private *priv = (moal_private *) woal_get_netdev_priv(dev); int ret = 0; t_u8 status = 1; @@ -2146,8 +2188,9 @@ woal_cfg80211_remain_on_channel(struct wiphy *wiphy, } /** cancel previous remain on channel */ if (priv->phandle->remain_on_channel) { - if (woal_cfg80211_remain_on_channel_cfg - (wiphy, MOAL_IOCTL_WAIT, MTRUE, &status, NULL, 0, 0)) { + if (woal_cfg80211_remain_on_channel_cfg(priv, + MOAL_IOCTL_WAIT, MTRUE, &status, + NULL, 0, 0)) { PRINTM(MERROR, "Fail to cancel remain on channel\n"); ret = -EFAULT; goto done; @@ -2156,7 +2199,7 @@ woal_cfg80211_remain_on_channel(struct wiphy *wiphy, priv->phandle->remain_on_channel = MFALSE; } if (MLAN_STATUS_SUCCESS != - woal_cfg80211_remain_on_channel_cfg(wiphy, MOAL_IOCTL_WAIT, + woal_cfg80211_remain_on_channel_cfg(priv, MOAL_IOCTL_WAIT, MFALSE, &status, chan, channel_type, (t_u32) duration)) { ret = -EFAULT; @@ -2195,14 +2238,15 @@ static int woal_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, struct net_device *dev, u64 cookie) { - moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + moal_private *priv = (moal_private *) woal_get_netdev_priv(dev); int ret = 0; t_u8 status = 1; ENTER(); PRINTM(MIOCTL, "Cancel remain on Channel: cookie = %#llx\n", cookie); - if (woal_cfg80211_remain_on_channel_cfg - (wiphy, MOAL_IOCTL_WAIT, MTRUE, &status, NULL, 0, 0)) { + if (woal_cfg80211_remain_on_channel_cfg(priv, + MOAL_IOCTL_WAIT, MTRUE, &status, + NULL, 0, 0)) { PRINTM(MERROR, "Fail to cancel remain on channel\n"); ret = -EFAULT; goto done; diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.c b/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.c index 7f7528216282..18d18328d0ed 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_uap_cfg80211.c @@ -124,44 +124,6 @@ static struct cfg80211_ops woal_cfg80211_uap_ops = { /******************************************************** Global Functions ********************************************************/ -/** - * @brief Filter specific IE in ie buf - * - * @param ie Pointer to IEs - * @param len Total length of ie - * @param ie_out Pointer to out IE buf - * - * @return out IE length - */ -static t_u16 -woal_filter_beacon_ies(const t_u8 * ie, int len, t_u8 * ie_out) -{ - int left_len = len; - const t_u8 *pos = ie; - int length; - t_u8 id = 0; - t_u16 out_len = 0; - - /* ERP_INFO and RSN IE will be fileter out */ - while (left_len >= 2) { - length = *(pos + 1); - id = *pos; - if ((length + 2) > left_len) - break; - switch (id) { - case ERP_INFO: - case RSN_IE: - break; - default: - memcpy(ie_out + out_len, pos, length + 2); - out_len += length + 2; - break; - } - pos += (length + 2); - left_len -= (length + 2); - } - return out_len; -} #if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0) && !defined(COMPAT_WIRELESS) /** @@ -363,442 +325,6 @@ woal_find_wpa_ies(t_u8 * ie, int len, mlan_uap_bss_param * sys_config) } #endif -/** - * @brief Look up specific IE in a buf - * - * @param ie Pointer to IEs - * @param len Total length of ie - * @param id Element id to lookup - * - * @return Pointer of the specific IE -- success, NULL -- fail - */ -static const t_u8 * -woal_parse_ie_tlv(const t_u8 * ie, int len, t_u8 id) -{ - int left_len = len; - const t_u8 *pos = ie; - int length; - - /* IE format: | u8 | id | | u8 | len | | var | data | */ - while (left_len >= 2) { - length = *(pos + 1); - if ((*pos == id) && (length + 2) <= left_len) - return pos; - pos += (length + 2); - left_len -= (length + 2); - } - - return NULL; -} - -/** - * @brief Add custom ie to mgmt frames. - * - * @param priv A pointer to moal private structure - * @param beacon_ies_data Beacon ie - * @param beacon_index The index for beacon when auto index - * @param proberesp_ies_data Probe resp ie - * @param proberesp_index The index for probe resp when auto index - * @param assocresp_ies_data Assoc resp ie - * @param assocresp_index The index for assoc resp when auto index - * @param probereq_ies_data Probe req ie - * @param probereq_index The index for probe req when auto index * - * - * @return 0 -- success, otherwise fail - */ -static int -woal_cfg80211_custom_ie(moal_private * priv, - custom_ie * beacon_ies_data, t_u16 * beacon_index, - custom_ie * proberesp_ies_data, t_u16 * proberesp_index, - custom_ie * assocresp_ies_data, t_u16 * assocresp_index, - custom_ie * probereq_ies_data, t_u16 * probereq_index) -{ - mlan_ioctl_req *ioctl_req = NULL; - mlan_ds_misc_cfg *misc = NULL; - mlan_ds_misc_custom_ie *custom_ie = NULL; - t_u8 *pos = NULL; - t_u16 len = 0; - int ret = 0; - - ENTER(); - - if (!(custom_ie = kmalloc(sizeof(mlan_ds_misc_custom_ie), GFP_KERNEL))) { - ret = -ENOMEM; - goto done; - } - - memset(custom_ie, 0x00, sizeof(mlan_ds_misc_custom_ie)); - custom_ie->type = TLV_TYPE_MGMT_IE; - - pos = (t_u8 *) custom_ie->ie_data_list; - if (beacon_ies_data) { - len = sizeof(*beacon_ies_data) - MAX_IE_SIZE - + beacon_ies_data->ie_length; - memcpy(pos, beacon_ies_data, len); - pos += len; - custom_ie->len += len; - } - - if (proberesp_ies_data) { - len = sizeof(*proberesp_ies_data) - MAX_IE_SIZE - + proberesp_ies_data->ie_length; - memcpy(pos, proberesp_ies_data, len); - pos += len; - custom_ie->len += len; - } - - if (assocresp_ies_data) { - len = sizeof(*assocresp_ies_data) - MAX_IE_SIZE - + assocresp_ies_data->ie_length; - memcpy(pos, assocresp_ies_data, len); - custom_ie->len += len; - } - - if (probereq_ies_data) { - len = sizeof(*probereq_ies_data) - MAX_IE_SIZE - + probereq_ies_data->ie_length; - memcpy(pos, probereq_ies_data, len); - pos += len; - custom_ie->len += len; - } - - ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); - if (ioctl_req == NULL) { - ret = -ENOMEM; - goto done; - } - - misc = (mlan_ds_misc_cfg *) ioctl_req->pbuf; - misc->sub_command = MLAN_OID_MISC_CUSTOM_IE; - ioctl_req->req_id = MLAN_IOCTL_MISC_CFG; - ioctl_req->action = MLAN_ACT_SET; - - memcpy(&misc->param.cust_ie, custom_ie, sizeof(mlan_ds_misc_custom_ie)); - - if (MLAN_STATUS_SUCCESS != - woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) { - ret = -EFAULT; - goto done; - } - - /* get the assigned index */ - pos = (t_u8 *) (&misc->param.cust_ie.ie_data_list[0].ie_index); - if (beacon_ies_data && beacon_ies_data->ie_length - && beacon_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) { - /* save beacon ie index after auto-indexing */ - *beacon_index = misc->param.cust_ie.ie_data_list[0].ie_index; - len = sizeof(*beacon_ies_data) - MAX_IE_SIZE - + beacon_ies_data->ie_length; - pos += len; - } - - if (proberesp_ies_data && proberesp_ies_data->ie_length - && proberesp_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) { - /* save probe resp ie index after auto-indexing */ - *proberesp_index = *((t_u16 *) pos); - len = sizeof(*proberesp_ies_data) - MAX_IE_SIZE - + proberesp_ies_data->ie_length; - pos += len; - } - - if (assocresp_ies_data && assocresp_ies_data->ie_length - && assocresp_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) { - /* save assoc resp ie index after auto-indexing */ - *assocresp_index = *((t_u16 *) pos); - len = sizeof(*assocresp_ies_data) - MAX_IE_SIZE - + assocresp_ies_data->ie_length; - pos += len; - } - if (probereq_ies_data && probereq_ies_data->ie_length - && probereq_ies_data->ie_index == MLAN_CUSTOM_IE_AUTO_IDX_MASK) { - /* save probe resp ie index after auto-indexing */ - *probereq_index = *((t_u16 *) pos); - len = sizeof(*probereq_ies_data) - MAX_IE_SIZE - + probereq_ies_data->ie_length; - pos += len; - } - - if (ioctl_req->status_code == MLAN_ERROR_IOCTL_FAIL) - ret = -EFAULT; - - done: - if (ioctl_req) - kfree(ioctl_req); - if (custom_ie) - kfree(custom_ie); - LEAVE(); - return ret; -} - -/** - * @brief This function returns priv - * based on mgmt ie index - * - * @param handle A pointer to moal_handle - * @param index mgmt ie index - * - * @return Pointer to moal_private - */ -static moal_private * -woal_get_priv_by_mgmt_index(moal_handle * handle, t_u16 index) -{ - int i; - - for (i = 0; i < MIN(handle->priv_num, MLAN_MAX_BSS_NUM); i++) { - if (handle->priv[i]) { - if (handle->priv[i]->probereq_index == index) - return (handle->priv[i]); - } - } - return NULL; -} - -/** - * @brief config AP or GO for mgmt frame ies. - * - * @param priv A pointer to moal private structure - * @param beacon_ies A pointer to beacon ies - * @param beacon_ies_len Beacon ies length - * @param proberesp_ies A pointer to probe resp ies - * @param proberesp_ies_len Probe resp ies length - * @param assocresp_ies A pointer to probe resp ies - * @param assocresp_ies_len Assoc resp ies length - * @param probereq_ies A pointer to probe req ies - * @param probereq_ies_len Probe req ies length * - * @param mask Mgmt frame mask - * - * @return 0 -- success, otherwise fail - */ -int -woal_cfg80211_mgmt_frame_ie(moal_private * priv, - const t_u8 * beacon_ies, size_t beacon_ies_len, - const t_u8 * proberesp_ies, - size_t proberesp_ies_len, - const t_u8 * assocresp_ies, - size_t assocresp_ies_len, const t_u8 * probereq_ies, - size_t probereq_ies_len, t_u16 mask) -{ - int ret = 0; - t_u8 *pos = NULL; - custom_ie *beacon_ies_data = NULL; - custom_ie *proberesp_ies_data = NULL; - custom_ie *assocresp_ies_data = NULL; - custom_ie *probereq_ies_data = NULL; - - /* static variables for mgmt frame ie auto-indexing */ - static t_u16 beacon_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; - static t_u16 proberesp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; - static t_u16 assocresp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; - static t_u16 probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; - moal_private *pmpriv = NULL; - static t_u16 rsn_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; - const t_u8 *rsn_ie; - - ENTER(); - - if (mask & MGMT_MASK_BEACON) { - if (!(beacon_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) { - ret = -ENOMEM; - goto done; - } - if (beacon_ies && beacon_ies_len) { - rsn_ie = - woal_parse_ie_tlv((t_u8 *) beacon_ies, (int) beacon_ies_len, - RSN_IE); - if (rsn_ie) { - beacon_ies_data->ie_index = rsn_index; - beacon_ies_data->mgmt_subtype_mask = - MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP | - MGMT_MASK_ASSOC_RESP; - beacon_ies_data->ie_length = rsn_ie[1] + 2; - memcpy(beacon_ies_data->ie_buffer, rsn_ie, rsn_ie[1] + 2); - if (MLAN_STATUS_SUCCESS != - woal_cfg80211_custom_ie(priv, beacon_ies_data, &rsn_index, - NULL, &proberesp_index, NULL, - &assocresp_index, NULL, - &probereq_index)) { - ret = -EFAULT; - goto done; - } - } - } else { - /* clear rsn_ie */ - if (rsn_index <= MAX_MGMT_IE_INDEX) { - beacon_ies_data->ie_index = rsn_index; - beacon_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK; - beacon_ies_data->ie_length = 0; - rsn_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; - if (MLAN_STATUS_SUCCESS != - woal_cfg80211_custom_ie(priv, beacon_ies_data, &rsn_index, - NULL, &proberesp_index, NULL, - &assocresp_index, NULL, - &probereq_index)) { - ret = -EFAULT; - goto done; - } - } - } - } - - if (mask & MGMT_MASK_PROBE_RESP) { - if (!(proberesp_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) { - ret = -ENOMEM; - goto done; - } - } - - if (mask & MGMT_MASK_ASSOC_RESP) { - if (!(assocresp_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) { - ret = -ENOMEM; - goto done; - } - } - if (mask & MGMT_MASK_PROBE_REQ) { - if (!(probereq_ies_data = kmalloc(sizeof(custom_ie), GFP_KERNEL))) { - ret = -ENOMEM; - goto done; - } - } - - if (beacon_ies_data) { - memset(beacon_ies_data, 0x00, sizeof(custom_ie)); - if (beacon_ies && beacon_ies_len) { - /* set the beacon ies */ - beacon_ies_data->ie_index = beacon_index; - beacon_ies_data->mgmt_subtype_mask = MGMT_MASK_BEACON; - beacon_ies_data->mgmt_subtype_mask |= MGMT_MASK_ASSOC_RESP; - beacon_ies_data->ie_length = woal_filter_beacon_ies(beacon_ies, - beacon_ies_len, - beacon_ies_data-> - ie_buffer); - } else { - /* clear the beacon ies */ - if (beacon_index > MAX_MGMT_IE_INDEX) { - PRINTM(MERROR, "Invalid beacon index for mgmt frame ie.\n"); - goto done; - } - - beacon_ies_data->ie_index = beacon_index; - beacon_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK; - beacon_ies_data->ie_length = 0; - beacon_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; - } - } - - if (proberesp_ies_data) { - memset(proberesp_ies_data, 0x00, sizeof(custom_ie)); - if (proberesp_ies && proberesp_ies_len) { - /* set the probe response ies */ - // proberesp_ies_data->ie_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; - proberesp_ies_data->ie_index = proberesp_index; - proberesp_ies_data->mgmt_subtype_mask = MGMT_MASK_PROBE_RESP; - proberesp_ies_data->ie_length = proberesp_ies_len; - pos = proberesp_ies_data->ie_buffer; - memcpy(pos, proberesp_ies, proberesp_ies_len); - } else { - /* clear the probe response ies */ - if (proberesp_index > MAX_MGMT_IE_INDEX) { - PRINTM(MERROR, "Invalid probe resp index for mgmt frame ie.\n"); - goto done; - } - - proberesp_ies_data->ie_index = proberesp_index; - proberesp_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK; - proberesp_ies_data->ie_length = 0; - proberesp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; - } - } - if (assocresp_ies_data) { - memset(assocresp_ies_data, 0x00, sizeof(custom_ie)); - if (assocresp_ies && assocresp_ies_len) { - /* set the assoc response ies */ - assocresp_ies_data->ie_index = assocresp_index; - assocresp_ies_data->mgmt_subtype_mask = MGMT_MASK_ASSOC_RESP; - assocresp_ies_data->ie_length = assocresp_ies_len; - pos = assocresp_ies_data->ie_buffer; - memcpy(pos, assocresp_ies, assocresp_ies_len); - } else { - /* clear the assoc response ies */ - if (assocresp_index > MAX_MGMT_IE_INDEX) { - PRINTM(MERROR, "Invalid assoc resp index for mgmt frame ie.\n"); - goto done; - } - - assocresp_ies_data->ie_index = assocresp_index; - assocresp_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK; - assocresp_ies_data->ie_length = 0; - assocresp_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; - } - } - - if (probereq_ies_data) { - memset(probereq_ies_data, 0x00, sizeof(custom_ie)); - if ((probereq_index != MLAN_CUSTOM_IE_AUTO_IDX_MASK) && - (priv->probereq_index != probereq_index)) { - pmpriv = woal_get_priv_by_mgmt_index(priv->phandle, probereq_index); - if (pmpriv) { - probereq_ies_data->ie_index = probereq_index; - probereq_ies_data->mgmt_subtype_mask = - MLAN_CUSTOM_IE_DELETE_MASK; - probereq_ies_data->ie_length = 0; - probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; - pmpriv->probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; - if (MLAN_STATUS_SUCCESS != - woal_cfg80211_custom_ie(pmpriv, NULL, &beacon_index, - NULL, &proberesp_index, - NULL, &assocresp_index, - probereq_ies_data, - &probereq_index)) { - ret = -EFAULT; - goto done; - } - memset(probereq_ies_data, 0x00, sizeof(custom_ie)); - } - } - if (probereq_ies && probereq_ies_len) { - /* set the probe req ies */ - probereq_ies_data->ie_index = probereq_index; - probereq_ies_data->mgmt_subtype_mask = MGMT_MASK_PROBE_REQ; - probereq_ies_data->ie_length = probereq_ies_len; - pos = probereq_ies_data->ie_buffer; - memcpy(pos, probereq_ies, probereq_ies_len); - } else { - /* clear the probe req ies */ - if (probereq_index > MAX_MGMT_IE_INDEX) { - PRINTM(MERROR, "Invalid probe resp index for mgmt frame ie.\n"); - goto done; - } - probereq_ies_data->ie_index = probereq_index; - probereq_ies_data->mgmt_subtype_mask = MLAN_CUSTOM_IE_DELETE_MASK; - probereq_ies_data->ie_length = 0; - probereq_index = MLAN_CUSTOM_IE_AUTO_IDX_MASK; - } - } - - if (MLAN_STATUS_SUCCESS != - woal_cfg80211_custom_ie(priv, beacon_ies_data, &beacon_index, - proberesp_ies_data, &proberesp_index, - assocresp_ies_data, &assocresp_index, - probereq_ies_data, &probereq_index)) { - ret = -EFAULT; - goto done; - } - if (probereq_ies_data) - priv->probereq_index = probereq_index; - - done: - if (beacon_ies_data) - kfree(beacon_ies_data); - if (proberesp_ies_data) - kfree(proberesp_ies_data); - if (assocresp_ies_data) - kfree(assocresp_ies_data); - - LEAVE(); - - return ret; -} - /** * @brief initialize AP or GO bss config * @@ -1330,7 +856,7 @@ woal_cfg80211_add_beacon(struct wiphy *wiphy, struct net_device *dev, struct beacon_parameters *params) { - moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + moal_private *priv = (moal_private *) woal_get_netdev_priv(dev); int ret = 0; ENTER(); @@ -1402,7 +928,7 @@ woal_cfg80211_set_beacon(struct wiphy *wiphy, struct net_device *dev, struct beacon_parameters *params) { - moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + moal_private *priv = (moal_private *) woal_get_netdev_priv(dev); int ret = 0; ENTER(); @@ -1471,7 +997,7 @@ woal_cfg80211_set_beacon(struct wiphy *wiphy, int woal_cfg80211_del_beacon(struct wiphy *wiphy, struct net_device *dev) { - moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + moal_private *priv = (moal_private *) woal_get_netdev_priv(dev); int ret = 0; ENTER(); @@ -1521,7 +1047,7 @@ int woal_uap_cfg80211_get_station(struct wiphy *wiphy, struct net_device *dev, u8 * mac, struct station_info *stainfo) { - moal_private *priv = (moal_private *) woal_get_wiphy_priv(wiphy); + moal_private *priv = (moal_private *) woal_get_netdev_priv(dev); int ret = -EFAULT; int i = 0; mlan_ds_get_info *info = NULL; diff --git a/drivers/net/wireless/sd8797/mlinux/moal_wext.c b/drivers/net/wireless/sd8797/mlinux/moal_wext.c index 8595892090fb..a967c939f009 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_wext.c +++ b/drivers/net/wireless/sd8797/mlinux/moal_wext.c @@ -2124,12 +2124,14 @@ woal_set_priv(struct net_device *dev, struct iw_request_info *info, priv->bg_scan_reported = MFALSE; len = sprintf(buf, "OK\n") + 1; } else if (strncmp(buf, "BGSCAN-STOP", strlen("BGSCAN-STOP")) == 0) { - if (MLAN_STATUS_SUCCESS != woal_stop_bg_scan(priv)) { - ret = -EFAULT; - goto done; + if (priv->bg_scan_start && !priv->scan_cfg.rssi_threshold) { + if (MLAN_STATUS_SUCCESS != woal_stop_bg_scan(priv)) { + ret = -EFAULT; + goto done; + } + priv->bg_scan_start = MFALSE; + priv->bg_scan_reported = MFALSE; } - priv->bg_scan_start = MFALSE; - priv->bg_scan_reported = MFALSE; len = sprintf(buf, "OK\n") + 1; } else if (strncmp(buf, "RXFILTER-START", strlen("RXFILTER-START")) == 0) { #ifdef MEF_CFG_RX_FILTER @@ -2326,13 +2328,13 @@ woal_set_essid(struct net_device *dev, struct iw_request_info *info, * Check if we asked for `any' or 'particular' */ if (!dwrq->flags) { - +#ifdef REASSOCIATION if (!req_ssid.ssid_len) { memset(&priv->prev_ssid_bssid.ssid, 0x00, sizeof(mlan_802_11_ssid)); memset(&priv->prev_ssid_bssid.bssid, 0x00, MLAN_MAC_ADDR_LENGTH); goto setessid_ret; } - +#endif /* Do normal SSID scanning */ if (MLAN_STATUS_SUCCESS != woal_request_scan(priv, MOAL_IOCTL_WAIT, NULL)) { @@ -2351,6 +2353,7 @@ woal_set_essid(struct net_device *dev, struct iw_request_info *info, PRINTM(MINFO, "Requested new SSID = %s\n", (char *) req_ssid.ssid); memcpy(&ssid_bssid.ssid, &req_ssid, sizeof(mlan_802_11_ssid)); + if (dwrq->flags != 0xFFFF) { if (MLAN_STATUS_SUCCESS != woal_find_essid(priv, &ssid_bssid)) { /* Do specific SSID scanning */ diff --git a/drivers/net/wireless/sd8797/mlinux/moal_wext.h b/drivers/net/wireless/sd8797/mlinux/moal_wext.h index 91f918e1b130..dfafff866b96 100644 --- a/drivers/net/wireless/sd8797/mlinux/moal_wext.h +++ b/drivers/net/wireless/sd8797/mlinux/moal_wext.h @@ -45,7 +45,6 @@ Change log: #define CUS_EVT_BEACON_SNR_HIGH "EVENT=BEACON_SNR_HIGH" /** Custom event : Max fail */ #define CUS_EVT_MAX_FAIL "EVENT=MAX_FAIL" -#define CUS_EVT_BG_SCAN "EVENT=BG_SCAN_REPORT" /** Custom event : Data RSSI low */ #define CUS_EVT_DATA_RSSI_LOW "EVENT=DATA_RSSI_LOW" /** Custom event : Data SNR low */ -- cgit v1.2.3