| /** @file moal_ioctl.c |
| * |
| * @brief This file contains ioctl function to MLAN |
| * |
| * |
| * Copyright 2008-2021 NXP |
| * |
| * This software file (the File) is distributed by NXP |
| * under the terms of the GNU General Public License Version 2, June 1991 |
| * (the License). You may use, redistribute and/or modify the 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" |
| #ifdef SDIO |
| #include "moal_sdio.h" |
| #endif |
| #ifdef USB |
| #include "moal_usb.h" |
| #endif |
| #ifdef UAP_SUPPORT |
| #include "moal_uap.h" |
| #endif |
| |
| #if defined(STA_CFG80211) || defined(UAP_CFG80211) |
| #include "moal_cfg80211.h" |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) |
| #include "moal_cfg80211_util.h" |
| #endif |
| #endif |
| |
| /******************************************************** |
| Local Variables |
| ********************************************************/ |
| #define MRVL_TLV_HEADER_SIZE 4 |
| /* NXP 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; |
| |
| /** Region code mapping */ |
| typedef struct _region_code_mapping_t { |
| /** Region */ |
| t_u8 region[COUNTRY_CODE_LEN]; |
| /** Code */ |
| t_u8 code; |
| } region_code_mapping_t; |
| |
| #define EU_REGION_CODE 0x30 |
| |
| /** Region code mapping table */ |
| static region_code_mapping_t region_code_mapping[] = { |
| {"00", 0x00}, /* World */ |
| {"US", 0x10}, /* US FCC */ |
| {"CA", 0x20}, /* IC Canada */ |
| {"SG", 0x10}, /* Singapore */ |
| {"EU", 0x30}, /* ETSI */ |
| {"AU", 0x30}, /* Australia */ |
| {"KR", 0x30}, /* Republic Of Korea */ |
| {"JP", 0x40}, /* Japan */ |
| {"CN", 0x50}, /* China */ |
| {"BR", 0x09}, /* Brazil */ |
| {"RU", 0x0f}, /* Russia */ |
| {"IN", 0x06}, /* India */ |
| {"MY", 0x06}, /* Malaysia */ |
| {"MX", 0x07}, /* Mexico */ |
| {"NE", 0x30}, /* New Zeland */ |
| }; |
| |
| /** EEPROM Region code mapping table */ |
| static region_code_mapping_t hw_region_code_mapping[] = { |
| {"00 ", 0x00}, /* World */ |
| {"US ", 0x10}, /* US FCC */ |
| {"CA ", 0x20}, /* IC Canada */ |
| {"KR ", 0x30}, /* Korea */ |
| {"CN ", 0x50}, /* China */ |
| {"ES ", 0x31}, /* Spain */ |
| {"FR ", 0x32}, /* France */ |
| {"JP ", 0x40}, /* Japan */ |
| {"JP ", 0x41}, /* Japan */ |
| }; |
| |
| /** Country code for ETSI */ |
| static t_u8 eu_country_code_table[][COUNTRY_CODE_LEN] = { |
| "AL", "AD", "AT", "AU", "BY", "BE", "BA", "BG", "HR", "CY", "CZ", "DK", |
| "EE", "FI", "FR", "MK", "DE", "GR", "HU", "IS", "IE", "IT", "KR", "LV", |
| "LI", "LT", "LU", "MT", "MD", "MC", "ME", "NL", "NO", "PL", "RO", "RU", |
| "SM", "RS", "SI", "SK", "ES", "SE", "CH", "TR", "UA", "UK", "GB", "NE" |
| }; |
| |
| /******************************************************** |
| 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 |
| |
| /******************************************************** |
| Local Functions |
| ********************************************************/ |
| /** |
| * @brief This function converts region string to region code |
| * |
| * @param country_code Region string |
| * |
| * @return Region code |
| */ |
| static t_bool |
| woal_is_country_code_supported(t_u8 *country_code) |
| { |
| t_u8 i; |
| ENTER(); |
| |
| for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) { |
| if (!memcmp(country_code, region_code_mapping[i].region, |
| COUNTRY_CODE_LEN - 1)) { |
| PRINTM(MIOCTL, |
| "found country code in region_code table\n"); |
| LEAVE(); |
| return MTRUE; |
| } |
| } |
| |
| LEAVE(); |
| return MFALSE; |
| } |
| |
| /** |
| * @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; |
| |
| ENTER(); |
| for (i = 0; i < ARRAY_SIZE(region_code_mapping); i++) { |
| if (!memcmp(region_string, region_code_mapping[i].region, |
| strlen(region_string))) { |
| LEAVE(); |
| return region_code_mapping[i].code; |
| } |
| } |
| |
| /* If still not found, look for code in EU country code table */ |
| for (i = 0; i < ARRAY_SIZE(eu_country_code_table); i++) { |
| if (!memcmp(region_string, eu_country_code_table[i], |
| COUNTRY_CODE_LEN - 1)) { |
| PRINTM(MIOCTL, "found region code=%d in EU table\n", |
| EU_REGION_CODE); |
| LEAVE(); |
| return EU_REGION_CODE; |
| } |
| } |
| |
| /* Default is US */ |
| LEAVE(); |
| return region_code_mapping[0].code; |
| } |
| |
| /** |
| * @brief This function converts region string to region code |
| * |
| * @param country_code Region string |
| * |
| * @return Region code |
| */ |
| t_bool |
| woal_is_etsi_country(t_u8 *country_code) |
| { |
| t_u8 i; |
| ENTER(); |
| |
| for (i = 0; i < ARRAY_SIZE(eu_country_code_table); i++) { |
| if (!memcmp(country_code, eu_country_code_table[i], |
| COUNTRY_CODE_LEN - 1)) { |
| PRINTM(MIOCTL, "found region code=%d in EU table\n", |
| EU_REGION_CODE); |
| LEAVE(); |
| return MTRUE; |
| } |
| } |
| |
| LEAVE(); |
| return MFALSE; |
| } |
| |
| /** |
| * @brief This function converts region string to region code |
| * |
| * @param region_code region code |
| * |
| * @return Region string or NULL |
| */ |
| char * |
| region_code_2_string(t_u8 region_code) |
| { |
| t_u8 i; |
| |
| ENTER(); |
| for (i = 0; i < ARRAY_SIZE(hw_region_code_mapping); i++) { |
| if (hw_region_code_mapping[i].code == region_code) { |
| LEAVE(); |
| return hw_region_code_mapping[i].region; |
| } |
| } |
| LEAVE(); |
| return NULL; |
| } |
| |
| t_u8 |
| woal_is_valid_alpha2(char *alpha2) |
| { |
| if (!alpha2 || strlen(alpha2) < 2) |
| return MFALSE; |
| if (isalpha(alpha2[0]) && isalpha(alpha2[1])) |
| return MTRUE; |
| return MFALSE; |
| } |
| |
| /** |
| * @brief Get second channel offset |
| * |
| * @param priv A pointer to moal_private structure |
| * @param chan channel num |
| * @return second channel offset |
| */ |
| t_u8 |
| woal_get_second_channel_offset(moal_private *priv, int chan) |
| { |
| t_u8 chan2Offset = SEC_CHAN_NONE; |
| mlan_bss_info bss_info; |
| |
| /* Special Case: 20Mhz-only Channel */ |
| woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info); |
| if (chan == 165) |
| return chan2Offset; |
| |
| switch (chan) { |
| case 36: |
| case 44: |
| case 52: |
| case 60: |
| case 100: |
| case 108: |
| case 116: |
| case 124: |
| case 132: |
| case 140: |
| case 149: |
| case 157: |
| chan2Offset = SEC_CHAN_ABOVE; |
| break; |
| case 40: |
| case 48: |
| case 56: |
| case 64: |
| case 104: |
| case 112: |
| case 120: |
| case 128: |
| case 136: |
| case 144: |
| case 153: |
| case 161: |
| chan2Offset = SEC_CHAN_BELOW; |
| break; |
| } |
| return chan2Offset; |
| } |
| |
| /** |
| * @brief Copy mc address to the mlist |
| * |
| * @param mlist A pointer to mlan_multicast_list structure |
| * @param mac mc address |
| * |
| * @return N/A |
| */ |
| static inline void |
| woal_copy_mc_addr(mlan_multicast_list *mlist, mlan_802_11_mac_addr mac) |
| { |
| t_u32 i = 0; |
| for (i = 0; i < mlist->num_multicast_addr; i++) { |
| if (!memcmp(&mlist->mac_list[i], mac, ETH_ALEN)) |
| return; |
| } |
| if (mlist->num_multicast_addr < MLAN_MAX_MULTICAST_LIST_SIZE) |
| moal_memcpy_ext(NULL, |
| &mlist->mac_list[mlist->num_multicast_addr], |
| mac, ETH_ALEN, sizeof(mlan_802_11_mac_addr)); |
| mlist->num_multicast_addr++; |
| return; |
| } |
| |
| /** |
| * @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) |
| { |
| #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) |
| struct dev_mc_list *mcptr = dev->mc_list; |
| int i = 0; |
| #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++) { |
| woal_copy_mc_addr(mlist, mcptr->dmi_addr); |
| mcptr = mcptr->next; |
| } |
| #else |
| netdev_for_each_mc_addr(mcptr, dev) |
| woal_copy_mc_addr(mlist, mcptr->addr); |
| #endif /* < 2.6.35 */ |
| LEAVE(); |
| return mlist->num_multicast_addr; |
| } |
| |
| /** |
| * @brief copy mc list from all the active interface |
| * |
| * @param handle A pointer to moal_handle |
| * @param mlist A pointer to multicast list |
| * |
| * @return total_mc_count |
| */ |
| static int |
| woal_copy_all_mc_list(moal_handle *handle, mlan_multicast_list *mlist) |
| { |
| int i; |
| moal_private *priv = NULL; |
| #ifdef STA_SUPPORT |
| int mc_count = 0; |
| #endif |
| ENTER(); |
| for (i = 0; i < handle->priv_num && (priv = handle->priv[i]); i++) { |
| #ifdef STA_SUPPORT |
| if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_STA) { |
| if (handle->priv[i]->media_connected == MTRUE) { |
| #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35) |
| mc_count = priv->netdev->mc_count; |
| #else |
| mc_count = netdev_mc_count(priv->netdev); |
| #endif |
| if (mc_count) |
| woal_copy_mcast_addr(mlist, |
| priv->netdev); |
| } |
| } |
| #endif |
| } |
| PRINTM(MIOCTL, "total mc_count=%d\n", mlist->num_multicast_addr); |
| LEAVE(); |
| return mlist->num_multicast_addr; |
| } |
| |
| /** |
| * @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; |
| wait->wait_timeout = MFALSE; |
| switch (wait_option) { |
| case MOAL_NO_WAIT: |
| break; |
| case MOAL_IOCTL_WAIT: |
| init_waitqueue_head(&wait->wait); |
| break; |
| case MOAL_IOCTL_WAIT_TIMEOUT: |
| init_waitqueue_head(&wait->wait); |
| wait->wait_timeout = MTRUE; |
| break; |
| } |
| 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 mlan_status |
| 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; |
| unsigned long flags; |
| |
| ENTER(); |
| |
| priv->phandle->ioctl_timeout = MFALSE; |
| |
| switch (wait_option) { |
| case MOAL_NO_WAIT: |
| break; |
| case MOAL_IOCTL_WAIT: |
| while (wait_event_interruptible_exclusive |
| (wait->wait, wait->condition) == -ERESTARTSYS && |
| wait->retry < MAX_RETRY_CNT) { |
| wait->retry++; |
| } |
| break; |
| case MOAL_IOCTL_WAIT_TIMEOUT: |
| wait_event_timeout(wait->wait, wait->condition, |
| MOAL_IOCTL_TIMEOUT); |
| break; |
| } |
| spin_lock_irqsave(&priv->phandle->driver_lock, flags); |
| if (wait->condition == MFALSE) { |
| if (wait_option == MOAL_IOCTL_WAIT_TIMEOUT) { |
| priv->phandle->ioctl_timeout = MTRUE; |
| PRINTM(MMSG, |
| "wlan: IOCTL timeout %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); |
| } else { |
| PRINTM(MMSG, |
| "wlan: IOCTL by signal %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); |
| } |
| req->reserved_1 = 0; |
| status = MLAN_STATUS_PENDING; |
| } else { |
| status = wait->status; |
| } |
| spin_unlock_irqrestore(&priv->phandle->driver_lock, flags); |
| |
| LEAVE(); |
| return status; |
| } |
| |
| /** |
| * @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 || |
| sub_command == MLAN_OID_BSS_CHANNEL |
| /* sub_command == MLAN_OID_BSS_ROLE */ ) |
| ret = MTRUE; |
| #ifdef UAP_SUPPORT |
| else if (sub_command == MLAN_OID_UAP_BSS_CONFIG) { |
| mlan_ds_bss *bss = (mlan_ds_bss *)req->pbuf; |
| if (bss->param.bss_config.channel) |
| ret = MTRUE; |
| else |
| ret = MFALSE; |
| } |
| #endif |
| break; |
| case MLAN_IOCTL_RADIO_CFG: |
| if (sub_command == MLAN_OID_BAND_CFG || |
| sub_command == MLAN_OID_REMAIN_CHAN_CFG) |
| ret = MTRUE; |
| break; |
| case MLAN_IOCTL_SNMP_MIB: |
| if (sub_command == MLAN_OID_SNMP_MIB_DOT11D) |
| ret = MTRUE; |
| #if defined(UAP_SUPPORT) |
| if (sub_command == MLAN_OID_SNMP_MIB_DOT11H) |
| ret = MTRUE; |
| #endif |
| break; |
| case MLAN_IOCTL_11D_CFG: |
| #ifdef STA_SUPPORT |
| if (sub_command == MLAN_OID_11D_CFG_ENABLE) |
| ret = MTRUE; |
| #endif |
| #ifdef UAP_SUPPORT |
| if (sub_command == MLAN_OID_11D_DOMAIN_INFO) |
| ret = MTRUE; |
| #endif |
| if (sub_command == MLAN_OID_11D_DOMAIN_INFO_EXT) |
| 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 = NULL; |
| mlan_status status; |
| unsigned long flags; |
| t_u32 sub_command = 0; |
| |
| ENTER(); |
| |
| if (!priv || !priv->phandle || !priv->phandle->pmlan_adapter ||!req) { |
| PRINTM(MINFO, |
| "priv or priv->phandle or priv->phandle->pmlan_adapter or req is null\n"); |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| |
| sub_command = *(t_u32 *)req->pbuf; |
| |
| if (sub_command != MLAN_OID_GET_DEBUG_INFO && |
| sub_command != MLAN_OID_MISC_WARM_RESET) { |
| if (priv->phandle->surprise_removed == MTRUE || |
| priv->phandle->driver_status) { |
| PRINTM(MCMND, |
| "IOCTL is not allowed while the device is not present or hang\n"); |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| if (priv->phandle->is_suspended == MTRUE) { |
| PRINTM(MCMND, "IOCTL is not allowed while suspended\n"); |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| #ifdef MFG_CMD_SUPPORT |
| if (mfg_mode && sub_command != MLAN_OID_MISC_HOST_CMD) { |
| PRINTM(MCMND, "Only HOST_CMD allowed in MFG mode\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) { |
| /* CAC checking period left to complete jiffies */ |
| long cac_left_jiffies; |
| |
| /* 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 = |
| priv->phandle->cac_timer_jiffies - |
| (jiffies - priv->phandle->meas_start_jiffies); |
| if (priv->phandle->cac_period_jiffies) { |
| cac_left_jiffies = |
| priv->phandle->cac_period_jiffies - |
| (jiffies - priv->phandle->meas_start_jiffies); |
| } |
| if (priv->phandle->cac_restart) |
| cac_left_jiffies = DEF_CAC_DWELL_TIME * HZ / 1000; |
| 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; |
| #ifdef UAP_SUPPORT |
| #if defined(STA_CFG80211) || defined(UAP_CFG80211) |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) |
| if (priv->uap_host_based && |
| moal_extflg_isset(priv->phandle, EXT_DFS_OFFLOAD)) |
| woal_cfg80211_dfs_vendor_event(priv, |
| event_dfs_cac_aborted, |
| &priv->chan); |
| #endif |
| #endif |
| #endif |
| |
| 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; |
| moal_memcpy_ext(priv->phandle, |
| &priv->phandle-> |
| delay_ssid_bssid, |
| &bss->param.ssid_bssid, |
| sizeof(mlan_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); |
| } |
| } |
| #ifdef UAP_CFG80211 |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 12, 0) |
| else if (priv->phandle->is_cac_timer_set && |
| (req->action == MLAN_ACT_SET || req->action == 0)) { |
| if (woal_cac_period_block_cmd(priv, req)) { |
| PRINTM(MMSG, |
| "CAC check is on going... Blocking Command\n"); |
| status = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| } |
| #endif |
| #endif |
| 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 */ |
| atomic_inc(&priv->phandle->ioctl_pending); |
| spin_lock_irqsave(&priv->phandle->ioctl_lock, flags); |
| status = mlan_ioctl(priv->phandle->pmlan_adapter, req); |
| spin_unlock_irqrestore(&priv->phandle->ioctl_lock, flags); |
| switch (status) { |
| case MLAN_STATUS_PENDING: |
| if (wait_option == MOAL_NO_WAIT) |
| PRINTM(MIOCTL, "IOCTL MOAL_NO_WAIT: %p\n", req); |
| else |
| 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); |
| /* Status pending, wake up main process */ |
| queue_work(priv->phandle->workqueue, &priv->phandle->main_work); |
| |
| /* Wait for completion */ |
| if (wait_option) |
| status = woal_wait_ioctl_complete(priv, req, |
| wait_option); |
| break; |
| case MLAN_STATUS_SUCCESS: |
| case MLAN_STATUS_FAILURE: |
| case MLAN_STATUS_RESOURCE: |
| if (req) |
| 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); |
| atomic_dec(&priv->phandle->ioctl_pending); |
| break; |
| default: |
| atomic_dec(&priv->phandle->ioctl_pending); |
| break; |
| } |
| |
| done: |
| LEAVE(); |
| return status; |
| } |
| |
| /** |
| * @brief Send set MAC address request 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 |
| */ |
| mlan_status |
| woal_request_set_mac_address(moal_private *priv, t_u8 wait_option) |
| { |
| 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; |
| moal_memcpy_ext(priv->phandle, &bss->param.mac_addr, priv->current_addr, |
| sizeof(mlan_802_11_mac_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, wait_option); |
| if (status == MLAN_STATUS_FAILURE) { |
| PRINTM(MERROR, |
| "set mac address failed! status=%d, error_code=0x%x\n", |
| status, req->status_code); |
| } else { |
| moal_memcpy_ext(priv->phandle, priv->netdev->dev_addr, |
| priv->current_addr, ETH_ALEN, ETH_ALEN); |
| HEXDUMP("priv->MacAddr:", priv->current_addr, ETH_ALEN); |
| } |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| 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; |
| int mc_count = 0; |
| |
| 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", |
| __func__); |
| 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) { |
| bss->param.multicast_list.mode = MLAN_ALL_MULTI_MODE; |
| } else { |
| bss->param.multicast_list.mode = MLAN_MULTICAST_MODE; |
| mc_count = woal_copy_all_mc_list(priv->phandle, |
| &bss->param.multicast_list); |
| if (mc_count > MLAN_MAX_MULTICAST_LIST_SIZE) |
| bss->param.multicast_list.mode = MLAN_ALL_MULTI_MODE; |
| } |
| PRINTM(MCMND, "%s set multicast_list\n", dev->name); |
| /* Send IOCTL request to MLAN */ |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_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 |
| * @param reason code reason code 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, |
| t_u16 reason_code) |
| { |
| 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) |
| moal_memcpy_ext(priv->phandle, |
| &bss->param.deauth_param.mac_addr, mac, |
| sizeof(mlan_802_11_mac_addr), |
| sizeof(bss->param.deauth_param.mac_addr)); |
| bss->param.deauth_param.reason_code = reason_code; |
| 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 (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| #ifdef REASSOCIATION |
| priv->reassoc_required = MFALSE; |
| #endif /* REASSOCIATION */ |
| LEAVE(); |
| return status; |
| } |
| |
| #if defined(UAP_SUPPORT) |
| /** |
| * @brief Get non-global oper class |
| * |
| * @param priv Pointer to moal_private structure |
| * @param bw bandwidth |
| * @param channel channel |
| * @param oper_class pointer to oper_class |
| |
| * @return non-global operclass |
| */ |
| int |
| woal_priv_get_nonglobal_operclass_by_bw_channel(moal_private *priv, |
| t_u8 bandwidth, |
| t_u8 channel, t_u8 *oper_class) |
| { |
| int ret = 0; |
| mlan_ioctl_req *ioctl_req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| 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_OPER_CLASS; |
| ioctl_req->req_id = MLAN_IOCTL_MISC_CFG; |
| ioctl_req->action = MLAN_ACT_GET; |
| misc->param.bw_chan_oper.bandwidth = bandwidth; |
| misc->param.bw_chan_oper.channel = channel; |
| |
| status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| *oper_class = misc->param.bw_chan_oper.oper_class; |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(ioctl_req); |
| |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| |
| /** |
| * @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 When we are roaming */ |
| woal_stop_queue(priv->netdev); |
| if (priv->media_connected == MFALSE) { |
| if (netif_carrier_ok(priv->netdev)) |
| netif_carrier_off(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) |
| moal_memcpy_ext(priv->phandle, &bss->param.ssid_bssid, |
| ssid_bssid, sizeof(mlan_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); |
| if (ssid_bssid) |
| moal_memcpy_ext(priv->phandle, ssid_bssid, |
| &bss->param.ssid_bssid, sizeof(mlan_ssid_bssid), |
| sizeof(mlan_ssid_bssid)); |
| #ifdef STA_CFG80211 |
| #ifdef STA_SUPPORT |
| priv->assoc_status = req->status_code; |
| #endif |
| #endif |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| 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) |
| { |
| 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) { |
| PRINTM(MERROR, |
| "Fail to allocate the buffer for get bss_info\n"); |
| status = MLAN_STATUS_FAILURE; |
| 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) |
| moal_memcpy_ext(priv->phandle, bss_info, |
| &info->param.bss_info, |
| sizeof(mlan_bss_info), |
| sizeof(mlan_bss_info)); |
| } |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return status; |
| } |
| |
| /** |
| * @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 |
| * @param wait_option wait option |
| * |
| * @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, t_u8 wait_option) |
| { |
| 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) |
| moal_memcpy_ext(priv->phandle, |
| misc->param.gen_ie.ie_data, ie, *ie_len, |
| MAX_IE_SIZE); |
| } |
| |
| ret = woal_request_ioctl(priv, req, wait_option); |
| if (ret != MLAN_STATUS_SUCCESS) |
| goto done; |
| |
| if (action == MLAN_ACT_GET) { |
| *ie_len = misc->param.gen_ie.len; |
| if (*ie_len) |
| moal_memcpy_ext(priv->phandle, ie, |
| misc->param.gen_ie.ie_data, *ie_len, |
| *ie_len); |
| } |
| |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| #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(priv->phandle->params.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; |
| } |
| #endif |
| |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Performs pre-warm-reset |
| * |
| * @param priv A pointer to moal_private structure |
| * |
| * @return 0 if successful else negative value |
| */ |
| int |
| woal_pre_warmreset(moal_private *priv) |
| { |
| moal_handle *handle = priv->phandle; |
| int ret = 0; |
| int intf_num; |
| #ifdef 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 */ |
| |
| ENTER(); |
| #ifdef USB |
| #ifdef CONFIG_USB_SUSPEND |
| if (IS_USB(handle->card_type) && handle->is_suspended && |
| woal_exit_usb_suspend(handle)) { |
| PRINTM(MERROR, "Failed to resume the suspended device\n"); |
| LEAVE(); |
| return -EFAULT; |
| } |
| #endif /* CONFIG_USB_SUSPEND */ |
| #endif |
| 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); |
| #ifdef 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) && |
| (GET_BSS_ROLE(handle->priv[intf_num]) == |
| MLAN_BSS_ROLE_UAP)) { |
| 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 */ |
| } |
| woal_shutdown_fw(priv, MOAL_IOCTL_WAIT); |
| #ifdef WIFI_DIRECT_SUPPORT |
| #if defined(STA_SUPPORT) && defined(UAP_SUPPORT) |
| #if defined(STA_WEXT) || defined(UAP_WEXT) |
| done: |
| #endif /* STA_WEXT || UAP_WEXT */ |
| #endif /* STA_SUPPORT && UAP_SUPPORT */ |
| #endif /* WIFI_DIRECT_SUPPORT */ |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief warm reset |
| * |
| * @param priv A pointer to moal_private structure |
| * |
| * @return 0 success, otherwise failure |
| */ |
| int |
| woal_warmreset(moal_private *priv) |
| { |
| moal_handle *handle = priv->phandle; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| int ret = 0; |
| int intf_num; |
| |
| /* 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; |
| misc->param.fw_reload = MTRUE; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| req->action = MLAN_ACT_SET; |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| PRINTM(MERROR, "warm reset failure!\n"); |
| ret = -EFAULT; |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| goto done; |
| } |
| kfree(req); |
| } |
| #ifdef USB |
| if (IS_USB(handle->card_type) && handle->params.usb_aggr == 1) { |
| /* Enable USB aggregation in FW */ |
| if (woal_usb_aggr_init(handle)) { |
| PRINTM(MERROR, "usb aggr init fail\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| } |
| #endif |
| |
| if (moal_extflg_isset(handle, EXT_AGGR_CTRL)) { |
| /* Enable aggregation in FW */ |
| if (woal_init_aggr_ctrl(handle, MOAL_IOCTL_WAIT)) { |
| PRINTM(MERROR, "Fail to init aggr ctrl\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| } |
| |
| /* 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 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(priv->phandle->params.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 |
| |
| done: |
| if (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(priv->phandle->params.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 |
| |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| 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) |
| moal_memcpy_ext(priv->phandle, &pcfg->param.power_cfg, |
| power_cfg, sizeof(mlan_power_cfg_t), |
| sizeof(mlan_power_cfg_t)); |
| |
| ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (ret != MLAN_STATUS_SUCCESS) |
| goto done; |
| |
| if (ret == MLAN_STATUS_SUCCESS && power_cfg) |
| moal_memcpy_ext(priv->phandle, power_cfg, |
| &pcfg->param.power_cfg, |
| sizeof(mlan_power_cfg_t), |
| sizeof(mlan_power_cfg_t)); |
| |
| done: |
| if (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 |
| * @param wait_option wait option |
| * |
| * @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, t_u8 wait_option) |
| { |
| 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 & MW_POWER_TYPE) == MW_POWER_TIMEOUT) { |
| PRINTM(MERROR, |
| "Setting power timeout is not supported\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } else if ((power_type & MW_POWER_TYPE) == |
| MW_POWER_PERIOD) { |
| PRINTM(MERROR, |
| "Setting power period is not supported\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| pm_cfg->param.ps_mode = 1; |
| } |
| } |
| |
| ret = woal_request_ioctl(priv, req, wait_option); |
| if (ret != MLAN_STATUS_SUCCESS) |
| 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(priv->phandle->params.cfg80211_wext) && |
| priv->wdev && (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 (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set Country 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 |
| */ |
| static int |
| woal_set_countrycode(moal_private *priv, char *country) |
| { |
| int ret = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *pcfg_misc = NULL; |
| mlan_ds_misc_country_code *country_code = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| /* 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; |
| |
| memset(country_code->country_code, 0, COUNTRY_CODE_LEN); |
| moal_memcpy_ext(priv->phandle, country_code->country_code, country, |
| COUNTRY_CODE_LEN - 1, COUNTRY_CODE_LEN - 1); |
| req->action = MLAN_ACT_SET; |
| |
| /* Send IOCTL request to MLAN */ |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| 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(); |
| if (woal_is_country_code_supported(region)) |
| return woal_set_countrycode(priv, region); |
| |
| 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 (ret != MLAN_STATUS_PENDING) |
| 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)) |
| moal_memcpy_ext(priv->phandle, &rate->param.rate_cfg, datarate, |
| sizeof(mlan_rate_cfg_t), |
| sizeof(mlan_rate_cfg_t)); |
| |
| ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (ret == MLAN_STATUS_SUCCESS && datarate && action == MLAN_ACT_GET) |
| moal_memcpy_ext(priv->phandle, datarate, &rate->param.rate_cfg, |
| sizeof(mlan_rate_cfg_t), |
| sizeof(mlan_rate_cfg_t)); |
| |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get assoc_resp buffer |
| * |
| * @param priv A pointer to moal_private structure |
| * @param assoc_rsp A pointer to mlan_ds_misc_assoc_rsp structure |
| * @param wait_option wait option |
| * |
| * @return MLAN_STATUS_SUCCESS -- success, otherwise fail |
| */ |
| mlan_status |
| woal_get_assoc_rsp(moal_private *priv, |
| mlan_ds_misc_assoc_rsp *assoc_rsp, t_u8 wait_option) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| 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) { |
| PRINTM(MERROR, "Fail to allocate buffer for get assoc resp\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| misc = (pmlan_ds_misc_cfg)req->pbuf; |
| misc->sub_command = MLAN_OID_MISC_ASSOC_RSP; |
| req->action = MLAN_ACT_GET; |
| |
| ret = woal_request_ioctl(priv, req, wait_option); |
| if (ret == MLAN_STATUS_SUCCESS && assoc_rsp) |
| moal_memcpy_ext(priv->phandle, assoc_rsp, |
| &misc->param.assoc_resp, |
| sizeof(mlan_ds_misc_assoc_rsp), |
| sizeof(mlan_ds_misc_assoc_rsp)); |
| |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| 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_get_info)); |
| 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; |
| priv->phandle->fw_hotfix_version = |
| info->param.fw_info.hotfix_version; |
| priv->phandle->fw_ecsa_enable = info->param.fw_info.ecsa_enable; |
| priv->phandle->fw_getlog_enable = |
| info->param.fw_info.getlog_enable; |
| if (priv->current_addr[0] == 0xff) |
| moal_memcpy_ext(priv->phandle, priv->current_addr, |
| &info->param.fw_info.mac_addr, |
| sizeof(mlan_802_11_mac_addr), ETH_ALEN); |
| moal_memcpy_ext(priv->phandle, priv->netdev->dev_addr, |
| priv->current_addr, ETH_ALEN, ETH_ALEN); |
| if (fw_info) |
| moal_memcpy_ext(priv->phandle, fw_info, |
| &info->param.fw_info, |
| sizeof(mlan_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 (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return status; |
| } |
| |
| /** |
| * @brief Get current channel of active interface |
| * |
| * @param priv A pointer to moal_private |
| * @param channel A pointer to chan_band_info structure |
| * |
| * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE |
| */ |
| mlan_status |
| woal_get_active_intf_channel(moal_private *priv, chan_band_info * channel) |
| { |
| moal_handle *handle = priv->phandle; |
| int i; |
| 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) |
| return woal_get_sta_channel(handle->priv[i], |
| MOAL_IOCTL_WAIT, |
| channel); |
| } |
| #endif |
| #ifdef UAP_SUPPORT |
| if (GET_BSS_ROLE(handle->priv[i]) == MLAN_BSS_ROLE_UAP) { |
| if (handle->priv[i]->bss_started == MTRUE) |
| return woal_set_get_ap_channel(handle->priv[i], |
| MLAN_ACT_GET, |
| MOAL_IOCTL_WAIT, |
| channel); |
| } |
| #endif |
| } |
| return MLAN_STATUS_FAILURE; |
| } |
| |
| #ifdef STA_SUPPORT |
| /** |
| * @brief Send get ext cap info request to MLAN |
| * |
| * @param priv A pointer to moal_private structure |
| * @param buf data buffer |
| * @param len data buffer length |
| * |
| * @return number of bytes of extended capability -- success, |
| * otherwise error |
| */ |
| int |
| woal_request_extcap(moal_private *priv, t_u8 *buf, t_u8 len) |
| { |
| int ret = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *cfg = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| if (buf == NULL || len <= 0 || len < sizeof(ExtCap_t)) { |
| ret = -EINVAL; |
| goto out; |
| } |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto out; |
| } |
| cfg = (mlan_ds_misc_cfg *)req->pbuf; |
| cfg->sub_command = MLAN_OID_MISC_EXT_CAP_CFG; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| req->action = MLAN_ACT_GET; |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto out; |
| } |
| memset(buf, 0, len); |
| moal_memcpy_ext(priv->phandle, buf, &cfg->param.ext_cap, |
| sizeof(ExtCap_t), len); |
| ret = sizeof(ExtCap_t); |
| out: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| |
| /** |
| * @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) |
| { |
| 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(t_u32) + |
| sizeof(mlan_debug_info)); |
| if (req == NULL) { |
| status = MLAN_STATUS_FAILURE; |
| 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) { |
| moal_memcpy_ext(priv->phandle, debug_info, |
| &info->param.debug_info, |
| sizeof(mlan_debug_info), |
| sizeof(mlan_debug_info)); |
| } |
| } |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return status; |
| } |
| |
| #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; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| 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 > MRVDRV_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; |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| 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 (status != MLAN_STATUS_PENDING) |
| 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; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| 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) > MRVDRV_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; |
| |
| status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| 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 (status != MLAN_STATUS_PENDING) |
| 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 *pcustom_ie = NULL; |
| int ret = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| gfp_t flag; |
| |
| ENTER(); |
| |
| /* Sanity check */ |
| if (req->ifr_data == NULL) { |
| PRINTM(MERROR, "woal_custom_ie_ioctl() corrupt data\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| flag = (in_atomic() || irqs_disabled())? GFP_ATOMIC : GFP_KERNEL; |
| pcustom_ie = kzalloc(sizeof(mlan_ds_misc_custom_ie), flag); |
| if (!pcustom_ie) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| if (copy_from_user(pcustom_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 ((pcustom_ie->len == 0) || |
| (pcustom_ie->len == sizeof(pcustom_ie->ie_data_list[0].ie_index))) |
| ioctl_req->action = MLAN_ACT_GET; |
| else |
| ioctl_req->action = MLAN_ACT_SET; |
| |
| moal_memcpy_ext(priv->phandle, &misc->param.cust_ie, pcustom_ie, |
| sizeof(mlan_ds_misc_custom_ie), |
| sizeof(mlan_ds_misc_custom_ie)); |
| |
| status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| 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 (status != MLAN_STATUS_PENDING) |
| kfree(ioctl_req); |
| kfree(pcustom_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(); |
| |
| if (!priv || !priv->phandle) { |
| PRINTM(MERROR, "priv or handle is NULL\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| /* 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 |
| #define MV_ETH_FRAME_LEN 1514 |
| if (packet_len > MV_ETH_FRAME_LEN) { |
| PRINTM(MERROR, "Invalid packet length %d\n", packet_len); |
| ret = -EFAULT; |
| goto done; |
| } |
| pmbuf = woal_alloc_mlan_buffer(priv->phandle, |
| (int)(MLAN_MIN_DATA_HEADER_LEN + |
| (int)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 priv A pointer to moal_private structure |
| * @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; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| 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; |
| |
| 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; |
| moal_memcpy_ext(priv->phandle, pcust_bcn_ie->ie_buffer, ie, ie_len, |
| MAX_IE_SIZE); |
| |
| status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) |
| ret = -EFAULT; |
| |
| if (status != MLAN_STATUS_PENDING) |
| kfree(ioctl_req); |
| LEAVE(); |
| return ret; |
| } |
| #endif /* defined(HOST_TXRX_MGMT_FRAME) && defined(UAP_WEXT) */ |
| |
| /** |
| * @brief TDLS configuration ioctl handler |
| * |
| * @param dev A pointer to net_device structure |
| * @param req A pointer to ifreq structure |
| * @return 0 --success, otherwise fail |
| */ |
| int |
| woal_tdls_config_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_tdls_config *tdls_data = NULL; |
| int ret = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| gfp_t flag; |
| |
| ENTER(); |
| |
| /* Sanity check */ |
| if (req->ifr_data == NULL) { |
| PRINTM(MERROR, "woal_tdls_config_ioctl() corrupt data\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| flag = (in_atomic() || irqs_disabled())? GFP_ATOMIC : GFP_KERNEL; |
| tdls_data = kzalloc(sizeof(mlan_ds_misc_tdls_config), flag); |
| if (!tdls_data) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| if (copy_from_user(tdls_data, req->ifr_data, |
| sizeof(mlan_ds_misc_tdls_config))) { |
| 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_TDLS_CONFIG; |
| ioctl_req->req_id = MLAN_IOCTL_MISC_CFG; |
| if (tdls_data->tdls_action == WLAN_TDLS_DISCOVERY_REQ || |
| tdls_data->tdls_action == WLAN_TDLS_LINK_STATUS) |
| ioctl_req->action = MLAN_ACT_GET; |
| else |
| ioctl_req->action = MLAN_ACT_SET; |
| |
| moal_memcpy_ext(priv->phandle, &misc->param.tdls_config, tdls_data, |
| sizeof(mlan_ds_misc_tdls_config), |
| sizeof(mlan_ds_misc_tdls_config)); |
| |
| status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| if (tdls_data->tdls_action == WLAN_TDLS_DISCOVERY_REQ |
| || tdls_data->tdls_action == WLAN_TDLS_LINK_STATUS) { |
| if (copy_to_user(req->ifr_data, &misc->param.tdls_config, |
| sizeof(mlan_ds_misc_tdls_config))) { |
| PRINTM(MERROR, "Copy to user failed!\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(ioctl_req); |
| kfree(tdls_data); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @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(STA_SUPPORT) && defined(UAP_SUPPORT) |
| /** |
| * @brief Swithces BSS role of interface |
| * |
| * @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 |
| */ |
| 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; |
| struct net_device *dev = priv->netdev; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| 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; |
| if (action == MLAN_ACT_SET) { |
| if (priv->bss_role == *bss_role) { |
| PRINTM(MWARN, "BSS is in desired role already\n"); |
| goto done; |
| } else { |
| bss->param.bss_role = *bss_role; |
| } |
| } |
| status = woal_request_ioctl(priv, req, wait_option); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| if (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 (*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(priv->phandle->params.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 /* 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(priv->phandle->params.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 /* STA_WEXT */ |
| } |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| #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; |
| 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) |
| #ifdef WIFI_DIRECT_SUPPORT |
| || (priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) |
| #endif |
| ) { |
| PRINTM(MWARN, "Invalid BSS role\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (bss_role == (int)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 { |
| #if defined(STA_CFG80211) || defined(UAP_CFG80211) |
| if (IS_STA_OR_UAP_CFG80211(priv->phandle->params.cfg80211_wext)) |
| woal_clear_all_mgmt_ies(priv, MOAL_IOCTL_WAIT); |
| #endif |
| /* 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 */ |
| |
| /** |
| * @brief Enable IPv6 Router Advertisement offload |
| * |
| * @param handle A pointer to moal_handle structure |
| * @param enable enable or disable |
| * |
| * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise |
| * fail |
| */ |
| static mlan_status |
| woal_set_ipv6_ra_offload(moal_handle *handle, t_u8 enable) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| moal_private *priv = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_ipv6_ra_offload *ipv6_ra; |
| int i = 0; |
| |
| ENTER(); |
| |
| for (i = 0; i < handle->priv_num && (priv = handle->priv[i]); i++) { |
| if (priv->ipv6_addr_configured) |
| break; |
| } |
| |
| if (!priv || !priv->ipv6_addr_configured) { |
| PRINTM(MIOCTL, "No IPv6 address configured\n"); |
| goto done; |
| } |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| PRINTM(MIOCTL, "IOCTL req allocated failed!\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| misc = (mlan_ds_misc_cfg *)req->pbuf; |
| misc->sub_command = MLAN_OID_MISC_IPV6_RA_OFFLOAD; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| req->action = MLAN_ACT_SET; |
| ipv6_ra = &misc->param.ipv6_ra_offload; |
| ipv6_ra->enable = enable; |
| moal_memcpy_ext(priv->phandle, ipv6_ra->ipv6_addr, priv->ipv6_addr, 16, |
| sizeof(ipv6_ra->ipv6_addr)); |
| ret = woal_request_ioctl(woal_get_priv(handle, MLAN_BSS_ROLE_STA), req, |
| MOAL_NO_WAIT); |
| if (ret != MLAN_STATUS_SUCCESS && ret != MLAN_STATUS_PENDING) |
| PRINTM(MIOCTL, "Set IPv6 RA offload failed\n"); |
| |
| done: |
| if (ret != MLAN_STATUS_PENDING && req != NULL) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Enable IPv6 Neighbor Solicitation offload |
| * |
| * @param handle A pointer to moal_handle structure |
| * @param enable enable or disable mef entry |
| * |
| * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise |
| * fail |
| */ |
| static mlan_status |
| woal_set_ipv6_ns_offload(moal_handle *handle) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_misc_cfg *misc = NULL; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_mef_flt_cfg *mef_cfg = NULL; |
| mef_entry_t *entry = NULL; |
| mef_filter_t *filter = NULL; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| PRINTM(MIOCTL, "IOCTL req allocated failed!\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| misc = (mlan_ds_misc_cfg *)req->pbuf; |
| misc->sub_command = MLAN_OID_MISC_MEF_FLT_CFG; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| req->action = MLAN_ACT_SET; |
| |
| mef_cfg = (mlan_ds_misc_mef_flt_cfg *)(&misc->param.mef_flt_cfg); |
| mef_cfg->mef_act_type = MEF_ACT_IPV6_NS; |
| mef_cfg->criteria = (MBIT(1) | MBIT(3)); |
| |
| entry = (mef_entry_t *)&mef_cfg->mef_entry; |
| entry->mode = MBIT(0); |
| entry->action = 0x40; |
| |
| filter = (mef_filter_t *)entry->filter_item; |
| filter->fill_flag = (FILLING_TYPE | FILLING_REPEAT | FILLING_OFFSET | |
| FILLING_BYTE_SEQ); |
| filter->type = TYPE_BYTE_EQ; |
| filter->repeat = 1; |
| filter->offset = 20; |
| filter->num_byte_seq = 2; |
| moal_memcpy_ext(handle, filter->byte_seq, "\x86\xdd", 2, |
| sizeof(filter->byte_seq)); |
| entry->rpn[1] = RPN_TYPE_AND; |
| |
| filter++; |
| filter->fill_flag = (FILLING_TYPE | FILLING_REPEAT | FILLING_OFFSET | |
| FILLING_BYTE_SEQ); |
| filter->type = TYPE_BYTE_EQ; |
| filter->repeat = 1; |
| filter->offset = 62; |
| filter->num_byte_seq = 1; |
| moal_memcpy_ext(handle, filter->byte_seq, "\x87", 1, |
| sizeof(filter->byte_seq)); |
| |
| entry->filter_num = 2; |
| |
| ret = woal_request_ioctl(woal_get_priv(handle, MLAN_BSS_ROLE_ANY), req, |
| MOAL_NO_WAIT); |
| if (ret != MLAN_STATUS_SUCCESS && ret != MLAN_STATUS_PENDING) |
| PRINTM(MIOCTL, "Set ipv6 ns offload failed! ret=%d\n", ret); |
| |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set auto arp resp |
| * |
| * @param handle A pointer to moal_handle structure |
| * @param enable enable/disable |
| * |
| * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, |
| * otherwise fail |
| */ |
| static mlan_status |
| woal_set_auto_arp(moal_handle *handle, t_u8 enable) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| int i = 0; |
| moal_private *priv = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_ipaddr_cfg ipaddr_cfg; |
| |
| ENTER(); |
| |
| memset(&ipaddr_cfg, 0, sizeof(ipaddr_cfg)); |
| for (i = 0; i < handle->priv_num && (priv = handle->priv[i]); i++) { |
| if (priv && priv->ip_addr_type != IPADDR_TYPE_NONE) { |
| moal_memcpy_ext(handle, |
| ipaddr_cfg.ip_addr[ipaddr_cfg. |
| ip_addr_num], |
| priv->ip_addr, IPADDR_LEN, IPADDR_LEN); |
| ipaddr_cfg.ip_addr_num++; |
| } |
| } |
| if (ipaddr_cfg.ip_addr_num == 0) { |
| PRINTM(MIOCTL, "No IP addr configured.\n"); |
| goto done; |
| } |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| PRINTM(MIOCTL, "IOCTL req allocated failed!\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| misc = (mlan_ds_misc_cfg *)req->pbuf; |
| misc->sub_command = MLAN_OID_MISC_IP_ADDR; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| req->action = MLAN_ACT_SET; |
| moal_memcpy_ext(handle, &misc->param.ipaddr_cfg, &ipaddr_cfg, |
| sizeof(ipaddr_cfg), sizeof(misc->param.ipaddr_cfg)); |
| if (enable) { |
| misc->param.ipaddr_cfg.op_code = MLAN_IPADDR_OP_ARP_FILTER | |
| MLAN_IPADDR_OP_AUTO_ARP_RESP; |
| misc->param.ipaddr_cfg.ip_addr_type = IPADDR_TYPE_IPV4; |
| } else { |
| /** remove ip */ |
| misc->param.ipaddr_cfg.op_code = MLAN_IPADDR_OP_IP_REMOVE; |
| } |
| ret = woal_request_ioctl(woal_get_priv(handle, MLAN_BSS_ROLE_ANY), req, |
| MOAL_NO_WAIT); |
| if (ret != MLAN_STATUS_SUCCESS && ret != MLAN_STATUS_PENDING) |
| PRINTM(MIOCTL, "Set auto arp IOCTL failed!\n"); |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set auto arp resp with enhancement method |
| * |
| * @param handle A pointer to moal_handle structure |
| * @param enable enable/disable |
| * |
| * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, |
| * otherwise fail |
| */ |
| mlan_status |
| woal_set_auto_arp_ext(moal_handle *handle, t_u8 enable) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| int i = 0, ip_addr_num = 0; |
| moal_private *priv = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_mef_flt_cfg *mef_cfg = NULL; |
| mef_entry_t *entry = NULL; |
| mef_filter_t *filter = NULL; |
| t_u8 ip_addr[MAX_IPADDR][IPADDR_LEN]; |
| |
| ENTER(); |
| |
| memset(&mef_cfg, 0, sizeof(mef_cfg)); |
| for (i = 0; i < handle->priv_num && (priv = handle->priv[i]); i++) { |
| if (priv && priv->ip_addr_type != IPADDR_TYPE_NONE) { |
| moal_memcpy_ext(handle, ip_addr[ip_addr_num], |
| priv->ip_addr, IPADDR_LEN, IPADDR_LEN); |
| ip_addr_num++; |
| } |
| } |
| if (ip_addr_num == 0) { |
| PRINTM(MIOCTL, "No IP addr configured.\n"); |
| goto done; |
| } |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| PRINTM(MIOCTL, "IOCTL req allocated failed!\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| misc = (mlan_ds_misc_cfg *)req->pbuf; |
| misc->sub_command = MLAN_OID_MISC_MEF_FLT_CFG; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| req->action = MLAN_ACT_SET; |
| |
| mef_cfg = (mlan_ds_misc_mef_flt_cfg *)(&(misc->param.mef_flt_cfg)); |
| mef_cfg->mef_act_type = MEF_ACT_AUTOARP; |
| mef_cfg->criteria = (MBIT(0) | MBIT(1)); |
| |
| entry = (mef_entry_t *)&mef_cfg->mef_entry; |
| entry->mode = MBIT(0); |
| entry->action = 0x10; |
| |
| filter = (mef_filter_t *)(entry->filter_item); |
| filter->fill_flag = (FILLING_TYPE | FILLING_REPEAT | FILLING_OFFSET | |
| FILLING_BYTE_SEQ); |
| filter->type = TYPE_BYTE_EQ; |
| filter->repeat = 1; |
| filter->offset = 20; |
| filter->num_byte_seq = 2; |
| moal_memcpy_ext(handle, filter->byte_seq, "\x08\x06", 2, |
| sizeof(filter->byte_seq)); |
| entry->rpn[1] = RPN_TYPE_AND; |
| |
| for (i = 0; i < ip_addr_num; i++) { |
| filter++; |
| filter->fill_flag = (FILLING_TYPE | FILLING_REPEAT | |
| FILLING_OFFSET | FILLING_BYTE_SEQ); |
| filter->type = TYPE_BYTE_EQ; |
| filter->repeat = 1; |
| filter->offset = 46; |
| filter->num_byte_seq = 4; |
| moal_memcpy_ext(handle, filter->byte_seq, &ip_addr[i], |
| sizeof(t_u32), sizeof(filter->byte_seq)); |
| if (i > 1) |
| entry->rpn[i] = RPN_TYPE_OR; |
| } |
| entry->filter_num = ip_addr_num + 1; |
| |
| if (enable) |
| mef_cfg->op_code = MLAN_IPADDR_OP_ARP_FILTER | |
| MLAN_IPADDR_OP_AUTO_ARP_RESP; |
| else |
| /** remove ip */ |
| mef_cfg->op_code = MLAN_IPADDR_OP_IP_REMOVE; |
| ret = woal_request_ioctl(woal_get_priv(handle, MLAN_BSS_ROLE_ANY), req, |
| MOAL_NO_WAIT); |
| if (ret != MLAN_STATUS_SUCCESS && ret != MLAN_STATUS_PENDING) |
| PRINTM(MIOCTL, "Set auto arp IOCTL failed!\n"); |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @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 |
| */ |
| 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 (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @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) |
| moal_memcpy_ext(priv->phandle, &pmcfg->param.hs_cfg, hscfg, |
| sizeof(mlan_ds_hs_cfg), 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) { |
| moal_memcpy_ext(priv->phandle, hscfg, |
| &pmcfg->param.hs_cfg, |
| sizeof(mlan_ds_hs_cfg), |
| sizeof(mlan_ds_hs_cfg)); |
| } |
| } |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get wakeup reason |
| * |
| * @param priv A pointer to moal_private structure |
| * @param wakeup_reason A pointer to mlan_ds_hs_wakeup_reason structure |
| * |
| * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, |
| * otherwise fail |
| */ |
| mlan_status |
| woal_get_wakeup_reason(moal_private *priv, |
| mlan_ds_hs_wakeup_reason *wakeup_reason) |
| { |
| 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_HS_WAKEUP_REASON; |
| req->req_id = MLAN_IOCTL_PM_CFG; |
| req->action = MLAN_ACT_GET; |
| |
| /* Send IOCTL request to MLAN */ |
| ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT_TIMEOUT); |
| if (ret == MLAN_STATUS_SUCCESS) { |
| wakeup_reason->hs_wakeup_reason = |
| pmcfg->param.wakeup_reason.hs_wakeup_reason; |
| } |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set or Get wowlan config |
| * |
| * @param priv A pointer to moal_private structure |
| * @param action Action: action to config wowlan |
| * @param wait_option Wait option (MOAL_WAIT or MOAL_NO_WAIT) |
| * @param mefcfg A pointer to mlan_ds_misc_mef_flt_cfg structure |
| * |
| * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_FAILURE |
| */ |
| mlan_status |
| woal_set_get_wowlan_config(moal_private *priv, t_u16 action, |
| t_u8 wait_option, mlan_ds_misc_mef_flt_cfg *mefcfg) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_misc_cfg *misccfg = NULL; |
| mlan_ioctl_req *req = NULL; |
| |
| ENTER(); |
| |
| /** 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 */ |
| misccfg = (mlan_ds_misc_cfg *)req->pbuf; |
| misccfg->sub_command = MLAN_OID_MISC_MEF_FLT_CFG; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| req->action = action; |
| moal_memcpy_ext(priv->phandle, &misccfg->param.mef_flt_cfg, mefcfg, |
| sizeof(mlan_ds_misc_mef_flt_cfg), |
| sizeof(mlan_ds_misc_mef_flt_cfg)); |
| /* Send IOCTL request to MLAN */ |
| ret = woal_request_ioctl(priv, req, wait_option); |
| if (ret == MLAN_STATUS_SUCCESS) { |
| if (mefcfg && action == MLAN_ACT_GET) { |
| moal_memcpy_ext(priv->phandle, mefcfg, |
| &misccfg->param.mef_flt_cfg, |
| sizeof(mlan_ds_misc_mef_flt_cfg), |
| sizeof(mlan_ds_misc_mef_flt_cfg)); |
| } |
| } |
| if (ret != MLAN_STATUS_SUCCESS && ret != MLAN_STATUS_PENDING) |
| PRINTM(MIOCTL, "Set Get wowlan IOCTL failed!\n"); |
| done: |
| if (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) |
| { |
| #ifdef STA_CFG80211 |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) |
| moal_handle *handle = NULL; |
| #endif |
| #endif |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_hs_cfg hscfg; |
| #ifdef STA_CFG80211 |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) |
| int i; |
| #endif |
| #endif |
| ENTER(); |
| |
| if (!priv) { |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| /* 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); |
| |
| #if IS_ENABLED(CONFIG_IPV6) |
| if (priv->phandle->hs_auto_arp) { |
| PRINTM(MIOCTL, "Canecl Host Sleep... remove ipv6 offload\n"); |
| /** Set ipv6 router advertisement message offload */ |
| woal_set_ipv6_ra_offload(priv->phandle, MFALSE); |
| } |
| #endif |
| |
| if (priv->phandle->hs_auto_arp) { |
| PRINTM(MIOCTL, "Cancel Host Sleep... remove FW auto arp\n"); |
| /* remove auto arp from FW */ |
| woal_set_auto_arp(priv->phandle, MFALSE); |
| /* remove auto arp from FW */ |
| woal_set_auto_arp_ext(priv->phandle, MFALSE); |
| } |
| #ifdef STA_CFG80211 |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) |
| handle = priv->phandle; |
| if (GTK_REKEY_OFFLOAD_SUSPEND == handle->params.gtk_rekey_offload) { |
| PRINTM(MIOCTL, |
| "Cancel Host Sleep... clear gtk rekey offload of FW\n"); |
| for (i = 0; i < handle->priv_num; i++) { |
| if (handle->priv[i] && handle->priv[i]->gtk_data_ready) { |
| PRINTM(MCMND, "clear GTK in resume\n"); |
| woal_set_rekey_data(handle->priv[i], NULL, |
| MLAN_ACT_CLEAR, |
| wait_option); |
| } |
| } |
| } |
| #endif |
| #endif |
| |
| 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; |
| int i; |
| #ifdef SDIO_SUSPEND_RESUME |
| mlan_ds_ps_info pm_info; |
| #endif |
| pmlan_ds_misc_keep_alive keep_alive = NULL; |
| t_u8 media_connected = MFALSE; |
| |
| 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; |
| } |
| 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 (moal_extflg_isset(handle, |
| EXT_DISCONNECT_ON_SUSPEND) && |
| handle->priv[i]->media_connected == MTRUE) { |
| PRINTM(MIOCTL, "disconnect on suspend\n"); |
| woal_disconnect(handle->priv[i], MOAL_NO_WAIT, |
| NULL, DEF_DEAUTH_REASON_CODE); |
| } |
| } |
| if (handle->priv[i]) { |
| PRINTM(MIOCTL, "woal_delba_all on priv[%d]\n", i); |
| woal_delba_all(handle->priv[i], MOAL_NO_WAIT); |
| } |
| } |
| |
| #if defined(STA_CFG80211) || defined(UAP_CFG80211) |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) |
| if (priv->phandle->is_remain_timer_set) { |
| woal_cancel_timer(&priv->phandle->remain_timer); |
| woal_remain_timer_func(priv->phandle); |
| } |
| /* cancel pending remain on channel */ |
| if (priv->phandle->remain_on_channel) { |
| t_u8 channel_status; |
| moal_private *remain_priv = |
| priv->phandle->priv[priv->phandle->remain_bss_index]; |
| if (remain_priv) { |
| woal_cfg80211_remain_on_channel_cfg(remain_priv, |
| MOAL_NO_WAIT, MTRUE, |
| &channel_status, |
| NULL, 0, 0); |
| if (priv->phandle->cookie) { |
| cfg80211_remain_on_channel_expired( |
| #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 6, 0) |
| remain_priv-> |
| netdev, |
| #else |
| remain_priv-> |
| wdev, |
| #endif |
| priv-> |
| phandle-> |
| cookie, |
| &priv-> |
| phandle-> |
| chan, |
| #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 8, 0) |
| priv-> |
| phandle-> |
| channel_type, |
| #endif |
| GFP_ATOMIC); |
| priv->phandle->cookie = 0; |
| } |
| } |
| priv->phandle->remain_on_channel = MFALSE; |
| } |
| #endif |
| #endif |
| |
| #ifdef STA_SUPPORT |
| woal_reconfig_bgscan(priv->phandle); |
| #endif |
| |
| media_connected = woal_check_media_connected(handle); |
| #if IS_ENABLED(CONFIG_IPV6) |
| if (handle->hs_auto_arp && media_connected) { |
| PRINTM(MIOCTL, "Host Sleep enabled... set ipv6 offload\n"); |
| /** Set ipv6 router advertisement message offload */ |
| woal_set_ipv6_ra_offload(handle, MTRUE); |
| /** Set Neighbor Solitation message offload */ |
| woal_set_ipv6_ns_offload(handle); |
| } |
| #endif |
| if (handle->hs_auto_arp && media_connected) { |
| PRINTM(MIOCTL, "Host Sleep enabled... set FW auto arp\n"); |
| /* Set auto arp response configuration to Fw */ |
| woal_set_auto_arp(handle, MTRUE); |
| /* Set auto arp response configuration to Fw */ |
| woal_set_auto_arp_ext(handle, MTRUE); |
| } |
| #ifdef STA_CFG80211 |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 1, 0) |
| if (GTK_REKEY_OFFLOAD_SUSPEND == handle->params.gtk_rekey_offload) { |
| PRINTM(MIOCTL, |
| "Host Sleep enabled... set gtk rekey offload to FW\n"); |
| for (i = 0; i < handle->priv_num; i++) { |
| if (handle->priv[i] && handle->priv[i]->gtk_data_ready) { |
| PRINTM(MCMND, "set GTK before suspend\n"); |
| woal_set_rekey_data(handle->priv[i], |
| &handle->priv[i]-> |
| gtk_rekey_data, |
| MLAN_ACT_SET, MOAL_NO_WAIT); |
| } |
| } |
| } |
| #endif |
| #endif |
| |
| for (i = 0; i < MAX_KEEP_ALIVE_ID; i++) { |
| keep_alive = &handle->keep_alive[i]; |
| if (keep_alive && keep_alive->cached && keep_alive->enable) { |
| keep_alive->cached = false; |
| woal_start_mkeep_alive(woal_get_priv |
| (handle, MLAN_BSS_ROLE_ANY), |
| keep_alive->mkeep_alive_id, |
| keep_alive->packet, |
| keep_alive->pkt_len, |
| keep_alive->src_mac, |
| keep_alive->dst_mac, |
| keep_alive->send_interval, |
| keep_alive->retry_interval, |
| keep_alive->retry_count); |
| keep_alive->pkt_len = 0; |
| memset(keep_alive->packet, 0, MKEEP_ALIVE_IP_PKT_MAX); |
| } |
| } |
| /* 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_timeout(handle->hs_activate_wait_q, |
| handle->hs_activate_wait_q_woken, |
| HS_ACTIVE_TIMEOUT); |
| #ifdef SDIO_MMC |
| if (IS_SD(handle->card_type)) { |
| sdio_claim_host(((struct sdio_mmc_card *)handle->card)->func); |
| } |
| #endif |
| |
| #ifdef SDIO_SUSPEND_RESUME |
| memset(&pm_info, 0, sizeof(mlan_ds_ps_info)); |
| #endif |
| 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 if (IS_SD(handle->card_type)) { |
| 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 */ |
| #ifdef SDIO_MMC |
| if (IS_SD(handle->card_type)) { |
| sdio_release_host(((struct sdio_mmc_card *)handle->card)->func); |
| } |
| #endif |
| if (hs_actived != MTRUE) { |
| handle->hs_skip_count++; |
| #ifdef SDIO_SUSPEND_RESUME |
| if (IS_SD(handle->card_type)) { |
| 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; |
| } |
| |
| #ifdef CONFIG_PROC_FS |
| /** |
| * @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_IOCTL_WAIT); |
| } |
| |
| handle->surprise_removed = MTRUE; |
| woal_sched_timeout(5); |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| #endif /* CONFIG_PROC_FS */ |
| |
| /** |
| * @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) |
| { |
| 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) { |
| status = MLAN_STATUS_FAILURE; |
| 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 (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) |
| { |
| t_u8 hotfix_ver = 0; |
| union { |
| t_u32 l; |
| t_u8 c[4]; |
| } ver; |
| char fw_ver[32]; |
| |
| ENTER(); |
| |
| hotfix_ver = handle->fw_hotfix_version; |
| ver.l = handle->fw_release_number; |
| |
| if (hotfix_ver) { |
| snprintf(fw_ver, sizeof(fw_ver), "%u.%u.%u.p%u.%u", ver.c[2], |
| ver.c[1], ver.c[0], ver.c[3], hotfix_ver); |
| |
| } else { |
| 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, handle->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; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| 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; |
| } |
| } |
| } |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| 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 (status != MLAN_STATUS_PENDING) |
| 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 drv_dbg Driver debug level |
| * |
| * @return 0 --success, otherwise fail |
| */ |
| int |
| woal_set_drvdbg(moal_private *priv, t_u32 drv_dbg) |
| { |
| 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 = drv_dbg; |
| |
| ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| |
| if (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) |
| moal_memcpy_ext(priv->phandle, &misc->param.mgmt_subtype_mask, |
| pmgmt_subtype_mask, |
| sizeof(misc->param.mgmt_subtype_mask), |
| sizeof(misc->param.mgmt_subtype_mask)); |
| |
| ret = woal_request_ioctl(priv, req, wait_option); |
| |
| if (req->action == MLAN_ACT_GET) |
| moal_memcpy_ext(priv->phandle, pmgmt_subtype_mask, |
| &misc->param.mgmt_subtype_mask, |
| sizeof(misc->param.mgmt_subtype_mask), |
| sizeof(misc->param.mgmt_subtype_mask)); |
| |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get Transmit beamforming capabilities |
| * |
| * @param priv A pointer to moal_private structure |
| * @param action Action: set or get |
| * @param tx_bf_cap A pointer to tx_buf_cap buffer |
| * |
| * @return MLAN_STATUS_SUCCESS -- success, otherwise fail |
| */ |
| mlan_status |
| woal_set_get_tx_bf_cap(moal_private *priv, t_u16 action, t_u32 *tx_bf_cap) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_11n_cfg *bf_cfg = NULL; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (!tx_bf_cap) { |
| 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_CAP; |
| req->action = action; |
| if (action == MLAN_ACT_SET) |
| bf_cfg->param.tx_bf_cap = *tx_bf_cap; |
| |
| /* Send IOCTL request to MLAN */ |
| ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (ret != MLAN_STATUS_SUCCESS) { |
| goto done; |
| } |
| |
| if (action == MLAN_ACT_GET) |
| *tx_bf_cap = bf_cfg->param.tx_bf_cap; |
| |
| done: |
| if (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; |
| moal_memcpy_ext(priv->phandle, &bf_cfg->param.tx_bf, tx_bf_cfg, |
| sizeof(mlan_ds_11n_tx_bf_cfg), |
| sizeof(mlan_ds_11n_tx_bf_cfg)); |
| |
| /* Send IOCTL request to MLAN */ |
| ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (ret != MLAN_STATUS_SUCCESS) |
| goto done; |
| |
| if (action == MLAN_ACT_GET) |
| moal_memcpy_ext(priv->phandle, tx_bf_cfg, &bf_cfg->param.tx_bf, |
| sizeof(mlan_ds_11n_tx_bf_cfg), |
| sizeof(mlan_ds_11n_tx_bf_cfg)); |
| |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| 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) |
| { |
| int cfg80211_wext; |
| |
| ENTER(); |
| |
| if (priv == NULL) { |
| LEAVE(); |
| return; |
| } |
| cfg80211_wext = priv->phandle->params.cfg80211_wext; |
| 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 |
| case MLAN_IOCTL_MISC_CFG: |
| woal_ioctl_get_misc_conf(priv, (mlan_ds_misc_cfg *)req->pbuf); |
| 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_IOCTL_WAIT); |
| if (ret == MLAN_STATUS_SUCCESS) { |
| if (pm_info) { |
| moal_memcpy_ext(priv->phandle, pm_info, |
| &pmcfg->param.ps_info, |
| sizeof(mlan_ds_ps_info), |
| sizeof(mlan_ds_ps_info)); |
| } |
| } |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| 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; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| 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; |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| *data = pm->param.auto_deep_sleep.auto_ds; |
| *(data + 1) = pm->param.auto_deep_sleep.idletime; |
| |
| done: |
| if (status != 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 (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; |
| /* Make sure Chan Report is cancelled */ |
| woal_11h_cancel_chan_report_ioctl(priv, MOAL_IOCTL_WAIT); |
| 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); |
| } |
| #ifdef UAP_SUPPORT |
| #if defined(STA_CFG80211) || defined(UAP_CFG80211) |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) |
| if (priv->uap_host_based && |
| moal_extflg_isset(priv->phandle, EXT_DFS_OFFLOAD)) |
| woal_cfg80211_dfs_vendor_event(priv, |
| event_dfs_cac_aborted, |
| &priv->chan); |
| #endif |
| #endif |
| #endif |
| } |
| 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 |
| * @param wait_option wait option |
| * |
| * @return 0 --success, otherwise fail |
| */ |
| int |
| woal_11h_channel_check_ioctl(moal_private *priv, t_u8 wait_option) |
| { |
| int ret = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_11h_cfg *ds_11hcfg = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| #ifdef UAP_SUPPORT |
| if (priv->skip_cac) { |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| |
| /* Skip sending request/report query when DFS_REPEATER_MODE is on. This |
| * would get rid of CAC timers before starting BSSes in |
| * DFS_REPEATER_MODE |
| */ |
| if (priv->phandle->dfs_repeater_mode) { |
| LEAVE(); |
| return ret; |
| } |
| |
| if (woal_is_any_interface_active(priv->phandle)) { |
| } |
| |
| 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; |
| ds_11hcfg->param.chan_rpt_req.host_based = MFALSE; |
| req->req_id = MLAN_IOCTL_11H_CFG; |
| req->action = MLAN_ACT_SET; |
| /* Send Channel Check command and wait until the report is ready */ |
| status = woal_request_ioctl(priv, req, wait_option); |
| if (status != MLAN_STATUS_SUCCESS) { |
| goto done; |
| } |
| |
| /* set flag from here */ |
| priv->phandle->cac_period = MTRUE; |
| priv->phandle->meas_start_jiffies = jiffies; |
| priv->phandle->cac_timer_jiffies = |
| ds_11hcfg->param.chan_rpt_req.millisec_dwell_time * HZ / 1000; |
| |
| #ifdef UAP_SUPPORT |
| #if defined(STA_CFG80211) || defined(UAP_CFG80211) |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) |
| if (priv->uap_host_based && |
| moal_extflg_isset(priv->phandle, EXT_DFS_OFFLOAD)) |
| woal_cfg80211_dfs_vendor_event(priv, event_dfs_cac_started, |
| &priv->chan); |
| #endif |
| #endif |
| #endif |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Issue MLAN_OID_11H_CHAN_REPORT_REQUEST ioctl to cancel dozer |
| * |
| * @param priv Pointer to the moal_private driver data struct |
| * @param wait_option wait option |
| * |
| * @return 0 --success, otherwise fail |
| */ |
| int |
| woal_11h_cancel_chan_report_ioctl(moal_private *priv, t_u8 wait_option) |
| { |
| int ret = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_11h_cfg *ds_11hcfg = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| PRINTM(MCMND, "wlan: woal_11h_cancel_chan_report\n"); |
| 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_CHAN_REPORT_REQUEST; |
| req->req_id = MLAN_IOCTL_11H_CFG; |
| req->action = MLAN_ACT_SET; |
| ds_11hcfg->param.chan_rpt_req.millisec_dwell_time = 0; |
| /* Send Channel Check command and wait until the report is ready */ |
| status = woal_request_ioctl(priv, req, wait_option); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| 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; |
| moal_memcpy_ext(priv->phandle, &radio_cfg->param.remain_chan, pchan, |
| sizeof(mlan_ds_remain_chan), |
| sizeof(mlan_ds_remain_chan)); |
| ret = woal_request_ioctl(priv, req, wait_option); |
| if (ret == MLAN_STATUS_SUCCESS) { |
| moal_memcpy_ext(priv->phandle, pchan, |
| &radio_cfg->param.remain_chan, |
| sizeof(mlan_ds_remain_chan), |
| sizeof(mlan_ds_remain_chan)); |
| PRINTM(MCMND, |
| "Remain_chan_cfg: remove=%d, channel=%d, remain_period=%d\n", |
| pchan->remove, pchan->channel, pchan->remain_period); |
| } |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| #ifdef 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_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 (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set p2p config |
| * |
| * @param priv A pointer to moal_private structure |
| * @param action Action set or get |
| * @param p2p_config A pointer to mlan_ds_wifi_direct_config structure |
| * |
| * @return MLAN_STATUS_SUCCESS -- success, otherwise fail |
| */ |
| mlan_status |
| woal_p2p_config(moal_private *priv, t_u32 action, |
| mlan_ds_wifi_direct_config *p2p_config) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *misc_cfg = NULL; |
| |
| ENTER(); |
| if (!p2p_config) { |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| misc_cfg = (mlan_ds_misc_cfg *)req->pbuf; |
| misc_cfg->sub_command = MLAN_OID_MISC_WIFI_DIRECT_CONFIG; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| req->action = action; |
| moal_memcpy_ext(priv->phandle, &misc_cfg->param.p2p_config, p2p_config, |
| sizeof(mlan_ds_wifi_direct_config), |
| sizeof(mlan_ds_wifi_direct_config)); |
| ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (ret == MLAN_STATUS_SUCCESS) { |
| if (action == MLAN_ACT_GET) |
| moal_memcpy_ext(priv->phandle, p2p_config, |
| &misc_cfg->param.p2p_config, |
| sizeof(mlan_ds_wifi_direct_config), |
| sizeof(mlan_ds_wifi_direct_config)); |
| } |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| #endif /* WIFI_DIRECT_SUPPORT */ |
| |
| #ifdef STA_SUPPORT |
| /** |
| * @brief Get STA Channel Info |
| * |
| * @param priv A pointer to moal_private structure |
| * @param wait_option Wait option |
| * @param channel A pointer to channel info |
| * |
| * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- |
| * success, otherwise fail |
| */ |
| mlan_status |
| woal_get_sta_channel(moal_private *priv, t_u8 wait_option, |
| chan_band_info * channel) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_bss *bss = 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) { |
| PRINTM(MERROR, "woal_get_sta_channel req alloc fail\n"); |
| status = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| |
| /* Fill request buffer */ |
| bss = (mlan_ds_bss *)req->pbuf; |
| bss->sub_command = MLAN_OID_BSS_CHAN_INFO; |
| 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 && channel) |
| moal_memcpy_ext(priv->phandle, channel, |
| &(bss->param.sta_channel), |
| sizeof(chan_band_info), sizeof(chan_band_info)); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return status; |
| } |
| |
| /** |
| * @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) |
| { |
| 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) { |
| status = MLAN_STATUS_FAILURE; |
| 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) |
| moal_memcpy_ext(priv->phandle, signal, |
| &info->param.signal, |
| sizeof(mlan_ds_get_signal), |
| sizeof(mlan_ds_get_signal)); |
| #ifdef STA_WEXT |
| if (IS_STA_WEXT(priv->phandle->params.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 (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) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_scan *scan = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| ENTER(); |
| |
| if (!scan_resp) { |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| |
| /* Allocate an IOCTL request buffer */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan)); |
| if (req == NULL) { |
| status = MLAN_STATUS_FAILURE; |
| 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; |
| moal_memcpy_ext(priv->phandle, (void *)&scan->param.scan_resp, |
| (void *)scan_resp, sizeof(mlan_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) { |
| moal_memcpy_ext(priv->phandle, scan_resp, |
| &scan->param.scan_resp, |
| sizeof(mlan_scan_resp), |
| sizeof(mlan_scan_resp)); |
| } |
| } |
| |
| done: |
| if (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; |
| handle->scan_priv = priv; |
| |
| /* 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; |
| |
| moal_memcpy_ext(handle, scan->param.scan_req.scan_ssid.ssid, |
| req_ssid->ssid, req_ssid->ssid_len, |
| MLAN_MAX_SSID_LENGTH); |
| 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 (status != MLAN_STATUS_PENDING) |
| kfree(ioctl_req); |
| |
| if (ret == MLAN_STATUS_FAILURE) { |
| handle->scan_pending_on_block = MFALSE; |
| handle->scan_priv = NULL; |
| 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. |
| * @param wait_option wait_option |
| * |
| * @return MLAN_STATUS_SUCCESS--success, MLAN_STATUS_FAILURE--fail |
| */ |
| mlan_status |
| woal_change_adhoc_chan(moal_private *priv, int channel, t_u8 wait_option) |
| { |
| 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, wait_option, &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 */ |
| ret = woal_request_ioctl(priv, req, wait_option); |
| if (ret != MLAN_STATUS_SUCCESS) |
| 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 */ |
| ret = woal_request_ioctl(priv, req, wait_option); |
| if (ret != MLAN_STATUS_SUCCESS) |
| goto done; |
| |
| /* Do specific SSID scanning */ |
| if (MLAN_STATUS_SUCCESS != |
| woal_request_scan(priv, wait_option, &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)); |
| moal_memcpy_ext(priv->phandle, &bss->param.ssid_bssid.ssid, |
| &bss_info.ssid, sizeof(mlan_802_11_ssid), |
| sizeof(mlan_802_11_ssid)); |
| |
| /* Send IOCTL request to MLAN */ |
| ret = woal_request_ioctl(priv, req, wait_option); |
| |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| 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; |
| |
| 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; |
| |
| moal_memcpy_ext(priv->phandle, &bss->param.ssid_bssid, ssid_bssid, |
| sizeof(mlan_ssid_bssid), sizeof(mlan_ssid_bssid)); |
| |
| /* Send IOCTL request to MLAN */ |
| ret = woal_request_ioctl(priv, req, wait_option); |
| if (ret == MLAN_STATUS_SUCCESS) { |
| moal_memcpy_ext(priv->phandle, ssid_bssid, |
| &bss->param.ssid_bssid, sizeof(mlan_ssid_bssid), |
| sizeof(mlan_ssid_bssid)); |
| PRINTM(MINFO, "Find network: ssid=%s, " MACSTR ", idx=%d\n", |
| ssid_bssid->ssid.ssid, |
| MAC2STR((t_u8 *)&ssid_bssid->bssid), |
| (int)ssid_bssid->idx); |
| } |
| |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Find the best network to associate |
| * |
| * @param priv A pointer to moal_private structure |
| * @param bssid A pointer to bssid |
| * |
| * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- |
| * success, otherwise fail |
| */ |
| mlan_status |
| woal_find_bssid(moal_private *priv, mlan_802_11_mac_addr bssid) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_bss *bss = NULL; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| /* 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_BSSID; |
| |
| moal_memcpy_ext(priv->phandle, &bss->param.bssid, bssid, |
| sizeof(mlan_802_11_mac_addr), |
| sizeof(mlan_802_11_mac_addr)); |
| |
| /* Send IOCTL request to MLAN */ |
| ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Check if AP channel is valid for STA Region |
| * |
| * @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_11d_check_ap_channel(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; |
| |
| 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_11D_CHECK_CHANNEL; |
| |
| moal_memcpy_ext(priv->phandle, &bss->param.ssid_bssid, ssid_bssid, |
| sizeof(mlan_ssid_bssid), sizeof(mlan_ssid_bssid)); |
| |
| PRINTM(MINFO, "ssid=%s, " MACSTR ", idx=%d\n", ssid_bssid->ssid.ssid, |
| MAC2STR((t_u8 *)&ssid_bssid->bssid), (int)ssid_bssid->idx); |
| |
| /* Send IOCTL request to MLAN */ |
| ret = woal_request_ioctl(priv, req, wait_option); |
| |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| 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) |
| { |
| 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) { |
| status = MLAN_STATUS_FAILURE; |
| 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 (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) |
| { |
| 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) { |
| status = MLAN_STATUS_FAILURE; |
| 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 (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) |
| { |
| 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) { |
| status = MLAN_STATUS_FAILURE; |
| 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 (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) |
| { |
| 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) { |
| status = MLAN_STATUS_FAILURE; |
| 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 (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) |
| { |
| 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) { |
| status = MLAN_STATUS_FAILURE; |
| 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 (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) |
| { |
| 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) { |
| status = MLAN_STATUS_FAILURE; |
| 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 (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) |
| { |
| 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) { |
| status = 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; |
| 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 (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; |
| handle->scan_priv = priv; |
| |
| /* 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; |
| moal_memcpy_ext(handle, scan->param.user_scan.scan_cfg_buf, scan_cfg, |
| sizeof(wlan_user_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 (status != MLAN_STATUS_PENDING) |
| kfree(ioctl_req); |
| else if (wait_option != MOAL_NO_WAIT) { |
| PRINTM(MMSG, "scan interrupted by Signal, Cancel it..."); |
| woal_cancel_scan(priv, MOAL_IOCTL_WAIT_TIMEOUT); |
| } |
| if (ret == MLAN_STATUS_FAILURE) { |
| handle->scan_pending_on_block = MFALSE; |
| handle->scan_priv = NULL; |
| MOAL_REL_SEMAPHORE(&handle->async_sem); |
| } |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief woal_get_scan_config |
| * |
| * @param priv A pointer to moal_private structure |
| * @param scan_cfg A pointer to scan_cfg structure |
| * |
| * @return MLAN_STATUS_SUCCESS -- success, otherwise fail |
| */ |
| mlan_status |
| woal_get_scan_config(moal_private *priv, mlan_scan_cfg *scan_cfg) |
| { |
| 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_GET; |
| memset(&scan->param.scan_cfg, 0, sizeof(mlan_scan_cfg)); |
| ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (ret == MLAN_STATUS_SUCCESS && scan_cfg) |
| moal_memcpy_ext(priv->phandle, scan_cfg, &scan->param.scan_cfg, |
| sizeof(mlan_scan_cfg), sizeof(mlan_scan_cfg)); |
| |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief set scan time |
| * |
| * @param priv A pointer to moal_private structure |
| * @param active_scan_time Active scan time |
| * @param passive_scan_time Passive scan time |
| * @param specific_scan_time Specific scan time |
| * |
| * @return MLAN_STATUS_SUCCESS -- success, otherwise fail |
| */ |
| mlan_status |
| woal_set_scan_time(moal_private *priv, t_u16 active_scan_time, |
| 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; |
| mlan_scan_cfg scan_cfg; |
| |
| ENTER(); |
| |
| memset(&scan_cfg, 0, sizeof(scan_cfg)); |
| if (MLAN_STATUS_SUCCESS != woal_get_scan_config(priv, &scan_cfg)) { |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| 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_cfg.scan_time.active_scan_time = active_scan_time; |
| scan_cfg.scan_time.specific_scan_time = specific_scan_time; |
| scan_cfg.scan_time.passive_scan_time = passive_scan_time; |
| PRINTM(MIOCTL, "Set specific=%d, active=%d, passive=%d\n", |
| (int)active_scan_time, (int)passive_scan_time, |
| (int)specific_scan_time); |
| moal_memcpy_ext(priv->phandle, &scan->param.scan_cfg, &scan_cfg, |
| sizeof(mlan_scan_cfg), sizeof(mlan_scan_cfg)); |
| ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| 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 Cancel pending scan |
| * |
| * @param priv A pointer to moal_private structure |
| * @return MLAN_STATUS_SUCCESS -- success, otherwise fail |
| */ |
| mlan_status |
| woal_cancel_scan(moal_private *priv, t_u8 wait_option) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| moal_handle *handle = priv->phandle; |
| moal_private *scan_priv = handle->scan_priv; |
| #ifdef STA_CFG80211 |
| unsigned long flags; |
| #endif |
| /* If scan is in process, cancel the scan command */ |
| if (!handle->scan_pending_on_block || !scan_priv) |
| return ret; |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan)); |
| if (req == NULL) { |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| req->req_id = MLAN_IOCTL_SCAN; |
| req->action = MLAN_ACT_SET; |
| ((mlan_ds_scan *)req->pbuf)->sub_command = MLAN_OID_SCAN_CANCEL; |
| ret = woal_request_ioctl(scan_priv, req, wait_option); |
| handle->scan_pending_on_block = MFALSE; |
| MOAL_REL_SEMAPHORE(&handle->async_sem); |
| #ifdef STA_CFG80211 |
| spin_lock_irqsave(&handle->scan_req_lock, flags); |
| if (IS_STA_CFG80211(handle->params.cfg80211_wext) && |
| handle->scan_request) { |
| cancel_delayed_work(&handle->scan_timeout_work); |
| /** some supplicant can not handle SCAN abort event */ |
| if (scan_priv->bss_type == MLAN_BSS_TYPE_STA) |
| woal_cfg80211_scan_done(handle->scan_request, MTRUE); |
| else |
| woal_cfg80211_scan_done(handle->scan_request, MFALSE); |
| handle->scan_request = NULL; |
| } |
| spin_unlock_irqrestore(&handle->scan_req_lock, flags); |
| #endif |
| /* add 10ms delay, incase firmware delay 0x7f event after scan cancel |
| * command response */ |
| woal_sched_timeout(10); |
| handle->scan_priv = NULL; |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| return ret; |
| } |
| |
| /** |
| * @brief find ssid in scan_table |
| * |
| * @param priv A pointer to moal_private |
| * @param 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, |
| t_u8 wait_option) |
| { |
| int ret = 0; |
| mlan_scan_resp scan_resp; |
| wifi_timeval t; |
| ENTER(); |
| |
| if (MLAN_STATUS_SUCCESS != |
| woal_get_scan_table(priv, wait_option, &scan_resp)) { |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| #ifdef STA_CFG80211 |
| if (priv->ft_pre_connect || priv->ft_ie_len) { |
| /** skip check the scan age out */ |
| ret = woal_find_best_network(priv, wait_option, ssid_bssid); |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| woal_get_monotonic_time(&t); |
| /** scan result timeout value */ |
| #define SCAN_RESULT_AGEOUT 10 |
| if (t.time_sec > (scan_resp.age_in_secs + SCAN_RESULT_AGEOUT)) { |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| ret = woal_find_best_network(priv, wait_option, 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; |
| moal_memcpy_ext(priv->phandle, scan->param.user_scan.scan_cfg_buf, |
| scan_cfg, sizeof(wlan_bgscan_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 (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_FAILURE; |
| |
| ENTER(); |
| memset(&priv->scan_cfg, 0, sizeof(priv->scan_cfg)); |
| priv->scan_cfg.report_condition = |
| BG_SCAN_SSID_MATCH | BG_SCAN_WAIT_ALL_CHAN_DONE; |
| 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 | |
| BG_SCAN_WAIT_ALL_CHAN_DONE; |
| 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_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: |
| if (buf_left < 3) { |
| PRINTM(MERROR, |
| "Invalid scan_interval, buf_left=%d\n", |
| buf_left); |
| buf_left = 0; |
| break; |
| } |
| 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; |
| moal_memcpy_ext(priv->phandle, priv->scan_cfg.random_mac, |
| priv->random_mac, ETH_ALEN, |
| sizeof(priv->scan_cfg.random_mac)); |
| ret = woal_request_bgscan(priv, MOAL_IOCTL_WAIT, |
| &priv->scan_cfg); |
| } |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| #ifdef STA_CFG80211 |
| /** |
| * @brief set bgscan and new rssi_low_threshold |
| * |
| * @param priv A pointer to moal_private structure |
| * @param set_rssi flag for set rssi_low_threshold |
| * |
| * @return N/A |
| */ |
| void |
| woal_config_bgscan_and_rssi(moal_private *priv, t_u8 set_rssi) |
| { |
| char rssi_low[11]; |
| mlan_bss_info bss_info; |
| int band = 0; |
| |
| ENTER(); |
| if (!priv->rssi_low) { |
| LEAVE(); |
| return; |
| } |
| memset(&bss_info, 0, sizeof(bss_info)); |
| woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info); |
| if (!bss_info.media_connected) { |
| PRINTM(MIOCTL, "We already lost connection\n"); |
| LEAVE(); |
| return; |
| } |
| memset(&priv->scan_cfg, 0, sizeof(priv->scan_cfg)); |
| strncpy(priv->scan_cfg.ssid_list[0].ssid, bss_info.ssid.ssid, |
| bss_info.ssid.ssid_len); |
| priv->scan_cfg.ssid_list[0].max_len = 0; |
| |
| priv->scan_cfg.report_condition = |
| BG_SCAN_SSID_RSSI_MATCH | BG_SCAN_WAIT_ALL_CHAN_DONE; |
| priv->scan_cfg.rssi_threshold = priv->rssi_low - RSSI_HYSTERESIS; |
| priv->scan_cfg.repeat_count = DEF_REPEAT_COUNT; |
| priv->scan_cfg.scan_interval = MIN_BGSCAN_INTERVAL; |
| woal_get_band(priv, &band); |
| 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; |
| moal_memcpy_ext(priv->phandle, priv->scan_cfg.random_mac, |
| priv->random_mac, ETH_ALEN, |
| sizeof(priv->scan_cfg.random_mac)); |
| woal_request_bgscan(priv, MOAL_NO_WAIT, &priv->scan_cfg); |
| if (set_rssi && |
| ((priv->rssi_low + RSSI_HYSTERESIS) <= LOWEST_RSSI_THRESHOLD)) { |
| priv->rssi_low += RSSI_HYSTERESIS; |
| snprintf(rssi_low, sizeof(rssi_low), "%d", priv->rssi_low); |
| woal_set_rssi_low_threshold(priv, rssi_low, MOAL_NO_WAIT); |
| } |
| LEAVE(); |
| } |
| #endif |
| |
| /** |
| * @brief stop bg scan |
| * |
| * @param priv A pointer to moal_private structure |
| * @param wait_option wait option |
| * |
| * @return MLAN_STATUS_SUCCESS -- success, otherwise fail |
| */ |
| mlan_status |
| woal_stop_bg_scan(moal_private *priv, t_u8 wait_option) |
| { |
| wlan_bgscan_cfg scan_cfg; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| ENTER(); |
| |
| memset(&scan_cfg, 0, sizeof(scan_cfg)); |
| scan_cfg.action = BG_SCAN_ACT_SET; |
| scan_cfg.enable = MFALSE; |
| ret = woal_request_bgscan(priv, wait_option, &scan_cfg); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| #if defined(WIFI_LATENCY_MODE_SUPPORT) |
| /** |
| * @brief Enable/disable WiFi low-latency mode |
| * |
| * If low-latency mode is set to WIFI_LATENCY_MODE_LOW, this function |
| * will cancel existing pending Wi-Fi scans and suppress future Wi-Fi scans |
| * via setting |priv->scan_suppressed| to |MTRUE|. Future scans will be supressed |
| * until low-latency mode is set back to WIFI_LATENCY_MODE_NORMAL. |
| * If low-latency mode is set to WIFI_LATENCY_MODE_NORMAL, this function |
| * will set |priv-scan_suppressed| to |MFALSE| and any future will be run as |
| * normal. |
| * |
| * @param priv A pointer to moal_private structure |
| * @param mode 1 -- low-latency mode, 0 -- normal mode |
| * |
| * @return MLAN_STATUS_SUCCESS -- success, otherwise fail |
| */ |
| mlan_status |
| woal_set_wifi_low_latency_mode(moal_private *priv, t_u8 mode) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| /** WIFI_LATENCY_MODE_NORMAL : 0, WIFI_LATENCY_MODE_LOW : 1,*/ |
| t_bool low_latency_mode_enabled = (mode == 1 ? MTRUE : MFALSE); |
| PRINTM(MMSG, "wlan: enter %s.\n", __FUNCTION__); |
| if (MTRUE == low_latency_mode_enabled) { |
| PRINTM(MINFO, "Setting Wi-Fi latency mode to low-latency mode."); |
| /** Cancel pending Wi-Fi scanning if exist. */ |
| if (priv->phandle->scan_request) { |
| woal_cancel_scan(priv, MOAL_NO_WAIT); |
| PRINTM(MINFO, "Cancel existing scan due to low-latency mode."); |
| } |
| /** Suppress future Wi-Fi scan requests. */ |
| priv->scan_suppressed = MTRUE; |
| } else { |
| PRINTM(MINFO, "Setting Wi-Fi latency mode to normal mode."); |
| priv->scan_suppressed = MFALSE; |
| } |
| return ret; |
| } |
| #endif // defined(WIFI_LATENCY_MODE_SUPPORT) |
| |
| /** |
| * @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 rssi A pointer to low rssi |
| * @param wait_option Wait option |
| * |
| * @return MLAN_STATUS_SUCCESS -- success, otherwise fail |
| */ |
| mlan_status |
| woal_set_rssi_low_threshold(moal_private *priv, char *rssi, t_u8 wait_option) |
| { |
| 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 = MLAN_STATUS_FAILURE; |
| 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_action = SUBSCRIBE_EVT_ACT_BITWISE_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 = MLAN_STATUS_FAILURE; |
| 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; |
| ret = woal_request_ioctl(priv, req, wait_option); |
| if (ret == MLAN_STATUS_FAILURE) { |
| PRINTM(MERROR, "request set rssi_low_threshold fail!\n"); |
| goto done; |
| } |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| #if defined(STA_CFG80211) |
| /** |
| * @brief set rssi low threshold |
| * |
| * @param priv A pointer to moal_private structure |
| * @param event_id event id. |
| * @param wait_option wait option |
| * |
| * @return MLAN_STATUS_SUCCESS -- success, otherwise fail |
| */ |
| mlan_status |
| woal_set_rssi_threshold(moal_private *priv, t_u32 event_id, t_u8 wait_option) |
| { |
| 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 || !priv->cqm_rssi_thold) |
| 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_high_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_high_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; |
| if (!event_id && !priv->cqm_rssi_thold && !priv->cqm_rssi_hyst) |
| misc->param.subscribe_event.evt_action = |
| SUBSCRIBE_EVT_ACT_BITWISE_CLR; |
| else |
| misc->param.subscribe_event.evt_action = |
| SUBSCRIBE_EVT_ACT_BITWISE_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 action=%d\n", |
| (int)priv->last_rssi_low, (int)priv->last_rssi_high, |
| misc->param.subscribe_event.evt_action); |
| ret = woal_request_ioctl(priv, req, wait_option); |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| |
| /** |
| * @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, |
| MOAL_IOCTL_WAIT)) { |
| 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; |
| mlan_scan_cfg scan_cfg; |
| |
| ENTER(); |
| memset(&scan_cfg, 0, sizeof(scan_cfg)); |
| if (MLAN_STATUS_SUCCESS != woal_get_scan_config(priv, &scan_cfg)) { |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| |
| 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_cfg.scan_type = scan_type; |
| PRINTM(MIOCTL, "Set scan_type=%d\n", (int)scan_type); |
| moal_memcpy_ext(priv->phandle, &scan->param.scan_cfg, &scan_cfg, |
| sizeof(mlan_scan_cfg), sizeof(mlan_scan_cfg)); |
| ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief enable/disable ext_scan |
| * |
| * @param priv A pointer to moal_private structure |
| * @param enable MTRUE -- enable, MFALSE --disable |
| * |
| * @return MLAN_STATUS_SUCCESS -- success, otherwise fail |
| */ |
| mlan_status |
| woal_enable_ext_scan(moal_private *priv, t_u8 enable) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_scan *scan = NULL; |
| mlan_ioctl_req *req = NULL; |
| mlan_scan_cfg scan_cfg; |
| |
| ENTER(); |
| memset(&scan_cfg, 0, sizeof(scan_cfg)); |
| if (MLAN_STATUS_SUCCESS != woal_get_scan_config(priv, &scan_cfg)) { |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| |
| 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_cfg.ext_scan = enable; |
| PRINTM(MIOCTL, "Set ext_scan=%d\n", (int)enable); |
| moal_memcpy_ext(priv->phandle, &scan->param.scan_cfg, &scan_cfg, |
| sizeof(mlan_scan_cfg), sizeof(mlan_scan_cfg)); |
| ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| 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, |
| MOAL_IOCTL_WAIT)) |
| 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, 0, 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; |
| ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (ret != MLAN_STATUS_SUCCESS) |
| 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 (ret != MLAN_STATUS_PENDING) |
| 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; |
| #if defined(STA_CFG80211) || defined(UAP_CFG80211) |
| int cfg80211_wext = priv->phandle->params.cfg80211_wext; |
| #endif |
| |
| ENTER(); |
| if (priv->media_connected == MTRUE) { |
| PRINTM(MERROR, "Set band is not allowed in connected state\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| 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; |
| ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (ret != MLAN_STATUS_SUCCESS) |
| 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; |
| if (radio_cfg->param.band_cfg.fw_bands & BAND_AN) |
| band |= BAND_AN; |
| if (radio_cfg->param.band_cfg.fw_bands & BAND_AAC) |
| band |= BAND_AAC; |
| #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; |
| ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| 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/Get WMM IE QoS configuration |
| * |
| * @param priv A pointer to moal_private structure |
| * @param action Action set or get |
| * @param qos_cfg A pointer to QoS configuration structure |
| * |
| * @return MLAN_STATUS_SUCCESS -- success, otherwise fail |
| */ |
| mlan_status |
| woal_priv_qos_cfg(moal_private *priv, t_u32 action, 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 (qos_cfg == NULL) { |
| PRINTM(MERROR, "QOS info buffer is null\n"); |
| return MLAN_STATUS_FAILURE; |
| } |
| if ((action == MLAN_ACT_SET) && |
| (MLAN_STATUS_SUCCESS != woal_atoi(&qosinfo, qos_cfg))) { |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| 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 = action; |
| if (action == MLAN_ACT_SET) { |
| cfg->param.qos_cfg = (t_u8)qosinfo; |
| PRINTM(MIOCTL, "set qosinfo=%d\n", qosinfo); |
| } |
| ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| |
| if (action == MLAN_ACT_GET) |
| *qos_cfg = cfg->param.qos_cfg; |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| 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 |
| */ |
| mlan_status |
| 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; |
| } |
| |
| ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set scan period function |
| * |
| * @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 |
| */ |
| int |
| woal_set_scan_cfg(moal_private *priv, char *buf, int length) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u8 *ptr = buf + NL80211_SCANCFG_HEADER_SIZE; |
| int buf_left = length - NL80211_SCANCFG_HEADER_SIZE; |
| t_u16 active_scan_time = 0; |
| t_u16 passive_scan_time = 0; |
| t_u16 specific_scan_time = 0; |
| |
| ENTER(); |
| while (buf_left >= 2) { |
| switch (*ptr) { |
| case NL80211_SCANCFG_ACTV_DWELL_SECTION: |
| if (buf_left < 3) { |
| PRINTM(MERROR, |
| "Invalid ACTV_DWELL_SECTION, buf_left=%d\n", |
| buf_left); |
| buf_left = 0; |
| break; |
| } |
| active_scan_time = ptr[2] << 8 | ptr[1]; |
| ptr += 3; |
| buf_left -= 3; |
| break; |
| case NL80211_SCANCFG_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 NL80211_SCANCFG_SPCF_DWELL_SECTION: |
| if (buf_left < 3) { |
| PRINTM(MERROR, |
| "Invalid SPCF_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 (active_scan_time || passive_scan_time || specific_scan_time) { |
| PRINTM(MIOCTL, |
| "Set active_scan_time= %d passive_scan_time=%d specific_scan_time=%d\n", |
| active_scan_time, passive_scan_time, specific_scan_time); |
| if (MLAN_STATUS_FAILURE == |
| woal_set_scan_time(priv, active_scan_time, |
| passive_scan_time, specific_scan_time)) { |
| ret = -EFAULT; |
| } |
| } |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @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; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| 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; |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) |
| ret = -EFAULT; |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| #endif /* STA_SUPPORT */ |
| |
| #ifdef USB |
| /** |
| * @brief Initialize USB packet aggregation control |
| * |
| * @param handle A pointer to moal_private structure |
| * |
| * @return MLAN_STATUS_SUCCESS -- success, otherwise fail |
| */ |
| mlan_status |
| woal_usb_aggr_init(moal_handle *handle) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| moal_private *priv = NULL; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *pcfg_misc = NULL; |
| mlan_ds_misc_usb_aggr_ctrl *aggr_param = NULL; |
| t_u8 usb_aggr_enable; |
| struct usb_card_rec *cardp = NULL; |
| int i = 0, resubmit_urbs = 0; |
| |
| ENTER(); |
| |
| if (!handle) { |
| PRINTM(MERROR, "Handle is null\n"); |
| LEAVE(); |
| return MLAN_STATUS_FAILURE; |
| } |
| priv = woal_get_priv(handle, MLAN_BSS_ROLE_STA); |
| if (!priv) { |
| PRINTM(MERROR, "STA priv is null\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| if (handle->card == NULL) { |
| PRINTM(MERROR, "Card is null in %s()\n", __func__); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| cardp = (struct usb_card_rec *)handle->card; |
| |
| /* Check module parameter */ |
| if (handle->params.usb_aggr == 0 || handle->params.usb_aggr == 2) { |
| usb_aggr_enable = MFALSE; |
| } else if (handle->params.usb_aggr == 1) { |
| usb_aggr_enable = MTRUE; |
| } else { |
| PRINTM(MWARN, |
| "Invalid module param (usb_aggr) value %d, " |
| "using MLAN default\n", handle->params.usb_aggr); |
| handle->params.usb_aggr = 0; |
| usb_aggr_enable = MFALSE; |
| } |
| |
| /* Allocate an IOCTL request buffer */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| |
| /* Fill request buffer */ |
| pcfg_misc = (mlan_ds_misc_cfg *)req->pbuf; |
| pcfg_misc->sub_command = MLAN_OID_MISC_USB_AGGR_CTRL; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| req->action = MLAN_ACT_SET; |
| |
| aggr_param = &pcfg_misc->param.usb_aggr_params; |
| /* Initialize TX aggr default values */ |
| aggr_param->tx_aggr_ctrl.enable = usb_aggr_enable; |
| aggr_param->tx_aggr_ctrl.aggr_mode = MLAN_USB_AGGR_MODE_NUM; |
| aggr_param->tx_aggr_ctrl.aggr_align = |
| MAX(handle->params.max_tx_buf, MLAN_USB_TX_AGGR_ALIGN); |
| aggr_param->tx_aggr_ctrl.aggr_max = MLAN_USB_TX_MAX_AGGR_NUM; |
| aggr_param->tx_aggr_ctrl.aggr_tmo = |
| MLAN_USB_TX_AGGR_TIMEOUT_MSEC * 1000; |
| |
| /* Initialize RX deaggr default values */ |
| aggr_param->rx_deaggr_ctrl.enable = usb_aggr_enable; |
| aggr_param->rx_deaggr_ctrl.aggr_mode = MLAN_USB_AGGR_MODE_NUM; |
| aggr_param->rx_deaggr_ctrl.aggr_align = MLAN_USB_RX_ALIGN_SIZE; |
| aggr_param->rx_deaggr_ctrl.aggr_max = MLAN_USB_RX_MAX_AGGR_NUM; |
| aggr_param->rx_deaggr_ctrl.aggr_tmo = MLAN_USB_RX_DEAGGR_TIMEOUT_USEC; |
| |
| /* Do not fail driver init due to command failure */ |
| ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| /* Disable the feature if FW return failure/unsupported */ |
| if (req->status_code) |
| cardp->tx_aggr_ctrl.enable = MFALSE; |
| else |
| moal_memcpy_ext(handle, &cardp->tx_aggr_ctrl, |
| &aggr_param->tx_aggr_ctrl, |
| sizeof(usb_aggr_ctrl_cfg), |
| sizeof(usb_aggr_ctrl_cfg)); |
| |
| if (req->status_code) { |
| /* Disable the feature if FW return failure/unsupported */ |
| cardp->rx_deaggr_ctrl.enable = MFALSE; |
| } else { |
| /* Default is disable, resubmit URBs only for enable */ |
| if (cardp->rx_deaggr_ctrl.enable != usb_aggr_enable) |
| resubmit_urbs = 1; |
| } |
| if (resubmit_urbs) { |
| /* Indicate resubmition from here */ |
| cardp->resubmit_urbs = 1; |
| /* Rx SG feature is disabled due to FW failure/unsupported, |
| * kill the URBs, they will be resubmitted after saving the |
| * parameters to USB card */ |
| if (atomic_read(&cardp->rx_data_urb_pending)) { |
| for (i = 0; i < MVUSB_RX_DATA_URB; i++) { |
| if (cardp->rx_data_list[i].urb) { |
| usb_kill_urb(cardp->rx_data_list[i]. |
| urb); |
| usb_init_urb(cardp->rx_data_list[i]. |
| urb); |
| } |
| } |
| } |
| |
| /* Default is disable, update only for enable case */ |
| moal_memcpy_ext(handle, &cardp->rx_deaggr_ctrl, |
| &aggr_param->rx_deaggr_ctrl, |
| sizeof(usb_aggr_ctrl_cfg), |
| sizeof(usb_aggr_ctrl_cfg)); |
| |
| /* Ensure the next data URBs will use the modified parameters */ |
| if (!atomic_read(&cardp->rx_data_urb_pending)) { |
| /* Submit multiple Rx data URBs */ |
| woal_usb_submit_rx_data_urbs(handle); |
| } |
| cardp->resubmit_urbs = 0; |
| } |
| |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| |
| /** |
| * @brief Set hotspot configuration value to mlan layer |
| * |
| * @param priv A pointer to moal_private structure |
| * @param wait_option wait option |
| * @param hotspotcfg Hotspot configuration value |
| * |
| * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, |
| * otherwise fail |
| */ |
| mlan_status |
| woal_set_hotspotcfg(moal_private *priv, t_u8 wait_option, t_u32 hotspotcfg) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| 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 = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| |
| cfg = (mlan_ds_misc_cfg *)req->pbuf; |
| cfg->param.hotspot_cfg = hotspotcfg; |
| req->action = MLAN_ACT_SET; |
| |
| cfg->sub_command = MLAN_OID_MISC_HOTSPOT_CFG; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| |
| ret = woal_request_ioctl(priv, req, wait_option); |
| if (ret != MLAN_STATUS_SUCCESS) |
| goto done; |
| |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Send delelte all BA 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 |
| */ |
| mlan_status |
| woal_delba_all(moal_private *priv, t_u8 wait_option) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_11n_cfg *cfg_11n = NULL; |
| mlan_ds_11n_delba *del_ba = NULL; |
| t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = { 0 }; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| int ret = 0; |
| |
| req = (mlan_ioctl_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; |
| req->req_id = MLAN_IOCTL_11N_CFG; |
| cfg_11n->sub_command = MLAN_OID_11N_CFG_DELBA; |
| |
| del_ba = &cfg_11n->param.del_ba; |
| memset(del_ba, 0, sizeof(mlan_ds_11n_delba)); |
| del_ba->direction = DELBA_RX | DELBA_TX; |
| del_ba->tid = DELBA_ALL_TIDS; |
| moal_memcpy_ext(priv->phandle, del_ba->peer_mac_addr, zero_mac, |
| ETH_ALEN, sizeof(del_ba->peer_mac_addr)); |
| |
| status = woal_request_ioctl(priv, req, wait_option); |
| |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Send 11d enable/disable command to firmware. |
| * |
| * @param priv A pointer to moal_private structure |
| * @param wait_option Wait option |
| * @param enable Enable/Disable 11d |
| * |
| * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, |
| * otherwise fail |
| */ |
| mlan_status |
| woal_set_11d(moal_private *priv, t_u8 wait_option, t_u8 enable) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_snmp_mib *snmp = NULL; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib)); |
| if (req == NULL) { |
| LEAVE(); |
| return -ENOMEM; |
| } |
| |
| req->action = MLAN_ACT_SET; |
| req->req_id = MLAN_IOCTL_SNMP_MIB; |
| |
| snmp = (mlan_ds_snmp_mib *)req->pbuf; |
| snmp->sub_command = MLAN_OID_SNMP_MIB_DOT11D; |
| snmp->param.oid_value = enable; |
| |
| ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Handle miscellaneous ioctls for asynchronous command response |
| * |
| * @param priv Pointer to moal_private structure |
| * @param info Pointer to mlan_ds_misc_cfg structure |
| * |
| * @return N/A |
| */ |
| void |
| woal_ioctl_get_misc_conf(moal_private *priv, mlan_ds_misc_cfg *info) |
| { |
| ENTER(); |
| switch (info->sub_command) { |
| default: |
| break; |
| } |
| } |
| |
| #ifdef CONFIG_PROC_FS |
| #define RADIO_MODE_STR_LEN 20 |
| #define TX_PWR_STR_LEN 20 |
| #define TX_CONT_STR_LEN 50 |
| #define TX_FRAME_STR_LEN 200 |
| #define HE_TB_TX_STR_LEN 30 |
| |
| /* |
| * @brief Parse mfg cmd radio mode string |
| * |
| * @param s A pointer to user buffer |
| * @param len Length of user buffer |
| * @param d A pointer to mfg_cmd_generic_cfg struct |
| * @return 0 on success, -EINVAL otherwise |
| */ |
| static int |
| parse_radio_mode_string(const char *s, size_t len, |
| struct mfg_cmd_generic_cfg *d) |
| { |
| int ret = MLAN_STATUS_SUCCESS; |
| char *string = NULL; |
| char *tmp = NULL; |
| char *pos = NULL; |
| gfp_t flag; |
| |
| ENTER(); |
| if (!s || !d) { |
| LEAVE(); |
| return -EINVAL; |
| } |
| flag = (in_atomic() || irqs_disabled())? GFP_ATOMIC : GFP_KERNEL; |
| string = kzalloc(RADIO_MODE_STR_LEN, flag); |
| if (string == NULL) { |
| LEAVE(); |
| return -ENOMEM; |
| } |
| |
| moal_memcpy_ext(NULL, string, s + strlen("radio_mode="), |
| len - strlen("radio_mode="), RADIO_MODE_STR_LEN - 1); |
| |
| tmp = string; |
| string = strstrip(string); |
| |
| /* radio mode index 0 */ |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->data1 = (t_u32)woal_string_to_number(pos); |
| |
| /* radio mode index 1 */ |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->data2 = (t_u32)woal_string_to_number(pos); |
| |
| if ((d->data1 > 14 || d->data1 < 0) || (d->data2 > 14 || d->data2 < 0)) |
| ret = -EINVAL; |
| |
| kfree(tmp); |
| LEAVE(); |
| return ret; |
| } |
| |
| /* |
| * @brief Parse mfg cmd tx pwr string |
| * |
| * @param s A pointer to user buffer |
| * @param len Length of user buffer |
| * @param d A pointer to mfg_cmd_generic_cfg struct |
| * @return 0 on success, -EINVAL otherwise |
| */ |
| static int |
| parse_tx_pwr_string(const char *s, size_t len, struct mfg_cmd_generic_cfg *d) |
| { |
| int ret = MLAN_STATUS_SUCCESS; |
| char *string = NULL; |
| char *tmp = NULL; |
| char *pos = NULL; |
| gfp_t flag; |
| |
| ENTER(); |
| if (!s || !d) { |
| LEAVE(); |
| return -EINVAL; |
| } |
| flag = (in_atomic() || irqs_disabled())? GFP_ATOMIC : GFP_KERNEL; |
| string = kzalloc(TX_PWR_STR_LEN, flag); |
| if (string == NULL) { |
| LEAVE(); |
| return -ENOMEM; |
| } |
| |
| moal_memcpy_ext(NULL, string, s + strlen("tx_power="), |
| len - strlen("tx_power="), TX_PWR_STR_LEN - 1); |
| |
| tmp = string; |
| string = strstrip(string); |
| |
| /* tx power value */ |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->data1 = (t_u32)woal_string_to_number(pos); |
| |
| /* modulation */ |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->data2 = (t_u32)woal_string_to_number(pos); |
| |
| /* path id */ |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->data3 = (t_u32)woal_string_to_number(pos); |
| |
| if ((d->data1 > 24) || (d->data2 > 2)) |
| ret = -EINVAL; |
| |
| kfree(tmp); |
| LEAVE(); |
| return ret; |
| } |
| |
| /* |
| * @brief Parse mfg cmd tx cont string |
| * |
| * @param s A pointer to user buffer |
| * @param len Length of user buffer |
| * @param d A pointer to mfg_cmd_tx_cont struct |
| * @return 0 on success, -EINVAL otherwise |
| */ |
| static int |
| parse_tx_cont_string(const char *s, size_t len, struct mfg_cmd_tx_cont *d) |
| { |
| int ret = MLAN_STATUS_SUCCESS; |
| char *string = NULL; |
| char *tmp = NULL; |
| char *pos = NULL; |
| gfp_t flag; |
| |
| ENTER(); |
| if (!s || !d) { |
| LEAVE(); |
| return -EINVAL; |
| } |
| flag = (in_atomic() || irqs_disabled())? GFP_ATOMIC : GFP_KERNEL; |
| string = kzalloc(TX_CONT_STR_LEN, flag); |
| if (string == NULL) { |
| LEAVE(); |
| return -ENOMEM; |
| } |
| |
| moal_memcpy_ext(NULL, string, s + strlen("tx_continuous="), |
| len - strlen("tx_continuous="), TX_CONT_STR_LEN - 1); |
| |
| tmp = string; |
| string = strstrip(string); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->enable_tx = (t_u32)woal_string_to_number(pos); |
| |
| if (d->enable_tx == MFALSE) |
| goto done; |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->cw_mode = (t_u32)woal_string_to_number(pos); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->payload_pattern = (t_u32)woal_string_to_number(pos); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->cs_mode = (t_u32)woal_string_to_number(pos); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->act_sub_ch = (t_u32)woal_string_to_number(pos); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->tx_rate = (t_u32)woal_string_to_number(pos); |
| |
| if ((d->enable_tx > 1) || (d->cw_mode > 1) || (d->cs_mode > 1) |
| || (d->act_sub_ch == 2 || d->act_sub_ch > 3)) |
| ret = -EINVAL; |
| done: |
| kfree(tmp); |
| LEAVE(); |
| return ret; |
| } |
| |
| /* |
| * @brief Parse mfg cmd tx frame string |
| * |
| * @param s A pointer to user buffer |
| * @param len Length of user buffer |
| * @param d A pointer to mfg_cmd_tx_frame2 struct |
| * @return 0 on success, -EINVAL otherwise |
| */ |
| static int |
| parse_tx_frame_string(const char *s, size_t len, struct mfg_cmd_tx_frame2 *d) |
| { |
| int ret = MLAN_STATUS_SUCCESS; |
| char *string = NULL; |
| char *tmp = NULL; |
| char *pos = NULL; |
| int i; |
| gfp_t flag; |
| |
| ENTER(); |
| if (!s || !d) { |
| LEAVE(); |
| return -EINVAL; |
| } |
| flag = (in_atomic() || irqs_disabled())? GFP_ATOMIC : GFP_KERNEL; |
| string = kzalloc(TX_FRAME_STR_LEN, flag); |
| if (string == NULL) |
| return -ENOMEM; |
| |
| moal_memcpy_ext(NULL, string, s + strlen("tx_frame="), |
| len - strlen("tx_frame="), TX_FRAME_STR_LEN - 1); |
| |
| tmp = string; |
| string = strstrip(string); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->enable = (t_u32)woal_string_to_number(pos); |
| |
| if (d->enable == MFALSE) |
| goto done; |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->data_rate = (t_u32)woal_string_to_number(pos); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->frame_pattern = (t_u32)woal_string_to_number(pos); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->frame_length = (t_u32)woal_string_to_number(pos); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->adjust_burst_sifs = (t_u16)woal_string_to_number(pos); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->burst_sifs_in_us = (t_u32)woal_string_to_number(pos); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->short_preamble = (t_u32)woal_string_to_number(pos); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->act_sub_ch = (t_u32)woal_string_to_number(pos); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->short_gi = (t_u32)woal_string_to_number(pos); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->adv_coding = (t_u32)woal_string_to_number(pos); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->tx_bf = (t_u32)woal_string_to_number(pos); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->gf_mode = (t_u32)woal_string_to_number(pos); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->stbc = (t_u32)woal_string_to_number(pos); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->NumPkt = (t_u32)woal_string_to_number(pos); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->MaxPE = (t_u32)woal_string_to_number(pos); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->BeamChange = (t_u32)woal_string_to_number(pos); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->Dcm = (t_u32)woal_string_to_number(pos); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->Doppler = (t_u32)woal_string_to_number(pos); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->MidP = (t_u32)woal_string_to_number(pos); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->QNum = (t_u32)woal_string_to_number(pos); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) { |
| for (i = 0; i < ETH_ALEN; i++) { |
| pos = strsep(&string, ":"); |
| if (pos) |
| d->bssid[i] = woal_atox(pos); |
| } |
| } |
| |
| if ((d->enable > 1) |
| || (d->frame_length == 0) || (d->adjust_burst_sifs > 1) |
| || (d->burst_sifs_in_us > 255) || (d->short_preamble > 1) |
| || (d->act_sub_ch == 2 || d->act_sub_ch > 3) |
| || (d->short_gi > 1) || (d->adv_coding > 1) || (d->tx_bf > 1) |
| || (d->gf_mode > 1) || (d->stbc > 1)) |
| ret = -EINVAL; |
| done: |
| kfree(tmp); |
| LEAVE(); |
| return ret; |
| } |
| |
| /* |
| * @brief Parse mfg cmd HE TB Tx string |
| * |
| * @param s A pointer to user buffer |
| * @param len Length of user buffer |
| * @param d A pointer to mfg_Cmd_HE_TBTx_t struct |
| * @return 0 on success, -EINVAL otherwise |
| */ |
| static int |
| parse_he_tb_tx_string(const char *s, size_t len, struct mfg_Cmd_HE_TBTx_t *d) |
| { |
| int ret = MLAN_STATUS_SUCCESS; |
| char *string = NULL; |
| char *tmp = NULL; |
| char *pos = NULL; |
| gfp_t flag; |
| |
| ENTER(); |
| if (!s || !d) { |
| LEAVE(); |
| return -EINVAL; |
| } |
| flag = (in_atomic() || irqs_disabled())? GFP_ATOMIC : GFP_KERNEL; |
| string = kzalloc(HE_TB_TX_STR_LEN, flag); |
| if (string == NULL) |
| return -ENOMEM; |
| |
| moal_memcpy_ext(NULL, string, s + strlen("he_tb_tx="), |
| len - strlen("he_tb_tx="), HE_TB_TX_STR_LEN - 1); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->enable = (t_u32)woal_string_to_number(pos); |
| |
| if (d->enable == MFALSE) |
| goto done; |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->qnum = (t_u32)woal_string_to_number(pos); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->aid = (t_u32)woal_string_to_number(pos); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->axq_mu_timer = (t_u32)woal_string_to_number(pos); |
| |
| pos = strsep(&string, " \t"); |
| if (pos) |
| d->tx_power = (t_u16)woal_string_to_number(pos); |
| |
| if (d->enable > 1) |
| ret = -EINVAL; |
| |
| done: |
| kfree(tmp); |
| LEAVE(); |
| return ret; |
| } |
| |
| /* |
| * @brief This function enables/disables RF test mode in firmware |
| * |
| * @param handle A pointer to moal_handle structure |
| * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING on success, |
| * otherwise failure code |
| */ |
| mlan_status |
| woal_process_rf_test_mode(moal_handle *handle, t_u32 mode) |
| { |
| mlan_status ret = MLAN_STATUS_FAILURE; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| t_u32 flag = 0; |
| |
| ENTER(); |
| #ifdef MFG_CMD_SUPPORT |
| if (mfg_mode) { |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| if (mode != MFG_CMD_SET_TEST_MODE && mode != MFG_CMD_UNSET_TEST_MODE) { |
| LEAVE(); |
| return ret; |
| } |
| |
| 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_RF_TEST_GENERIC; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| req->action = MLAN_ACT_SET; |
| if (mode == MFG_CMD_SET_TEST_MODE) |
| misc->param.mfg_generic_cfg.mfg_cmd = |
| MFG_CMD_SET_TEST_MODE; |
| ret = woal_request_ioctl(woal_get_priv(handle, |
| MLAN_BSS_ROLE_ANY), |
| req, MOAL_IOCTL_WAIT); |
| } |
| |
| if (ret == MLAN_STATUS_SUCCESS && mode == MFG_CMD_SET_TEST_MODE |
| && handle->rf_data == NULL) { |
| flag = (in_atomic() || irqs_disabled())? |
| GFP_ATOMIC : GFP_KERNEL; |
| /* Allocate memory to hold RF test mode data */ |
| handle->rf_data = kzalloc(sizeof(struct rf_test_mode_data), |
| flag); |
| if (!handle->rf_data) |
| PRINTM(MERROR, |
| "Couldn't allocate memory for RF test mode\n"); |
| handle->rf_test_mode = MTRUE; |
| if (handle->rf_data) { |
| /* antenna is set to 1 by default */ |
| handle->rf_data->tx_antenna = 1; |
| handle->rf_data->rx_antenna = 1; |
| } |
| } else if (mode == MFG_CMD_UNSET_TEST_MODE) { |
| if (handle->rf_data) { |
| /* Free RF test mode data memory */ |
| kfree(handle->rf_data); |
| handle->rf_data = NULL; |
| } |
| handle->rf_test_mode = MFALSE; |
| } |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief This function sends RF test mode command in firmware |
| * |
| * @param handle A pointer to moal_handle structure |
| * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING on success, |
| * otherwise failure code |
| */ |
| mlan_status |
| woal_process_rf_test_mode_cmd(moal_handle *handle, t_u32 cmd, |
| const char *buffer, size_t len, |
| t_u32 action, t_u32 val) |
| { |
| mlan_status ret = MLAN_STATUS_FAILURE; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| int err = MFALSE; |
| int i; |
| |
| ENTER(); |
| |
| if (!handle->rf_test_mode || !handle->rf_data) |
| goto done; |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (!req) |
| goto done; |
| |
| misc = (mlan_ds_misc_cfg *)req->pbuf; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| misc->sub_command = MLAN_OID_MISC_RF_TEST_GENERIC; |
| req->action = action; |
| |
| switch (cmd) { |
| case MFG_CMD_TX_ANT: |
| if (val != 1 && val != 2 && val != 3) |
| err = MTRUE; |
| break; |
| case MFG_CMD_RX_ANT: |
| if (val != 1 && val != 2 && val != 3) |
| err = MTRUE; |
| break; |
| case MFG_CMD_RF_BAND_AG: |
| if (val != 0 && val != 1) |
| err = MTRUE; |
| break; |
| case MFG_CMD_RF_CHANNELBW: |
| if (val != 0 |
| && val != 1 |
| && (val != 4 |
| || (val == 4 && handle->rf_data->band == BAND_2GHZ)) |
| ) |
| err = MTRUE; |
| break; |
| case MFG_CMD_RF_CHAN: |
| break; |
| case MFG_CMD_CLR_RX_ERR: |
| break; |
| case MFG_CMD_RADIO_MODE_CFG: |
| if (parse_radio_mode_string(buffer, len, |
| &misc->param.mfg_generic_cfg)) |
| err = MTRUE; |
| break; |
| case MFG_CMD_RFPWR: |
| if (parse_tx_pwr_string(buffer, len, |
| &misc->param.mfg_generic_cfg)) |
| err = MTRUE; |
| break; |
| case MFG_CMD_TX_CONT: |
| misc->sub_command = MLAN_OID_MISC_RF_TEST_TX_CONT; |
| if (parse_tx_cont_string(buffer, len, &misc->param.mfg_tx_cont)) |
| err = MTRUE; |
| break; |
| case MFG_CMD_TX_FRAME: |
| misc->sub_command = MLAN_OID_MISC_RF_TEST_TX_FRAME; |
| if (parse_tx_frame_string(buffer, len, |
| &misc->param.mfg_tx_frame2)) |
| err = MTRUE; |
| break; |
| case MFG_CMD_CONFIG_MAC_HE_TB_TX: |
| misc->sub_command = MLAN_OID_MISC_RF_TEST_HE_POWER; |
| if (parse_he_tb_tx_string(buffer, len, |
| &misc->param.mfg_he_power)) |
| err = MTRUE; |
| break; |
| default: |
| err = MTRUE; |
| } |
| |
| if (!err) { |
| misc->param.mfg_generic_cfg.mfg_cmd = (t_u32)cmd; |
| if (cmd != MFG_CMD_RFPWR && |
| misc->sub_command == MLAN_OID_MISC_RF_TEST_GENERIC) |
| misc->param.mfg_generic_cfg.data1 = val; |
| |
| ret = woal_request_ioctl(woal_get_priv(handle, |
| MLAN_BSS_ROLE_ANY), |
| req, MOAL_IOCTL_WAIT); |
| } |
| if (ret != MLAN_STATUS_SUCCESS) |
| goto done; |
| |
| switch (cmd) { |
| case MFG_CMD_TX_ANT: |
| handle->rf_data->tx_antenna = misc->param.mfg_generic_cfg.data1; |
| break; |
| case MFG_CMD_RX_ANT: |
| handle->rf_data->rx_antenna = misc->param.mfg_generic_cfg.data1; |
| break; |
| case MFG_CMD_RADIO_MODE_CFG: |
| handle->rf_data->radio_mode[0] = |
| misc->param.mfg_generic_cfg.data1; |
| handle->rf_data->radio_mode[1] = |
| misc->param.mfg_generic_cfg.data2; |
| break; |
| case MFG_CMD_RF_BAND_AG: |
| handle->rf_data->band = misc->param.mfg_generic_cfg.data1; |
| /* set fw default bw and channel config on band change */ |
| handle->rf_data->bandwidth = CHANNEL_BW_20MHZ; |
| if (handle->rf_data->band == BAND_2GHZ) |
| handle->rf_data->channel = 6; |
| else if (handle->rf_data->band == BAND_5GHZ) |
| handle->rf_data->channel = 36; |
| break; |
| case MFG_CMD_RF_CHANNELBW: |
| handle->rf_data->bandwidth = misc->param.mfg_generic_cfg.data1; |
| break; |
| case MFG_CMD_RF_CHAN: |
| handle->rf_data->channel = misc->param.mfg_generic_cfg.data1; |
| break; |
| case MFG_CMD_CLR_RX_ERR: |
| handle->rf_data->rx_tot_pkt_count = |
| misc->param.mfg_generic_cfg.data1; |
| handle->rf_data->rx_mcast_bcast_pkt_count = |
| misc->param.mfg_generic_cfg.data2; |
| handle->rf_data->rx_pkt_fcs_err_count = |
| misc->param.mfg_generic_cfg.data3; |
| break; |
| case MFG_CMD_RFPWR: |
| handle->rf_data->tx_power_data[0] = |
| misc->param.mfg_generic_cfg.data1; |
| handle->rf_data->tx_power_data[1] = |
| misc->param.mfg_generic_cfg.data2; |
| handle->rf_data->tx_power_data[2] = |
| misc->param.mfg_generic_cfg.data3; |
| break; |
| case MFG_CMD_TX_CONT: |
| handle->rf_data->tx_cont_data[0] = |
| misc->param.mfg_tx_cont.enable_tx; |
| handle->rf_data->tx_cont_data[1] = |
| misc->param.mfg_tx_cont.cw_mode; |
| handle->rf_data->tx_cont_data[2] = |
| misc->param.mfg_tx_cont.payload_pattern; |
| handle->rf_data->tx_cont_data[3] = |
| misc->param.mfg_tx_cont.cs_mode; |
| handle->rf_data->tx_cont_data[4] = |
| misc->param.mfg_tx_cont.act_sub_ch; |
| handle->rf_data->tx_cont_data[5] = |
| misc->param.mfg_tx_cont.tx_rate; |
| break; |
| case MFG_CMD_TX_FRAME: |
| handle->rf_data->tx_frame_data[0] = |
| misc->param.mfg_tx_frame2.enable; |
| handle->rf_data->tx_frame_data[1] = |
| misc->param.mfg_tx_frame2.data_rate; |
| handle->rf_data->tx_frame_data[2] = |
| misc->param.mfg_tx_frame2.frame_pattern; |
| handle->rf_data->tx_frame_data[3] = |
| misc->param.mfg_tx_frame2.frame_length; |
| handle->rf_data->tx_frame_data[4] = |
| misc->param.mfg_tx_frame2.adjust_burst_sifs; |
| handle->rf_data->tx_frame_data[5] = |
| misc->param.mfg_tx_frame2.burst_sifs_in_us; |
| handle->rf_data->tx_frame_data[6] = |
| misc->param.mfg_tx_frame2.short_preamble; |
| handle->rf_data->tx_frame_data[7] = |
| misc->param.mfg_tx_frame2.act_sub_ch; |
| handle->rf_data->tx_frame_data[8] = |
| misc->param.mfg_tx_frame2.short_gi; |
| handle->rf_data->tx_frame_data[9] = |
| misc->param.mfg_tx_frame2.adv_coding; |
| handle->rf_data->tx_frame_data[10] = |
| misc->param.mfg_tx_frame2.tx_bf; |
| handle->rf_data->tx_frame_data[11] = |
| misc->param.mfg_tx_frame2.gf_mode; |
| handle->rf_data->tx_frame_data[12] = |
| misc->param.mfg_tx_frame2.stbc; |
| handle->rf_data->tx_frame_data[13] = |
| misc->param.mfg_tx_frame2.NumPkt; |
| handle->rf_data->tx_frame_data[14] = |
| misc->param.mfg_tx_frame2.MaxPE; |
| handle->rf_data->tx_frame_data[15] = |
| misc->param.mfg_tx_frame2.BeamChange; |
| handle->rf_data->tx_frame_data[16] = |
| misc->param.mfg_tx_frame2.Dcm; |
| handle->rf_data->tx_frame_data[17] = |
| misc->param.mfg_tx_frame2.Doppler; |
| handle->rf_data->tx_frame_data[18] = |
| misc->param.mfg_tx_frame2.MidP; |
| handle->rf_data->tx_frame_data[19] = |
| misc->param.mfg_tx_frame2.QNum; |
| for (i = 0; i < ETH_ALEN; i++) { |
| handle->rf_data->bssid[i] = |
| misc->param.mfg_tx_frame2.bssid[i]; |
| } |
| break; |
| case MFG_CMD_CONFIG_MAC_HE_TB_TX: |
| handle->rf_data->he_tb_tx[0] = misc->param.mfg_he_power.enable; |
| handle->rf_data->he_tb_tx[1] = misc->param.mfg_he_power.qnum; |
| handle->rf_data->he_tb_tx[2] = misc->param.mfg_he_power.aid; |
| handle->rf_data->he_tb_tx[3] = |
| misc->param.mfg_he_power.axq_mu_timer; |
| handle->rf_data->he_tb_tx[4] = |
| misc->param.mfg_he_power.tx_power; |
| break; |
| } |
| done: |
| if (err || ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| #endif /* RF_TEST_MODE */ |