| |
| /** @file moal_eth_ioctl.c |
| * |
| * @brief This file contains private ioctl functions |
| |
| * |
| * Copyright 2014-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: |
| 01/05/2012: initial version |
| ************************************************************************/ |
| |
| #include "moal_main.h" |
| #include "moal_eth_ioctl.h" |
| #include "mlan_ioctl.h" |
| #if defined(STA_WEXT) || defined(UAP_WEXT) |
| #include "moal_priv.h" |
| #endif |
| |
| #if defined(STA_CFG80211) || defined(UAP_CFG80211) |
| #include "moal_cfg80211.h" |
| #endif |
| #ifdef UAP_SUPPORT |
| #include "moal_uap.h" |
| #endif |
| #ifdef USB |
| #include "moal_usb.h" |
| #endif |
| #ifdef SDIO |
| #include "moal_sdio.h" |
| #endif |
| #ifdef PCIE |
| #include "moal_pcie.h" |
| #endif |
| #ifdef STA_CFG80211 |
| #include "moal_sta_cfg80211.h" |
| #endif |
| #ifdef STA_CFG80211 |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) |
| #include "moal_cfg80211_util.h" |
| #endif |
| #endif |
| |
| /******************************************************** |
| Local Variables |
| ********************************************************/ |
| |
| /** Bands supported in Infra mode */ |
| static t_u16 SupportedInfraBand[] = { |
| BAND_B, |
| BAND_B | BAND_G, |
| BAND_G, |
| BAND_GN, |
| BAND_B | BAND_G | BAND_GN, |
| BAND_G | BAND_GN, |
| BAND_A, |
| BAND_B | BAND_A, |
| BAND_B | BAND_G | BAND_A, |
| BAND_G | BAND_A, |
| BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN, |
| BAND_A | BAND_G | BAND_AN | BAND_GN, |
| BAND_A | BAND_AN, |
| BAND_GN | BAND_GAC, |
| BAND_B | BAND_G | BAND_GN | BAND_GAC, |
| BAND_G | BAND_GN | BAND_GAC, |
| BAND_GN | BAND_GAC | BAND_GAX, |
| BAND_B | BAND_G | BAND_GN | BAND_GAC | BAND_GAX, |
| BAND_G | BAND_GN | BAND_GAC | BAND_GAX, |
| BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN | BAND_AAC, |
| BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN | BAND_AAC | BAND_GAC, |
| BAND_A | BAND_G | BAND_AN | BAND_GN | BAND_AAC, |
| BAND_A | BAND_AN | BAND_AAC, |
| BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN | BAND_AAC | BAND_AAX, |
| BAND_A | BAND_B | BAND_G | BAND_AN | BAND_GN | BAND_AAC | BAND_GAC | |
| BAND_AAX, |
| BAND_A | BAND_G | BAND_AN | BAND_GN | BAND_AAC | BAND_AAX, |
| BAND_A | BAND_AN | BAND_AAC | BAND_AAX, |
| }; |
| |
| /** Bands supported in Ad-Hoc mode */ |
| static t_u8 SupportedAdhocBand[] = { |
| BAND_B, |
| BAND_B | BAND_G, |
| BAND_G, |
| BAND_A, |
| }; |
| |
| /******************************************************** |
| 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 Parse a string to extract numerical arguments |
| * |
| * @param pos Pointer to the arguments string |
| * @param data Pointer to the arguments buffer |
| * @param datalen Length of the arguments buffer |
| * @param user_data_len Pointer to the number of arguments extracted |
| * |
| * @return MLAN_STATUS_SUCCESS |
| */ |
| static mlan_status |
| parse_arguments(t_u8 *pos, int *data, int datalen, int *user_data_len) |
| { |
| int i, j, k; |
| char cdata[10]; |
| int is_hex = 0; |
| |
| if (strlen(pos) == 0) { |
| *user_data_len = 0; |
| return MLAN_STATUS_SUCCESS; |
| } |
| |
| memset(cdata, 0, sizeof(cdata)); |
| for (i = 0, j = 0, k = 0; i <= (int)strlen(pos); i++) { |
| if ((k == 0) && (i <= (int)(strlen(pos) - 2))) { |
| if ((pos[i] == '0') && (pos[i + 1] == 'x')) { |
| is_hex = 1; |
| i = i + 2; |
| } |
| } |
| if (pos[i] == '\0' || pos[i] == ' ') { |
| if (j >= datalen) { |
| j++; |
| break; |
| } |
| if (is_hex) { |
| data[j] = woal_atox(cdata); |
| is_hex = 0; |
| } else { |
| woal_atoi(&data[j], cdata); |
| } |
| j++; |
| k = 0; |
| memset(cdata, 0, sizeof(cdata)); |
| if (pos[i] == '\0') |
| break; |
| } else { |
| if (k >= (int)sizeof(cdata)) { |
| PRINTM(MERROR, "Invalid numerical arguments\n"); |
| break; |
| } |
| cdata[k] = pos[i]; |
| k++; |
| } |
| } |
| |
| *user_data_len = j; |
| return MLAN_STATUS_SUCCESS; |
| } |
| |
| #if defined(STA_CFG80211) && defined(UAP_CFG80211) |
| /** |
| * @brief Set wps & p2p ie in AP mode |
| * |
| * @param priv Pointer to priv stucture |
| * @param ie Pointer to ies data |
| * @param len Length of data |
| * |
| * @return MLAN_STATUS_SUCCESS -- success, otherwise fail |
| */ |
| mlan_status |
| woal_set_ap_wps_p2p_ie(moal_private *priv, t_u8 *ie, size_t len) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u8 *pos = ie; |
| int ie_len; |
| |
| ENTER(); |
| |
| ie_len = len - 2; |
| if (ie_len <= 0) { |
| PRINTM(MERROR, "IE len error: %d\n", ie_len); |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| /* Android cmd format: |
| * "SET_AP_WPS_P2P_IE 1" -- beacon IE |
| * "SET_AP_WPS_P2P_IE 2" -- proberesp IE |
| * "SET_AP_WPS_P2P_IE 4" -- assocresp IE |
| */ |
| if (*pos == '1') { |
| /* set the beacon wps/p2p ies */ |
| pos += 2; |
| if (MLAN_STATUS_SUCCESS != |
| woal_cfg80211_mgmt_frame_ie(priv, pos, ie_len, NULL, 0, |
| NULL, 0, NULL, 0, |
| MGMT_MASK_BEACON_WPS_P2P, |
| MOAL_IOCTL_WAIT)) { |
| PRINTM(MERROR, "Failed to set beacon wps/p2p ie\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| } else if (*pos == '2') { |
| /* set the probe resp ies */ |
| pos += 2; |
| if (MLAN_STATUS_SUCCESS != |
| woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, pos, ie_len, |
| NULL, 0, NULL, 0, |
| MGMT_MASK_PROBE_RESP, |
| MOAL_IOCTL_WAIT)) { |
| PRINTM(MERROR, "Failed to set probe resp ie\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| } else if (*pos == '4') { |
| /* set the assoc resp ies */ |
| pos += 2; |
| if (MLAN_STATUS_SUCCESS != |
| woal_cfg80211_mgmt_frame_ie(priv, NULL, 0, NULL, 0, pos, |
| ie_len, NULL, 0, |
| MGMT_MASK_ASSOC_RESP, |
| MOAL_IOCTL_WAIT)) { |
| PRINTM(MERROR, "Failed to set assoc resp ie\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| } |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| |
| #ifdef WIFI_DIRECT_SUPPORT |
| #if defined(STA_CFG80211) || defined(UAP_CFG80211) |
| /** |
| * @brief Set miracast mode |
| * |
| * @param priv Pointer to priv stucture |
| * @param pdata Pointer to cmd buffer |
| * @param len Length of data |
| * |
| * @return MLAN_STATUS_SUCCESS -- success, otherwise fail |
| */ |
| static mlan_status |
| woal_set_miracast_mode(moal_private *priv, t_u8 *pdata, size_t len) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| t_u8 *pos = pdata; |
| |
| ENTER(); |
| if (!pos || (len == 0)) { |
| PRINTM(MERROR, "%s: Null buf!\n", __func__); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| while (!isdigit(*pos) && --len > 0) |
| pos++; |
| switch (*pos) { |
| case '0': |
| /* disable miracast mode */ |
| priv->phandle->miracast_mode = 0; |
| break; |
| case '1': |
| /* Source */ |
| priv->phandle->miracast_mode = 1; |
| break; |
| case '2': |
| /* Sink */ |
| priv->phandle->miracast_mode = 2; |
| break; |
| default: |
| PRINTM(MERROR, "%s: Unknown miracast mode (%c)\n", |
| priv->netdev->name, *pos); |
| ret = MLAN_STATUS_FAILURE; |
| break; |
| } |
| done: |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| #endif |
| |
| /** |
| * @brief Get Driver Version |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_get_priv_driver_version(moal_private *priv, t_u8 *respbuf, |
| t_u32 respbuflen) |
| { |
| int len = 0, ret = -1; |
| char buf[MLAN_MAX_VER_STR_LEN]; |
| |
| ENTER(); |
| |
| if (!respbuf) { |
| LEAVE(); |
| return 0; |
| } |
| |
| memset(buf, 0, sizeof(buf)); |
| |
| /* Get version string to local buffer */ |
| woal_get_version(priv->phandle, buf, sizeof(buf) - 1); |
| len = strlen(buf); |
| |
| if (len) { |
| /* Copy back the retrieved version string */ |
| PRINTM(MINFO, "MOAL VERSION: %s\n", buf); |
| ret = MIN(len, (int)(respbuflen - 1)); |
| moal_memcpy_ext(priv->phandle, respbuf, buf, ret, |
| respbuflen - 1); |
| } else { |
| ret = -1; |
| PRINTM(MERROR, "Get version failed!\n"); |
| } |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Hostcmd interface from application |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * @param wait_option Wait option |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| int |
| woal_priv_hostcmd(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen, |
| t_u8 wait_option) |
| { |
| int ret = 0; |
| t_u8 *data_ptr; |
| t_u32 buf_len = 0; |
| HostCmd_Header cmd_header; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *misc_cfg = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_HOSTCMD)); |
| buf_len = *((t_u32 *)data_ptr); |
| moal_memcpy_ext(priv->phandle, &cmd_header, data_ptr + sizeof(buf_len), |
| sizeof(HostCmd_Header), sizeof(HostCmd_Header)); |
| |
| PRINTM(MINFO, "Host command len = %d\n", |
| woal_le16_to_cpu(cmd_header.size)); |
| if (woal_le16_to_cpu(cmd_header.size) > MRVDRV_SIZE_OF_CMD_BUFFER) { |
| LEAVE(); |
| return -EINVAL; |
| } |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto error; |
| } |
| misc_cfg = (mlan_ds_misc_cfg *)req->pbuf; |
| misc_cfg->sub_command = MLAN_OID_MISC_HOST_CMD; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| req->action = MLAN_ACT_SET; |
| misc_cfg->param.hostcmd.len = woal_le16_to_cpu(cmd_header.size); |
| /* get the whole command */ |
| moal_memcpy_ext(priv->phandle, misc_cfg->param.hostcmd.cmd, |
| data_ptr + sizeof(buf_len), misc_cfg->param.hostcmd.len, |
| MRVDRV_SIZE_OF_CMD_BUFFER); |
| |
| status = woal_request_ioctl(priv, req, wait_option); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto error; |
| } |
| ret = misc_cfg->param.hostcmd.len + sizeof(buf_len) + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_HOSTCMD); |
| if (ret > (int)respbuflen) { |
| ret = -EFAULT; |
| goto error; |
| } |
| moal_memcpy_ext(priv->phandle, data_ptr + sizeof(buf_len), |
| misc_cfg->param.hostcmd.cmd, |
| misc_cfg->param.hostcmd.len, |
| respbuflen - (strlen(CMD_NXP) + |
| strlen(PRIV_CMD_HOSTCMD) + |
| sizeof(buf_len))); |
| moal_memcpy_ext(priv->phandle, data_ptr, |
| (t_u8 *)&misc_cfg->param.hostcmd.len, sizeof(t_u32), |
| sizeof(t_u32)); |
| |
| error: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief configure 11ax HE capability or HE operation |
| * |
| * |
| * @param priv Pointer to the mlan_private driver data struct |
| * @param respbuf A pointer to response buffer |
| * @param len length used |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written if successful else negative value |
| */ |
| static int |
| woal_setget_priv_11axcmdcfg(moal_private *priv, t_u8 *respbuf, |
| t_u32 respbuflen, t_u8 wait_option) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_11ax_cmd_cfg *cfg = NULL; |
| int ret = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| int header_len = 0, user_data_len = 0; |
| int data[3] = { 0 }; |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ax_cmd_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| req->req_id = MLAN_IOCTL_11AX_CFG; |
| req->action = MLAN_ACT_SET; |
| |
| cfg = (mlan_ds_11ax_cmd_cfg *) req->pbuf; |
| cfg->sub_command = MLAN_OID_11AX_CMD_CFG; |
| |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| PRINTM(MINFO, "data_len=%d,data=%d,%d,%d\n", user_data_len, data[0], |
| data[1], data[2]); |
| |
| if (user_data_len > 3 || user_data_len == 0) { |
| PRINTM(MERROR, "Invalid parameters\n"); |
| ret = -EFAULT; |
| goto done; |
| } else if (user_data_len == 1) { |
| req->action = MLAN_ACT_GET; |
| } |
| |
| switch (data[0]) { |
| case MLAN_11AXCMD_CFG_ID_SR_OBSS_PD_OFFSET: |
| cfg->sub_id = MLAN_11AXCMD_SR_SUBID; |
| cfg->param.sr_cfg.type = MRVL_DOT11AX_OBSS_PD_OFFSET_TLV_ID; |
| cfg->param.sr_cfg.len = sizeof(mlan_11axcmdcfg_obss_pd_offset); |
| cfg->param.sr_cfg.param.obss_pd_offset.offset[0] = data[1]; |
| cfg->param.sr_cfg.param.obss_pd_offset.offset[1] = data[2]; |
| break; |
| case MLAN_11AXCMD_CFG_ID_SR_ENABLE: |
| cfg->sub_id = MLAN_11AXCMD_SR_SUBID; |
| cfg->param.sr_cfg.type = MRVL_DOT11AX_ENABLE_SR_TLV_ID; |
| cfg->param.sr_cfg.len = sizeof(mlan_11axcmdcfg_sr_control); |
| cfg->param.sr_cfg.param.sr_control.control = data[1]; |
| break; |
| case MLAN_11AXCMD_CFG_ID_BEAM_CHANGE: |
| cfg->sub_id = MLAN_11AXCMD_BEAM_SUBID; |
| cfg->param.beam_cfg.value = data[1]; |
| break; |
| case MLAN_11AXCMD_CFG_ID_HTC_ENABLE: |
| cfg->sub_id = MLAN_11AXCMD_HTC_SUBID; |
| cfg->param.htc_cfg.value = data[1]; |
| break; |
| case MLAN_11AXCMD_CFG_ID_TXOP_RTS: |
| cfg->sub_id = MLAN_11AXCMD_TXOPRTS_SUBID; |
| cfg->param.txop_cfg.rts_thres = data[1]; |
| break; |
| case MLAN_11AXCMD_CFG_ID_TX_OMI: |
| cfg->sub_id = MLAN_11AXCMD_TXOMI_SUBID; |
| cfg->param.txomi_cfg.omi = data[1]; |
| break; |
| case MLAN_11AXCMD_CFG_ID_OBSSNBRU_TOLTIME: |
| cfg->sub_id = MLAN_11AXCMD_OBSS_TOLTIME_SUBID; |
| cfg->param.toltime_cfg.tol_time = data[1]; |
| break; |
| default: |
| PRINTM(MERROR, "unknown 11axcmd\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| moal_memcpy_ext(priv->phandle, respbuf, &req->action, |
| sizeof(req->action), sizeof(req->action)); |
| respbuf += sizeof(req->action); |
| |
| cfg = (mlan_ds_11ax_cmd_cfg *) respbuf; |
| moal_memcpy_ext(priv->phandle, cfg, req->pbuf, |
| sizeof(mlan_ds_11ax_cmd_cfg), respbuflen); |
| |
| ret = sizeof(req->action) + sizeof(mlan_ds_11ax_cmd_cfg); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/get range ext mode |
| * |
| * |
| * @param priv Pointer to the mlan_private driver data struct |
| * @param respbuf A pointer to response buffer |
| * @param len length used |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written if successful else negative value |
| */ |
| static int |
| woal_setget_priv_range_ext(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| int ret = 0; |
| int data[1]; |
| int header_len = 0, user_data_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (!respbuf) { |
| PRINTM(MERROR, "response buffer is not available!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RANGE_EXT); |
| user_data_len = strlen(respbuf) - header_len; |
| |
| /* Allocate an IOCTL request buffer */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| /* Fill request buffer */ |
| misc = (mlan_ds_misc_cfg *)req->pbuf; |
| misc->sub_command = MLAN_OID_MISC_RANGE_EXT; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| req->action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| if (user_data_len != 1) { |
| PRINTM(MERROR, "Invalid Parameter\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| if (data[0] < 0 || data[0] > 2) { |
| PRINTM(MERROR, |
| "Invalid Parameter: range_ext mode 0-2\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| misc->param.range_ext_mode = (t_u8)data[0]; |
| 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; |
| } |
| |
| data[0] = misc->param.range_ext_mode; |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u32 *)data, sizeof(data), |
| respbuflen); |
| ret = sizeof(data); |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Custom IE setting |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_customie(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| t_u8 *data_ptr; |
| mlan_ioctl_req *ioctl_req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| mlan_ds_misc_custom_ie *pcustom_ie = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_CUSTOMIE)); |
| |
| pcustom_ie = (mlan_ds_misc_custom_ie *)data_ptr; |
| ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (ioctl_req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| misc = (mlan_ds_misc_cfg *)ioctl_req->pbuf; |
| misc->sub_command = MLAN_OID_MISC_CUSTOM_IE; |
| ioctl_req->req_id = MLAN_IOCTL_MISC_CFG; |
| if ((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; |
| } |
| pcustom_ie = (mlan_ds_misc_custom_ie *)data_ptr; |
| moal_memcpy_ext(priv->phandle, pcustom_ie, &misc->param.cust_ie, |
| sizeof(mlan_ds_misc_custom_ie), |
| respbuflen - |
| (strlen(CMD_NXP) + strlen(PRIV_CMD_CUSTOMIE))); |
| ret = sizeof(mlan_ds_misc_custom_ie); |
| if (ioctl_req->status_code == MLAN_ERROR_IOCTL_FAIL) { |
| /* send a separate error code to indicate error from driver */ |
| ret = EFAULT; |
| } |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(ioctl_req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get Band and Adhoc-band setting |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_setget_priv_bandcfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| unsigned int i; |
| int data[3]; |
| int user_data_len = 0; |
| t_u32 infra_band = 0; |
| t_u32 adhoc_band = 0; |
| t_u32 adhoc_channel = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_radio_cfg *radio_cfg = NULL; |
| mlan_ds_band_cfg *band_cfg = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_BANDCFG))) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| memset((char *)data, 0, sizeof(data)); |
| parse_arguments(respbuf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_BANDCFG), |
| data, ARRAY_SIZE(data), &user_data_len); |
| } |
| |
| if (sizeof(int) * user_data_len > sizeof(data)) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| LEAVE(); |
| return -EINVAL; |
| } |
| |
| if (user_data_len > 0) { |
| if (priv->media_connected == MTRUE) { |
| LEAVE(); |
| return -EOPNOTSUPP; |
| } |
| } |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto error; |
| } |
| radio_cfg = (mlan_ds_radio_cfg *)req->pbuf; |
| radio_cfg->sub_command = MLAN_OID_BAND_CFG; |
| req->req_id = MLAN_IOCTL_RADIO_CFG; |
| |
| if (user_data_len == 0) { |
| /* Get config_bands, adhoc_start_band and adhoc_channel values |
| * from MLAN |
| */ |
| req->action = MLAN_ACT_GET; |
| } else { |
| /* To support only <b/bg/bgn/n/aac/gac> */ |
| infra_band = data[0]; |
| for (i = 0; i < (sizeof(SupportedInfraBand) / |
| sizeof(SupportedInfraBand[0])); i++) |
| if (infra_band == SupportedInfraBand[i]) |
| break; |
| if (i == sizeof(SupportedInfraBand)) { |
| ret = -EINVAL; |
| goto error; |
| } |
| |
| /* Set Adhoc band */ |
| if (user_data_len >= 2) { |
| adhoc_band = data[1]; |
| for (i = 0; i < sizeof(SupportedAdhocBand); i++) |
| if (adhoc_band == SupportedAdhocBand[i]) |
| break; |
| if (i == sizeof(SupportedAdhocBand)) { |
| ret = -EINVAL; |
| goto error; |
| } |
| } |
| |
| /* Set Adhoc channel */ |
| if (user_data_len >= 3) { |
| adhoc_channel = data[2]; |
| if (adhoc_channel == 0) { |
| /* Check if specified adhoc channel is non-zero |
| */ |
| ret = -EINVAL; |
| goto error; |
| } |
| } |
| /* Set config_bands and adhoc_start_band values to MLAN */ |
| req->action = MLAN_ACT_SET; |
| radio_cfg->param.band_cfg.config_bands = infra_band; |
| radio_cfg->param.band_cfg.adhoc_start_band = adhoc_band; |
| radio_cfg->param.band_cfg.adhoc_channel = adhoc_channel; |
| } |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto error; |
| } |
| |
| band_cfg = (mlan_ds_band_cfg *)respbuf; |
| |
| moal_memcpy_ext(priv->phandle, band_cfg, &radio_cfg->param.band_cfg, |
| sizeof(mlan_ds_band_cfg), respbuflen); |
| |
| ret = sizeof(mlan_ds_band_cfg); |
| |
| error: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get 11n configurations |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_setget_priv_httxcfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| t_u32 data[2]; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_11n_cfg *cfg_11n = NULL; |
| int ret = 0; |
| int user_data_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_HTTXCFG))) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| memset((char *)data, 0, sizeof(data)); |
| parse_arguments(respbuf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_HTTXCFG), |
| data, ARRAY_SIZE(data), &user_data_len); |
| } |
| |
| if (user_data_len > 2) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| cfg_11n = (mlan_ds_11n_cfg *)req->pbuf; |
| cfg_11n->sub_command = MLAN_OID_11N_CFG_TX; |
| req->req_id = MLAN_IOCTL_11N_CFG; |
| |
| if (user_data_len == 0) { |
| /* Get 11n tx parameters from MLAN */ |
| req->action = MLAN_ACT_GET; |
| cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BG; |
| } else { |
| cfg_11n->param.tx_cfg.httxcap = data[0]; |
| PRINTM(MINFO, "SET: httxcap:0x%x\n", data[0]); |
| cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_BOTH; |
| if (user_data_len == 2) { |
| if (data[1] != BAND_SELECT_BG && |
| data[1] != BAND_SELECT_A && |
| data[1] != BAND_SELECT_BOTH) { |
| PRINTM(MERROR, "Invalid band selection\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| cfg_11n->param.tx_cfg.misc_cfg = data[1]; |
| PRINTM(MINFO, "SET: httxcap band:0x%x\n", data[1]); |
| } |
| /* Update 11n tx parameters in MLAN */ |
| req->action = MLAN_ACT_SET; |
| } |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| data[0] = cfg_11n->param.tx_cfg.httxcap; |
| PRINTM(MINFO, "GET: httxcap:0x%x\n", data[0]); |
| |
| if (req->action == MLAN_ACT_GET) { |
| cfg_11n->param.tx_cfg.httxcap = 0; |
| cfg_11n->param.tx_cfg.misc_cfg = BAND_SELECT_A; |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| data[1] = cfg_11n->param.tx_cfg.httxcap; |
| PRINTM(MINFO, "GET: httxcap for 5GHz:0x%x\n", data[1]); |
| } |
| |
| moal_memcpy_ext(priv->phandle, respbuf, data, sizeof(data), respbuflen); |
| ret = sizeof(data); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get 11n capability information |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_setget_priv_htcapinfo(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int data[2]; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_11n_cfg *cfg_11n = NULL; |
| woal_ht_cap_info *ht_cap = NULL; |
| int ret = 0; |
| int user_data_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_HTCAPINFO))) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| memset((char *)data, 0, sizeof(data)); |
| parse_arguments(respbuf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_HTCAPINFO), |
| data, ARRAY_SIZE(data), &user_data_len); |
| } |
| |
| if (user_data_len > 2) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| cfg_11n = (mlan_ds_11n_cfg *)req->pbuf; |
| cfg_11n->sub_command = MLAN_OID_11N_HTCAP_CFG; |
| req->req_id = MLAN_IOCTL_11N_CFG; |
| |
| if (user_data_len == 0) { |
| /* Get 11n tx parameters from MLAN */ |
| req->action = MLAN_ACT_GET; |
| cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_BG; |
| } else { |
| cfg_11n->param.htcap_cfg.htcap = data[0]; |
| PRINTM(MINFO, "SET: htcapinfo:0x%x\n", data[0]); |
| cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_BOTH; |
| if (user_data_len == 2) { |
| if (data[1] != BAND_SELECT_BG && |
| data[1] != BAND_SELECT_A && |
| data[1] != BAND_SELECT_BOTH) { |
| PRINTM(MERROR, "Invalid band selection\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| cfg_11n->param.htcap_cfg.misc_cfg = data[1]; |
| PRINTM(MINFO, "SET: htcapinfo band:0x%x\n", data[1]); |
| } |
| /* Update 11n tx parameters in MLAN */ |
| req->action = MLAN_ACT_SET; |
| } |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| data[0] = cfg_11n->param.htcap_cfg.htcap; |
| PRINTM(MINFO, "GET: htcapinfo for 2.4GHz:0x%x\n", data[0]); |
| |
| if (req->action == MLAN_ACT_GET) { |
| cfg_11n->param.htcap_cfg.htcap = 0; |
| cfg_11n->param.htcap_cfg.misc_cfg = BAND_SELECT_A; |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| data[1] = cfg_11n->param.htcap_cfg.htcap; |
| PRINTM(MINFO, "GET: htcapinfo for 5GHz:0x%x\n", data[1]); |
| } |
| |
| ht_cap = (woal_ht_cap_info *)respbuf; |
| ht_cap->ht_cap_info_bg = data[0]; |
| ht_cap->ht_cap_info_a = data[1]; |
| ret = sizeof(woal_ht_cap_info); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get add BA parameters |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_setget_priv_addbapara(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int data[5]; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_11n_cfg *cfg_11n = NULL; |
| woal_addba *addba = NULL; |
| int ret = 0; |
| int user_data_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_ADDBAPARA))) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| memset((char *)data, 0, sizeof(data)); |
| parse_arguments(respbuf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_ADDBAPARA), |
| data, ARRAY_SIZE(data), &user_data_len); |
| |
| if (user_data_len != ARRAY_SIZE(data)) { |
| PRINTM(MERROR, "Invalid number of arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (data[0] < 0 || data[0] > MLAN_DEFAULT_BLOCK_ACK_TIMEOUT) { |
| PRINTM(MERROR, "Incorrect addba timeout value.\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| if (data[1] <= 0 || data[1] > MLAN_AMPDU_MAX_TXWINSIZE || |
| data[2] <= 0 || data[2] > MLAN_AMPDU_MAX_RXWINSIZE) { |
| PRINTM(MERROR, "Incorrect Tx/Rx window size.\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| if (data[3] < 0 || data[3] > 1 || data[4] < 0 || data[4] > 1) { |
| PRINTM(MERROR, "Incorrect Tx/Rx amsdu.\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| } |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| cfg_11n = (mlan_ds_11n_cfg *)req->pbuf; |
| cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_PARAM; |
| req->req_id = MLAN_IOCTL_11N_CFG; |
| |
| if (user_data_len == 0) { |
| /* Get add BA parameters from MLAN */ |
| req->action = MLAN_ACT_GET; |
| } else { |
| cfg_11n->param.addba_param.timeout = data[0]; |
| cfg_11n->param.addba_param.txwinsize = data[1]; |
| cfg_11n->param.addba_param.rxwinsize = data[2]; |
| cfg_11n->param.addba_param.txamsdu = data[3]; |
| cfg_11n->param.addba_param.rxamsdu = data[4]; |
| PRINTM(MINFO, |
| "SET: timeout:%d txwinsize:%d rxwinsize:%d txamsdu=%d rxamsdu=%d\n", |
| data[0], data[1], data[2], data[3], data[4]); |
| /* Update add BA parameters in MLAN */ |
| req->action = MLAN_ACT_SET; |
| } |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| addba = (woal_addba *)respbuf; |
| |
| addba->time_out = cfg_11n->param.addba_param.timeout; |
| addba->tx_win_size = cfg_11n->param.addba_param.txwinsize; |
| addba->rx_win_size = cfg_11n->param.addba_param.rxwinsize; |
| addba->tx_amsdu = cfg_11n->param.addba_param.txamsdu; |
| addba->rx_amsdu = cfg_11n->param.addba_param.rxamsdu; |
| PRINTM(MINFO, |
| "GET: timeout:%d txwinsize:%d rxwinsize:%d txamsdu=%d, rxamsdu=%d\n", |
| addba->time_out, addba->tx_win_size, addba->rx_win_size, |
| addba->tx_amsdu, addba->rx_amsdu); |
| |
| ret = sizeof(woal_addba); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Delete selective BA based on parameters |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_delba(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| t_u32 data[2] = { 0xFF, 0xFF }; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_11n_cfg *cfg_11n = NULL; |
| mlan_ds_11n_delba *del_ba = NULL; |
| int ret = 0; |
| int user_data_len = 0; |
| int header_len = 0; |
| t_u8 *mac_pos = NULL; |
| t_u8 peer_mac[ETH_ALEN] = { 0 }; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DELBA); |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* Incorrect number of arguments */ |
| PRINTM(MERROR, "%d: Invalid arguments\n", __LINE__); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| mac_pos = strstr(respbuf + header_len, " "); |
| if (mac_pos) |
| mac_pos = strstr(mac_pos + 1, " "); |
| if (mac_pos) { |
| #define MAC_STRING_LENGTH 17 |
| if (strlen(mac_pos + 1) != MAC_STRING_LENGTH) { |
| PRINTM(MERROR, "%d: Invalid arguments\n", __LINE__); |
| ret = -EINVAL; |
| goto done; |
| } |
| woal_mac2u8(peer_mac, mac_pos + 1); |
| *mac_pos = '\0'; |
| } |
| |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| |
| if (mac_pos) |
| user_data_len++; |
| |
| if (user_data_len > 3 || (!(data[0] & (DELBA_TX | DELBA_RX))) || |
| (data[1] != DELBA_ALL_TIDS && !(data[1] <= 7))) { |
| /* Incorrect number of arguments */ |
| PRINTM(MERROR, "%d: Invalid arguments\n", __LINE__); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| cfg_11n = (mlan_ds_11n_cfg *)req->pbuf; |
| 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 = (t_u8)data[0]; |
| del_ba->tid = DELBA_ALL_TIDS; |
| if (user_data_len > 1) |
| del_ba->tid = (t_u8)data[1]; |
| if (user_data_len > 2) |
| moal_memcpy_ext(priv->phandle, del_ba->peer_mac_addr, peer_mac, |
| ETH_ALEN, MLAN_MAC_ADDR_LENGTH); |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| ret = sprintf(respbuf, "OK. BA deleted successfully.\n") + 1; |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get the reject addba requst conditions |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_rejectaddbareq(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| t_u32 data[1]; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_11n_cfg *cfg_11n = NULL; |
| int ret = 0; |
| int user_data_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (strlen(respbuf) == |
| (strlen(CMD_NXP) + strlen(PRIV_CMD_REJECTADDBAREQ))) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| memset((char *)data, 0, sizeof(data)); |
| parse_arguments(respbuf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_REJECTADDBAREQ), |
| data, ARRAY_SIZE(data), &user_data_len); |
| } |
| |
| if (user_data_len > 1) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| cfg_11n = (mlan_ds_11n_cfg *)req->pbuf; |
| cfg_11n->sub_command = MLAN_OID_11N_CFG_REJECT_ADDBA_REQ; |
| req->req_id = MLAN_IOCTL_11N_CFG; |
| |
| if (user_data_len == 0) { |
| /* Get the reject addba req conditions */ |
| req->action = MLAN_ACT_GET; |
| } else { |
| /* Set the reject addba req conditions */ |
| cfg_11n->param.reject_addba_req.conditions = data[0]; |
| 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; |
| } |
| if (req->action == MLAN_ACT_GET) { |
| sprintf(respbuf, "0x%x", |
| cfg_11n->param.reject_addba_req.conditions); |
| ret = strlen(respbuf) + 1; |
| } else { |
| ret = sprintf(respbuf, "OK\n") + 1; |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get the addba reject setting |
| * |
| * @param priv A pointer to moal_private structure |
| * @param action Action set or get |
| * @param addba_reject A pointer to addba_reject array. |
| * |
| * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, |
| * otherwise fail |
| */ |
| static mlan_status |
| woal_ioctl_addba_reject(moal_private *priv, t_u32 action, t_u8 *addba_reject) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_11n_cfg *cfg_11n = NULL; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| cfg_11n = (mlan_ds_11n_cfg *)req->pbuf; |
| cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_REJECT; |
| req->req_id = MLAN_IOCTL_11N_CFG; |
| |
| req->action = action; |
| if (action == MLAN_ACT_SET) |
| moal_memcpy_ext(priv->phandle, cfg_11n->param.addba_reject, |
| addba_reject, |
| sizeof(cfg_11n->param.addba_reject), |
| sizeof(cfg_11n->param.addba_reject)); |
| /* 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, addba_reject, |
| cfg_11n->param.addba_reject, |
| sizeof(cfg_11n->param.addba_reject), |
| MAX_NUM_TID); |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get addba prio_tbl |
| * |
| * @param priv A pointer to moal_private structure |
| * @param action Action set or get |
| * @param aggr_prio_tbl A pointer to mlan_ds_11n_aggr_prio_tbl. |
| * |
| * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, |
| * otherwise fail |
| */ |
| static mlan_status |
| woal_ioctl_aggr_prio_tbl(moal_private *priv, t_u32 action, |
| mlan_ds_11n_aggr_prio_tbl *aggr_prio_tbl) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_11n_cfg *cfg_11n = NULL; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| cfg_11n = (mlan_ds_11n_cfg *)req->pbuf; |
| cfg_11n->sub_command = MLAN_OID_11N_CFG_AGGR_PRIO_TBL; |
| req->req_id = MLAN_IOCTL_11N_CFG; |
| |
| req->action = action; |
| if (action == MLAN_ACT_SET) |
| moal_memcpy_ext(priv->phandle, &cfg_11n->param.aggr_prio_tbl, |
| aggr_prio_tbl, |
| sizeof(mlan_ds_11n_aggr_prio_tbl), |
| sizeof(mlan_ds_11n_aggr_prio_tbl)); |
| /* 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, aggr_prio_tbl, |
| &cfg_11n->param.aggr_prio_tbl, |
| sizeof(mlan_ds_11n_aggr_prio_tbl), |
| sizeof(mlan_ds_11n_aggr_prio_tbl)); |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get addba_param |
| * |
| * @param priv A pointer to moal_private structure |
| * @param action Action set or get |
| * @param addba_param A pointer to mlan_ds_11n_addba_param. |
| * |
| * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, |
| * otherwise fail |
| */ |
| static mlan_status |
| woal_ioctl_addba_param(moal_private *priv, t_u32 action, |
| mlan_ds_11n_addba_param *addba_param) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_11n_cfg *cfg_11n = NULL; |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| cfg_11n = (mlan_ds_11n_cfg *)req->pbuf; |
| cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_PARAM; |
| req->req_id = MLAN_IOCTL_11N_CFG; |
| |
| req->action = action; |
| if (action == MLAN_ACT_SET) |
| moal_memcpy_ext(priv->phandle, &cfg_11n->param.addba_param, |
| addba_param, sizeof(mlan_ds_11n_addba_param), |
| sizeof(mlan_ds_11n_addba_param)); |
| /* 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, addba_param, |
| &cfg_11n->param.addba_param, |
| sizeof(mlan_ds_11n_addba_param), |
| sizeof(mlan_ds_11n_addba_param)); |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Configuring rx block-ack window size |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return 0 --success, otherwise failure |
| */ |
| static int |
| woal_set_rx_ba_winsize(moal_private *priv, t_u8 *respbuf, int respbuflen) |
| { |
| int data[2]; |
| t_u8 addba_reject[MAX_NUM_TID]; |
| mlan_ds_11n_addba_param addba_param; |
| int ret = 0; |
| int user_data_len = 0; |
| |
| ENTER(); |
| |
| memset((char *)data, 0, sizeof(data)); |
| if (respbuf && strlen(respbuf) > 0) |
| parse_arguments(respbuf, data, ARRAY_SIZE(data), |
| &user_data_len); |
| |
| if (user_data_len != 2) { |
| PRINTM(MERROR, "Invalid arguments for ba_winsize command\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (data[0] > 7 || data[0] < 0) { |
| PRINTM(MERROR, "Invalid tid %d\n", data[0]); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (data[1] < 0) { |
| PRINTM(MERROR, "Invalid winsize %d\n", data[1]); |
| ret = -EINVAL; |
| goto done; |
| } |
| memset(addba_reject, 0, sizeof(addba_reject)); |
| if (MLAN_STATUS_SUCCESS != |
| woal_ioctl_addba_reject(priv, MLAN_ACT_GET, addba_reject)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| /* disable tx ba */ |
| if (data[1] == 0) { |
| addba_reject[data[0]] = MTRUE; |
| if (MLAN_STATUS_SUCCESS != |
| woal_ioctl_addba_reject(priv, MLAN_ACT_SET, addba_reject)) |
| ret = -EFAULT; |
| } else { |
| if (addba_reject[data[0]] == MTRUE) { |
| addba_reject[data[0]] = MFALSE; |
| if (MLAN_STATUS_SUCCESS != |
| woal_ioctl_addba_reject(priv, MLAN_ACT_SET, |
| addba_reject)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| } |
| memset(&addba_param, 0, sizeof(addba_param)); |
| if (MLAN_STATUS_SUCCESS != |
| woal_ioctl_addba_param(priv, MLAN_ACT_GET, &addba_param)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| if (data[1] != (int)addba_param.rxwinsize) { |
| addba_param.rxwinsize = data[1]; |
| if (MLAN_STATUS_SUCCESS != |
| woal_ioctl_addba_param(priv, MLAN_ACT_SET, |
| &addba_param)) |
| ret = -EFAULT; |
| } |
| } |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Configuring trx block-ack window size |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return 0 --success, otherwise failure |
| */ |
| static int |
| woal_set_tx_ba_winsize(moal_private *priv, t_u8 *respbuf, int respbuflen) |
| { |
| int data[2]; |
| mlan_ds_11n_aggr_prio_tbl aggr_prio_tbl; |
| mlan_ds_11n_addba_param addba_param; |
| t_u8 tos_to_tid_inv[] = { 0x02, 0x00, 0x01, 0x03, |
| 0x04, 0x05, 0x06, 0x07 |
| }; |
| int ret = 0; |
| int user_data_len = 0; |
| |
| ENTER(); |
| |
| memset((char *)data, 0, sizeof(data)); |
| if (respbuf && strlen(respbuf) > 0) |
| parse_arguments(respbuf, data, ARRAY_SIZE(data), |
| &user_data_len); |
| |
| if (user_data_len != 2) { |
| PRINTM(MERROR, "Invalid arguments for ba_winsize command\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (data[0] > 7 || data[0] < 0) { |
| PRINTM(MERROR, "Invalid tid %d\n", data[0]); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (data[1] < 0) { |
| PRINTM(MERROR, "Invalid winsize %d\n", data[1]); |
| ret = -EINVAL; |
| goto done; |
| } |
| memset(&aggr_prio_tbl, 0, sizeof(aggr_prio_tbl)); |
| if (MLAN_STATUS_SUCCESS != |
| woal_ioctl_aggr_prio_tbl(priv, MLAN_ACT_GET, &aggr_prio_tbl)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| /* disable tx ba */ |
| if (data[1] == 0) { |
| if (aggr_prio_tbl.ampdu[data[0]] != 0xff) { |
| aggr_prio_tbl.ampdu[data[0]] = 0xff; |
| if (MLAN_STATUS_SUCCESS != |
| woal_ioctl_aggr_prio_tbl(priv, MLAN_ACT_SET, |
| &aggr_prio_tbl)) |
| ret = -EFAULT; |
| } |
| } else { |
| if (aggr_prio_tbl.ampdu[data[0]] == 0xff) { |
| aggr_prio_tbl.ampdu[data[0]] = tos_to_tid_inv[data[0]]; |
| if (MLAN_STATUS_SUCCESS != |
| woal_ioctl_aggr_prio_tbl(priv, MLAN_ACT_SET, |
| &aggr_prio_tbl)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| } |
| memset(&addba_param, 0, sizeof(addba_param)); |
| if (MLAN_STATUS_SUCCESS != |
| woal_ioctl_addba_param(priv, MLAN_ACT_GET, &addba_param)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| if (data[1] != (int)addba_param.txwinsize) { |
| addba_param.txwinsize = data[1]; |
| if (MLAN_STATUS_SUCCESS != |
| woal_ioctl_addba_param(priv, MLAN_ACT_SET, |
| &addba_param)) |
| ret = -EFAULT; |
| } |
| } |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get aggregation priority table configurations |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_setget_priv_aggrpriotbl(moal_private *priv, t_u8 *respbuf, |
| t_u32 respbuflen) |
| { |
| int data[MAX_NUM_TID * 2], i, j; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_11n_cfg *cfg_11n = NULL; |
| int ret = 0; |
| int user_data_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_AGGRPRIOTBL))) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| memset((char *)data, 0, sizeof(data)); |
| parse_arguments(respbuf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_AGGRPRIOTBL), |
| data, ARRAY_SIZE(data), &user_data_len); |
| |
| if (user_data_len != ARRAY_SIZE(data)) { |
| PRINTM(MERROR, "Invalid number of arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| for (i = 0, j = 0; i < user_data_len; i = i + 2, ++j) { |
| if ((data[i] > 7 && data[i] != 0xff) || |
| (data[i + 1] > 7 && data[i + 1] != 0xff)) { |
| PRINTM(MERROR, |
| "Invalid priority, valid value 0-7 or 0xff.\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| } |
| } |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| cfg_11n = (mlan_ds_11n_cfg *)req->pbuf; |
| cfg_11n->sub_command = MLAN_OID_11N_CFG_AGGR_PRIO_TBL; |
| req->req_id = MLAN_IOCTL_11N_CFG; |
| |
| if (user_data_len == 0) { |
| /* Get aggr priority table from MLAN */ |
| req->action = MLAN_ACT_GET; |
| } else { |
| for (i = 0, j = 0; i < user_data_len; i = i + 2, ++j) { |
| cfg_11n->param.aggr_prio_tbl.ampdu[j] = data[i]; |
| cfg_11n->param.aggr_prio_tbl.amsdu[j] = data[i + 1]; |
| } |
| /* Update aggr priority table in MLAN */ |
| req->action = MLAN_ACT_SET; |
| } |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| for (i = 0, j = 0; i < (MAX_NUM_TID * 2); i = i + 2, ++j) { |
| respbuf[i] = cfg_11n->param.aggr_prio_tbl.ampdu[j]; |
| respbuf[i + 1] = cfg_11n->param.aggr_prio_tbl.amsdu[j]; |
| } |
| |
| ret = sizeof(data); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get Add BA reject configurations |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_setget_priv_addbareject(moal_private *priv, t_u8 *respbuf, |
| t_u32 respbuflen) |
| { |
| int data[MAX_NUM_TID], i; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_11n_cfg *cfg_11n = NULL; |
| int ret = 0; |
| int user_data_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_ADDBAREJECT))) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| memset((char *)data, 0, sizeof(data)); |
| parse_arguments(respbuf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_ADDBAREJECT), |
| data, ARRAY_SIZE(data), &user_data_len); |
| |
| if (user_data_len != ARRAY_SIZE(data)) { |
| PRINTM(MERROR, "Invalid number of arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| for (i = 0; i < user_data_len; i++) { |
| if (data[i] != 0 && data[i] != 1) { |
| PRINTM(MERROR, |
| "addba reject only takes argument as 0 or 1\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| } |
| } |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| cfg_11n = (mlan_ds_11n_cfg *)req->pbuf; |
| cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_REJECT; |
| req->req_id = MLAN_IOCTL_11N_CFG; |
| |
| if (user_data_len == 0) { |
| /* Get add BA reject configuration from MLAN */ |
| req->action = MLAN_ACT_GET; |
| } else { |
| for (i = 0; i < user_data_len; i++) |
| cfg_11n->param.addba_reject[i] = data[i]; |
| /* Update add BA reject configuration in MLAN */ |
| req->action = MLAN_ACT_SET; |
| } |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| for (i = 0; i < MAX_NUM_TID; i++) |
| respbuf[i] = cfg_11n->param.addba_reject[i]; |
| |
| ret = sizeof(data); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get 11AC configurations |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_setget_priv_vhtcfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int data[6]; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_11ac_cfg *cfg_11ac = NULL; |
| mlan_ds_11ac_vht_cfg *vhtcfg = NULL; |
| int ret = 0; |
| int user_data_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_VHTCFG))) { |
| PRINTM(MERROR, "Invalid number of arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| memset((char *)data, 0, sizeof(data)); |
| parse_arguments(respbuf + strlen(CMD_NXP) + strlen(PRIV_CMD_VHTCFG), |
| data, ARRAY_SIZE(data), &user_data_len); |
| |
| if ((user_data_len > 6) || (user_data_len < 2)) { |
| PRINTM(MERROR, "Invalid number of arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ac_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| cfg_11ac = (mlan_ds_11ac_cfg *)req->pbuf; |
| cfg_11ac->sub_command = MLAN_OID_11AC_VHT_CFG; |
| req->req_id = MLAN_IOCTL_11AC_CFG; |
| |
| /* Band */ |
| if ((data[0] < 0) || (data[0] > 2)) { |
| PRINTM(MERROR, "Invalid band selection\n"); |
| ret = -EINVAL; |
| goto done; |
| } else { |
| if (data[0] == BAND_SELECT_BOTH) { |
| cfg_11ac->param.vht_cfg.band = |
| (BAND_SELECT_BG | BAND_SELECT_A); |
| } else { |
| cfg_11ac->param.vht_cfg.band = data[0]; |
| } |
| PRINTM(MINFO, "GET/SET: vhtcfg band: 0x%x\n", data[0]); |
| } |
| |
| /* Tx/Rx */ |
| if ((data[1] <= 0) || (data[1] > 3)) { |
| PRINTM(MERROR, "Invalid Tx/Rx selection\n"); |
| ret = -EINVAL; |
| goto done; |
| } else { |
| cfg_11ac->param.vht_cfg.txrx = data[1]; |
| PRINTM(MINFO, "GET/SET: vhtcfg txrx: 0x%x\n", data[1]); |
| } |
| |
| if (user_data_len == 2) { |
| /* GET operation */ |
| if (data[0] == BAND_SELECT_BOTH) { |
| /* if get both bands, get BG first */ |
| cfg_11ac->param.vht_cfg.band = BAND_SELECT_BG; |
| } |
| if (priv->bss_role == MLAN_BSS_ROLE_UAP) |
| cfg_11ac->param.vht_cfg.txrx = MLAN_RADIO_RX; |
| |
| req->action = MLAN_ACT_GET; |
| } else { |
| if (user_data_len == 3) { |
| PRINTM(MERROR, "Invalid number of arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (user_data_len >= 4) { |
| /* BW cfg */ |
| if ((data[2] < 0) || (data[2] > 1) || |
| ((data[2] == 1) && (data[0] & BAND_SELECT_BG))) { |
| PRINTM(MERROR, "Invalid BW cfg selection\n"); |
| ret = -EINVAL; |
| goto done; |
| } else { |
| cfg_11ac->param.vht_cfg.bwcfg = data[2]; |
| PRINTM(MINFO, "SET: vhtcfg bw cfg:0x%x\n", |
| data[2]); |
| } |
| |
| cfg_11ac->param.vht_cfg.vht_cap_info = data[3]; |
| PRINTM(MINFO, "SET: vhtcfg vht_cap_info:0x%x\n", |
| data[3]); |
| } |
| if (user_data_len == 4) { |
| data[4] = 0xffffffff; |
| data[5] = 0xffffffff; |
| } |
| if (user_data_len == 5) { |
| PRINTM(MERROR, "Invalid number of arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (user_data_len >= 4) { |
| cfg_11ac->param.vht_cfg.vht_tx_mcs = data[4]; |
| cfg_11ac->param.vht_cfg.vht_rx_mcs = data[5]; |
| } |
| /* Update 11AC parameters in MLAN */ |
| req->action = MLAN_ACT_SET; |
| } |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| /* number of vhtcfg entries */ |
| *respbuf = 1; |
| vhtcfg = (mlan_ds_11ac_vht_cfg *)(respbuf + 1); |
| moal_memcpy_ext(priv->phandle, vhtcfg, &cfg_11ac->param.vht_cfg, |
| sizeof(mlan_ds_11ac_vht_cfg), respbuflen - 1); |
| ret = 1 + sizeof(mlan_ds_11ac_vht_cfg); |
| |
| if ((req->action == MLAN_ACT_GET) && (data[0] == BAND_SELECT_BOTH)) { |
| cfg_11ac->param.vht_cfg.band = BAND_SELECT_A; |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| /* number of vhtcfg entries */ |
| *respbuf = 2; |
| vhtcfg++; |
| moal_memcpy_ext(priv->phandle, vhtcfg, &cfg_11ac->param.vht_cfg, |
| sizeof(mlan_ds_11ac_vht_cfg), |
| respbuflen - 1 - sizeof(mlan_ds_11ac_vht_cfg)); |
| ret += sizeof(mlan_ds_11ac_vht_cfg); |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get 11AC Operating Mode Notification configurations |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_setget_priv_opermodecfg(moal_private *priv, t_u8 *respbuf, |
| t_u32 respbuflen) |
| { |
| int data[2]; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_11ac_cfg *cfg_11ac = NULL; |
| mlan_ds_11ac_opermode_cfg *opermodecfg = NULL; |
| int ret = 0; |
| int user_data_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| memset((char *)data, 0, sizeof(data)); |
| parse_arguments(respbuf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_OPERMODECFG), |
| data, ARRAY_SIZE(data), &user_data_len); |
| |
| if ((user_data_len != 0) && (user_data_len != 2)) { |
| PRINTM(MERROR, "Invalid number of arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (user_data_len == 2) { |
| /* Channel width */ |
| if ((data[0] < 1) || (data[0] > 4)) { |
| PRINTM(MERROR, "Invalid channel width: 0x%x\n", |
| data[0]); |
| ret = -EINVAL; |
| goto done; |
| } |
| /* nss */ |
| if ((data[1] < 1) || (data[1] > 8)) { |
| PRINTM(MERROR, "Invalid nss: 0x%x\n", data[1]); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ac_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| cfg_11ac = (mlan_ds_11ac_cfg *)req->pbuf; |
| cfg_11ac->sub_command = MLAN_OID_11AC_OPERMODE_CFG; |
| req->req_id = MLAN_IOCTL_11AC_CFG; |
| |
| if (user_data_len == 0) { |
| req->action = MLAN_ACT_GET; |
| } else { |
| req->action = MLAN_ACT_SET; |
| cfg_11ac->param.opermode_cfg.bw = data[0]; |
| cfg_11ac->param.opermode_cfg.nss = data[1]; |
| } |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| opermodecfg = (mlan_ds_11ac_opermode_cfg *) respbuf; |
| moal_memcpy_ext(priv->phandle, opermodecfg, |
| &(cfg_11ac->param.opermode_cfg), sizeof(*opermodecfg), |
| respbuflen); |
| ret = sizeof(*opermodecfg); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get 11AC configurations |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_get_priv_datarate(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_rate *rate = NULL; |
| mlan_data_rate *data_rate = NULL; |
| int ret = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| rate = (mlan_ds_rate *)req->pbuf; |
| rate->sub_command = MLAN_OID_GET_DATA_RATE; |
| req->req_id = MLAN_IOCTL_RATE; |
| req->action = MLAN_ACT_GET; |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| data_rate = (mlan_data_rate *)respbuf; |
| |
| moal_memcpy_ext(priv->phandle, data_rate, &rate->param.data_rate, |
| sizeof(mlan_data_rate), respbuflen); |
| |
| ret = sizeof(mlan_data_rate); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get tx rate configurations |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_setget_priv_txratecfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| t_u32 data[4]; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_rate *rate = NULL; |
| woal_tx_rate_cfg *ratecfg = NULL; |
| int ret = 0; |
| int user_data_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| txrate_setting *rate_setting = NULL; |
| |
| ENTER(); |
| |
| if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_TXRATECFG))) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| memset((char *)data, 0, sizeof(data)); |
| parse_arguments(respbuf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_TXRATECFG), |
| data, ARRAY_SIZE(data), &user_data_len); |
| } |
| |
| if (user_data_len > 4) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| req->req_id = MLAN_IOCTL_RATE; |
| rate = (mlan_ds_rate *)req->pbuf; |
| rate->sub_command = MLAN_OID_RATE_CFG; |
| rate->param.rate_cfg.rate_type = MLAN_RATE_INDEX; |
| |
| if (user_data_len == 0) { |
| /* Get operation */ |
| req->action = MLAN_ACT_GET; |
| } else { |
| /* Set operation */ |
| req->action = MLAN_ACT_SET; |
| /* format */ |
| if ((data[0] != AUTO_RATE) && (data[0] >= 4)) { |
| PRINTM(MERROR, "Invalid format selection\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (data[0] == AUTO_RATE) { |
| /* auto */ |
| rate->param.rate_cfg.is_rate_auto = 1; |
| } else { |
| /* fixed rate */ |
| PRINTM(MINFO, "SET: txratefg format: 0x%x\n", data[0]); |
| if ((data[0] != AUTO_RATE) && |
| (data[0] > MLAN_RATE_FORMAT_HE) |
| ) { |
| PRINTM(MERROR, "Invalid format selection\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| rate->param.rate_cfg.rate_format = data[0]; |
| |
| if (user_data_len >= 2) { |
| PRINTM(MINFO, "SET: txratefg index: 0x%x\n", |
| data[1]); |
| /* sanity check */ |
| if (((data[0] == MLAN_RATE_FORMAT_LG) && |
| (data[1] > MLAN_RATE_INDEX_OFDM7)) || |
| ((data[0] == MLAN_RATE_FORMAT_HT) && |
| (data[1] != 32) && (data[1] > 15) |
| ) |
| || ((data[0] == MLAN_RATE_FORMAT_VHT) && |
| (data[1] > MLAN_RATE_INDEX_MCS9)) |
| || ((data[0] == MLAN_RATE_FORMAT_HE) && |
| (data[1] > MLAN_RATE_INDEX_MCS11)) |
| ) { |
| PRINTM(MERROR, |
| "Invalid index selection\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| PRINTM(MINFO, "SET: txratefg index: 0x%x\n", |
| data[1]); |
| rate->param.rate_cfg.rate = data[1]; |
| } |
| |
| if (data[0] == 2 || data[0] == 3) { |
| PRINTM(MINFO, "SET: txratefg nss: 0x%x\n", |
| data[2]); |
| /* NSS is supported up to 2 */ |
| if ((data[2] <= 0) || (data[2] >= 3)) { |
| PRINTM(MERROR, |
| "Invalid nss selection\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| rate->param.rate_cfg.nss = data[2]; |
| } |
| if (user_data_len == 4) { |
| rate->param.rate_cfg.rate_setting = |
| data[3] & ~0x0C00; |
| PRINTM(MIOCTL, |
| "SET: txratefg HE Rate Setting: 0x%x\n", |
| data[3]); |
| |
| /* HE Preamble type */ |
| //#define HE_SU_PREAMBLE 0 |
| #define HE_ER_PREAMBLE 1 |
| |
| /* HE ER SU Type */ |
| #define HE_ER_SU_BANDWIDTH_TONE242 0 |
| #define HE_ER_SU_BANDWIDTH_TONE106 1 |
| |
| rate_setting = (txrate_setting *) & data[3]; |
| |
| if (data[0] == MLAN_RATE_FORMAT_HE) { |
| if (rate_setting->preamble == |
| HE_ER_PREAMBLE) { |
| if (rate_setting->bandwidth == |
| HE_ER_SU_BANDWIDTH_TONE242) |
| { |
| if ((data[1] > |
| MLAN_RATE_INDEX_MCS2) |
| || data[2] > |
| MLAN_RATE_NSS1) { |
| PRINTM(MERROR, |
| "Invalid rate and MCS or NSS configuration for 242 tone\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } else if (rate_setting-> |
| bandwidth == |
| HE_ER_SU_BANDWIDTH_TONE106) |
| { |
| if ((data[1] != |
| MLAN_RATE_INDEX_MCS0) |
| || data[2] != |
| MLAN_RATE_NSS1) { |
| PRINTM(MERROR, |
| "Invalid rate and MCS or NSS configuration\n for 106 tone"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } else { |
| PRINTM(MERROR, |
| "Invalid Bandwidth for HE ER Preamble\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| if ((rate_setting->dcm) && |
| (rate_setting->stbc == 0)) { |
| if ((data[1] == |
| MLAN_RATE_INDEX_MCS2) || |
| (data[1] > |
| MLAN_RATE_INDEX_MCS4)) { |
| PRINTM(MERROR, |
| "Invalid MCS configuration if DCM is supported\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| } |
| } else { |
| rate->param.rate_cfg.rate_setting = 0xffff; |
| } |
| } |
| } |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| ratecfg = (woal_tx_rate_cfg *)respbuf; |
| if (rate->param.rate_cfg.is_rate_auto == MTRUE) { |
| ratecfg->rate_format = 0xFF; |
| } else { |
| /* fixed rate */ |
| ratecfg->rate_format = rate->param.rate_cfg.rate_format; |
| ratecfg->rate_index = rate->param.rate_cfg.rate; |
| if (rate->param.rate_cfg.rate_format == MLAN_RATE_FORMAT_VHT |
| || rate->param.rate_cfg.rate_format == MLAN_RATE_FORMAT_HE) |
| ratecfg->nss = rate->param.rate_cfg.nss; |
| ratecfg->rate_setting = rate->param.rate_cfg.rate_setting; |
| } |
| |
| ret = sizeof(woal_tx_rate_cfg); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| #if defined(STA_SUPPORT) || defined(UAP_SUPPORT) |
| /** |
| * @brief Get statistics information |
| * |
| * @param priv A pointer to moal_private structure |
| * @param wait_option Wait option |
| * @param stats A pointer to mlan_ds_get_stats structure |
| * |
| * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, |
| * otherwise fail |
| */ |
| mlan_status |
| woal_get_stats_info(moal_private *priv, t_u8 wait_option, |
| mlan_ds_get_stats *stats) |
| { |
| 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; |
| if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) |
| info->sub_command = MLAN_OID_GET_STATS; |
| else if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) |
| info->sub_command = MLAN_OID_GET_UAP_STATS_LOG; |
| req->req_id = MLAN_IOCTL_GET_INFO; |
| req->action = MLAN_ACT_GET; |
| |
| /* Send IOCTL request to MLAN */ |
| status = woal_request_ioctl(priv, req, wait_option); |
| if (status == MLAN_STATUS_SUCCESS) { |
| if (stats) |
| moal_memcpy_ext(priv->phandle, stats, |
| &info->param.stats, |
| sizeof(mlan_ds_get_stats), |
| sizeof(mlan_ds_get_stats)); |
| #if defined(STA_WEXT) || defined(UAP_WEXT) |
| priv->w_stats.discard.fragment = info->param.stats.fcs_error; |
| priv->w_stats.discard.retries = info->param.stats.retry; |
| priv->w_stats.discard.misc = info->param.stats.ack_failure; |
| #endif |
| } |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return status; |
| } |
| |
| /** |
| * @brief Get wireless stats information |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_get_priv_getlog(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| mlan_ds_get_stats *stats; |
| ENTER(); |
| |
| if (respbuflen < sizeof(*stats)) { |
| PRINTM(MERROR, "Get log: respbuflen (%d) too small!", |
| (int)respbuflen); |
| ret = -EFAULT; |
| goto done; |
| } |
| stats = (mlan_ds_get_stats *)respbuf; |
| if (MLAN_STATUS_SUCCESS != |
| woal_get_stats_info(priv, MOAL_IOCTL_WAIT, stats)) { |
| PRINTM(MERROR, "Get log: Failed to get stats info!"); |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| if (priv->phandle->fw_getlog_enable) |
| ret = sizeof(mlan_ds_get_stats); |
| else |
| ret = sizeof(mlan_ds_get_stats_org); |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| |
| /** |
| * @brief Set/Get esupplicant mode configurations |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_setget_priv_esuppmode(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| t_u32 data[3]; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_sec_cfg *sec = NULL; |
| woal_esuppmode_cfg *esupp_mode = NULL; |
| int ret = 0; |
| int user_data_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (!priv->phandle->card_info->embedded_supp) { |
| PRINTM(MERROR, "Not supported cmd on this card\n"); |
| ret = -EOPNOTSUPP; |
| goto done; |
| } |
| if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_ESUPPMODE))) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| memset((char *)data, 0, sizeof(data)); |
| parse_arguments(respbuf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_ESUPPMODE), |
| data, ARRAY_SIZE(data), &user_data_len); |
| } |
| |
| if (user_data_len >= 4 || user_data_len == 1 || user_data_len == 2) { |
| PRINTM(MERROR, "Invalid number of arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| req->req_id = MLAN_IOCTL_SEC_CFG; |
| sec = (mlan_ds_sec_cfg *)req->pbuf; |
| sec->sub_command = MLAN_OID_SEC_CFG_ESUPP_MODE; |
| |
| if (user_data_len == 0) { |
| /* Get operation */ |
| req->action = MLAN_ACT_GET; |
| } else { |
| /* Set operation */ |
| req->action = MLAN_ACT_SET; |
| /* RSN mode */ |
| sec->param.esupp_mode.rsn_mode = data[0]; |
| /* Pairwise cipher */ |
| sec->param.esupp_mode.act_paircipher = (data[1] & 0xFF); |
| /* Group cipher */ |
| sec->param.esupp_mode.act_groupcipher = (data[2] & 0xFF); |
| } |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| esupp_mode = (woal_esuppmode_cfg *)respbuf; |
| esupp_mode->rsn_mode = |
| (t_u16)((sec->param.esupp_mode.rsn_mode) & 0xFFFF); |
| esupp_mode->pairwise_cipher = |
| (t_u8)((sec->param.esupp_mode.act_paircipher) & 0xFF); |
| esupp_mode->group_cipher = |
| (t_u8)((sec->param.esupp_mode.act_groupcipher) & 0xFF); |
| |
| ret = sizeof(woal_esuppmode_cfg); |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get esupplicant passphrase configurations |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_setget_priv_passphrase(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_sec_cfg *sec = NULL; |
| int ret = 0, action = -1, i = 0; |
| char *begin, *end, *opt; |
| t_u16 len = 0; |
| t_u8 zero_mac[] = { 0, 0, 0, 0, 0, 0 }; |
| t_u8 *mac = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (!priv->phandle->card_info->embedded_supp) { |
| PRINTM(MERROR, "Not supported cmd on this card\n"); |
| ret = -EOPNOTSUPP; |
| goto done; |
| } |
| |
| if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_PASSPHRASE))) { |
| PRINTM(MERROR, "No arguments provided\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| /* Parse the buf to get the cmd_action */ |
| begin = respbuf + strlen(CMD_NXP) + strlen(PRIV_CMD_PASSPHRASE); |
| end = woal_strsep(&begin, ';', '/'); |
| if (end) |
| action = woal_atox(end); |
| if (action < 0 || action > 2 || end[1] != '\0') { |
| PRINTM(MERROR, "Invalid action argument %s\n", end); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| req->req_id = MLAN_IOCTL_SEC_CFG; |
| sec = (mlan_ds_sec_cfg *)req->pbuf; |
| sec->sub_command = MLAN_OID_SEC_CFG_PASSPHRASE; |
| if (action == 0) |
| req->action = MLAN_ACT_GET; |
| else |
| req->action = MLAN_ACT_SET; |
| |
| while (begin) { |
| end = woal_strsep(&begin, ';', '/'); |
| opt = woal_strsep(&end, '=', '/'); |
| if (!opt || !end || !end[0]) { |
| PRINTM(MERROR, "Invalid option\n"); |
| ret = -EINVAL; |
| break; |
| } else if (!strnicmp(opt, "ssid", strlen(opt))) { |
| if (strlen(end) > MLAN_MAX_SSID_LENGTH) { |
| PRINTM(MERROR, |
| "SSID length exceeds max length\n"); |
| ret = -EFAULT; |
| break; |
| } |
| sec->param.passphrase.ssid.ssid_len = strlen(end); |
| moal_memcpy_ext(priv->phandle, |
| sec->param.passphrase.ssid.ssid, end, |
| strlen(end), MLAN_MAX_SSID_LENGTH); |
| PRINTM(MINFO, "ssid=%s, len=%d\n", |
| sec->param.passphrase.ssid.ssid, |
| (int)sec->param.passphrase.ssid.ssid_len); |
| } else if (!strnicmp(opt, "bssid", strlen(opt))) { |
| woal_mac2u8((t_u8 *)&sec->param.passphrase.bssid, end); |
| } else if (!strnicmp(opt, "psk", strlen(opt)) && |
| req->action == MLAN_ACT_SET) { |
| if (strlen(end) != MLAN_PMK_HEXSTR_LENGTH) { |
| PRINTM(MERROR, "Invalid PMK length\n"); |
| ret = -EINVAL; |
| break; |
| } |
| woal_ascii2hex((t_u8 *)(sec->param.passphrase.psk.pmk. |
| pmk), end, |
| MLAN_PMK_HEXSTR_LENGTH / 2); |
| sec->param.passphrase.psk_type = MLAN_PSK_PMK; |
| } else if (!strnicmp(opt, "passphrase", strlen(opt)) && |
| req->action == MLAN_ACT_SET) { |
| if (strlen(end) < MLAN_MIN_PASSPHRASE_LENGTH || |
| strlen(end) > MLAN_MAX_PASSPHRASE_LENGTH) { |
| PRINTM(MERROR, |
| "Invalid length for passphrase\n"); |
| ret = -EINVAL; |
| break; |
| } |
| sec->param.passphrase.psk_type = MLAN_PSK_PASSPHRASE; |
| moal_memcpy_ext(priv->phandle, |
| sec->param.passphrase.psk.passphrase. |
| passphrase, end, |
| sizeof(sec->param.passphrase.psk. |
| passphrase.passphrase), |
| sizeof(sec->param.passphrase.psk. |
| passphrase.passphrase)); |
| sec->param.passphrase.psk.passphrase.passphrase_len = |
| strlen(end); |
| PRINTM(MINFO, "passphrase=%s, len=%d\n", |
| sec->param.passphrase.psk.passphrase.passphrase, |
| (int)sec->param.passphrase.psk.passphrase. |
| passphrase_len); |
| } else if (!strnicmp(opt, "sae_password", strlen(opt)) && |
| req->action == MLAN_ACT_SET) { |
| if (strlen(end) < MLAN_MIN_SAE_PASSWORD_LENGTH || |
| strlen(end) > MLAN_MAX_SAE_PASSWORD_LENGTH) { |
| PRINTM(MERROR, |
| "Invalid length for sae password\n"); |
| ret = -EINVAL; |
| break; |
| } |
| sec->param.passphrase.psk_type = MLAN_PSK_SAE_PASSWORD; |
| moal_memcpy_ext(priv->phandle, |
| sec->param.passphrase.psk.sae_password. |
| sae_password, end, |
| sizeof(sec->param.passphrase.psk. |
| sae_password.sae_password), |
| sizeof(sec->param.passphrase.psk. |
| sae_password.sae_password)); |
| sec->param.passphrase.psk.sae_password. |
| sae_password_len = strlen(end); |
| PRINTM(MINFO, "sae_password=%s, len=%d\n", |
| sec->param.passphrase.psk.sae_password. |
| sae_password, |
| (int)sec->param.passphrase.psk.sae_password. |
| sae_password_len); |
| } else { |
| PRINTM(MERROR, "Invalid option %s\n", opt); |
| ret = -EINVAL; |
| break; |
| } |
| } |
| if (ret) |
| goto done; |
| |
| if (action == 2) |
| sec->param.passphrase.psk_type = MLAN_PSK_CLEAR; |
| else if (action == 0) |
| sec->param.passphrase.psk_type = MLAN_PSK_QUERY; |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| memset(respbuf, 0, respbuflen); |
| if (sec->param.passphrase.ssid.ssid_len) { |
| len += sprintf(respbuf + len, "ssid:"); |
| moal_memcpy_ext(priv->phandle, respbuf + len, |
| sec->param.passphrase.ssid.ssid, |
| sec->param.passphrase.ssid.ssid_len, |
| respbuflen - len); |
| len += sec->param.passphrase.ssid.ssid_len; |
| len += sprintf(respbuf + len, " "); |
| } |
| if (memcmp(&sec->param.passphrase.bssid, zero_mac, sizeof(zero_mac))) { |
| mac = (t_u8 *)&sec->param.passphrase.bssid; |
| len += sprintf(respbuf + len, "bssid:"); |
| for (i = 0; i < ETH_ALEN - 1; ++i) |
| len += sprintf(respbuf + len, "%02x:", mac[i]); |
| len += sprintf(respbuf + len, "%02x ", mac[i]); |
| } |
| if (sec->param.passphrase.psk_type == MLAN_PSK_PMK) { |
| len += sprintf(respbuf + len, "psk:"); |
| for (i = 0; i < MLAN_MAX_KEY_LENGTH; ++i) |
| len += sprintf(respbuf + len, "%02x", |
| sec->param.passphrase.psk.pmk.pmk[i]); |
| len += sprintf(respbuf + len, "\n"); |
| } |
| if (sec->param.passphrase.psk_type == MLAN_PSK_PASSPHRASE) |
| len += sprintf(respbuf + len, "passphrase:%s\n", |
| sec->param.passphrase.psk.passphrase.passphrase); |
| if (sec->param.passphrase.psk_type == MLAN_PSK_SAE_PASSWORD) |
| len += sprintf(respbuf + len, "sae_password:%s\n", |
| sec->param.passphrase.psk.sae_password. |
| sae_password); |
| |
| ret = len; |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Deauthenticate |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_deauth(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| t_u8 mac[ETH_ALEN]; |
| |
| ENTER(); |
| |
| if (strlen(respbuf) > (strlen(CMD_NXP) + strlen(PRIV_CMD_DEAUTH))) { |
| /* Deauth mentioned BSSID */ |
| woal_mac2u8(mac, respbuf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_DEAUTH)); |
| if (MLAN_STATUS_SUCCESS != |
| woal_disconnect(priv, MOAL_IOCTL_WAIT, mac, |
| DEF_DEAUTH_REASON_CODE)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| } else { |
| if (MLAN_STATUS_SUCCESS != |
| woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL, |
| DEF_DEAUTH_REASON_CODE)) |
| ret = -EFAULT; |
| } |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| #ifdef UAP_SUPPORT |
| /** |
| * @brief uap station deauth ioctl handler |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_ap_deauth(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| t_u8 *data_ptr; |
| mlan_ioctl_req *ioctl_req = NULL; |
| mlan_ds_bss *bss = NULL; |
| mlan_deauth_param deauth_param; |
| int ret = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_AP_DEAUTH)); |
| memset(&deauth_param, 0, sizeof(mlan_deauth_param)); |
| moal_memcpy_ext(priv->phandle, &deauth_param, data_ptr, |
| sizeof(mlan_deauth_param), sizeof(mlan_deauth_param)); |
| |
| PRINTM(MIOCTL, "ioctl deauth station: " MACSTR ", reason=%d\n", |
| MAC2STR(deauth_param.mac_addr), deauth_param.reason_code); |
| |
| ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); |
| if (ioctl_req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| bss = (mlan_ds_bss *)ioctl_req->pbuf; |
| |
| bss->sub_command = MLAN_OID_UAP_DEAUTH_STA; |
| ioctl_req->req_id = MLAN_IOCTL_BSS; |
| ioctl_req->action = MLAN_ACT_SET; |
| |
| moal_memcpy_ext(priv->phandle, &bss->param.deauth_param, &deauth_param, |
| sizeof(mlan_deauth_param), sizeof(mlan_deauth_param)); |
| status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| moal_memcpy_ext(priv->phandle, data_ptr, &ioctl_req->status_code, |
| sizeof(t_u32), |
| respbuflen - (strlen(CMD_NXP) + |
| strlen(PRIV_CMD_AP_DEAUTH))); |
| ret = sizeof(t_u32); |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(ioctl_req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief uap get station list handler |
| * |
| * @param dev A pointer to net_device structure |
| * @param req A pointer to ifreq structure |
| * @return 0 --success, otherwise fail |
| */ |
| static int |
| woal_priv_get_sta_list(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| mlan_ds_get_info *info = NULL; |
| mlan_ds_sta_list *sta_list = NULL; |
| mlan_ioctl_req *ioctl_req = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| /* Allocate an IOCTL request buffer */ |
| ioctl_req = |
| (mlan_ioctl_req *) |
| woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info)); |
| if (ioctl_req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| info = (mlan_ds_get_info *)ioctl_req->pbuf; |
| info->sub_command = MLAN_OID_UAP_STA_LIST; |
| ioctl_req->req_id = MLAN_IOCTL_GET_INFO; |
| ioctl_req->action = MLAN_ACT_GET; |
| |
| status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| sta_list = (mlan_ds_sta_list *)(respbuf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_GET_STA_LIST)); |
| moal_memcpy_ext(priv->phandle, sta_list, &info->param.sta_list, |
| ioctl_req->data_read_written, |
| respbuflen - (strlen(CMD_NXP) + |
| strlen(PRIV_CMD_GET_STA_LIST))); |
| ret = ioctl_req->data_read_written + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_GET_STA_LIST); |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(ioctl_req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief uap bss_config handler |
| * |
| * @param dev A pointer to net_device structure |
| * @param req A pointer to ifreq structure |
| * @return 0 --success, otherwise fail |
| */ |
| static int |
| woal_priv_bss_config(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| mlan_ds_bss *bss = NULL; |
| mlan_ioctl_req *ioctl_req = NULL; |
| t_u32 action = 0; |
| int offset = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| offset = strlen(CMD_NXP) + strlen(PRIV_CMD_BSS_CONFIG); |
| moal_memcpy_ext(priv->phandle, (u8 *)&action, respbuf + offset, |
| sizeof(action), sizeof(action)); |
| offset += sizeof(action); |
| |
| /* Allocate an IOCTL request buffer */ |
| ioctl_req = |
| (mlan_ioctl_req *) |
| woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); |
| if (ioctl_req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| bss = (mlan_ds_bss *)ioctl_req->pbuf; |
| bss->sub_command = MLAN_OID_UAP_BSS_CONFIG; |
| ioctl_req->req_id = MLAN_IOCTL_BSS; |
| if (action == 1) { |
| ioctl_req->action = MLAN_ACT_SET; |
| /* Get the BSS config from user */ |
| moal_memcpy_ext(priv->phandle, &bss->param.bss_config, |
| respbuf + offset, sizeof(mlan_uap_bss_param), |
| sizeof(mlan_uap_bss_param)); |
| } else { |
| ioctl_req->action = MLAN_ACT_GET; |
| } |
| |
| 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) { |
| moal_memcpy_ext(priv->phandle, respbuf + offset, |
| &bss->param.bss_config, |
| sizeof(mlan_uap_bss_param), |
| respbuflen - (t_u32)offset); |
| } |
| ret = sizeof(mlan_uap_bss_param); |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(ioctl_req); |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| |
| #ifdef WIFI_DIRECT_SUPPORT |
| #if defined(STA_SUPPORT) && defined(UAP_SUPPORT) |
| /** |
| * @brief Set/Get BSS role |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_bssrole(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| t_u32 data[1]; |
| int ret = 0; |
| int user_data_len = 0; |
| t_u8 action = MLAN_ACT_GET; |
| |
| ENTER(); |
| |
| memset((char *)data, 0, sizeof(data)); |
| if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_BSSROLE))) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_BSSROLE), |
| data, ARRAY_SIZE(data), &user_data_len); |
| } |
| |
| if (user_data_len >= 2) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto error; |
| } |
| |
| if (user_data_len == 0) { |
| action = MLAN_ACT_GET; |
| } else { |
| if ((data[0] != MLAN_BSS_ROLE_STA && |
| data[0] != MLAN_BSS_ROLE_UAP) || |
| priv->bss_type != MLAN_BSS_TYPE_WIFIDIRECT) { |
| PRINTM(MWARN, "Invalid BSS role\n"); |
| ret = -EINVAL; |
| goto error; |
| } |
| if (data[0] == GET_BSS_ROLE(priv)) { |
| PRINTM(MWARN, "Already BSS is in desired role\n"); |
| goto done; |
| } |
| action = MLAN_ACT_SET; |
| /* Reset interface */ |
| woal_reset_intf(priv, MOAL_IOCTL_WAIT, MFALSE); |
| } |
| |
| if (MLAN_STATUS_SUCCESS != |
| woal_bss_role_cfg(priv, action, MOAL_IOCTL_WAIT, (t_u8 *)data)) { |
| ret = -EFAULT; |
| goto error; |
| } |
| |
| if (user_data_len) { |
| /* Initialize private structures */ |
| woal_init_priv(priv, MOAL_IOCTL_WAIT); |
| /* Enable interfaces */ |
| netif_device_attach(priv->netdev); |
| woal_start_queue(priv->netdev); |
| } |
| |
| done: |
| memset(respbuf, 0, respbuflen); |
| respbuf[0] = (t_u8)data[0]; |
| ret = 1; |
| |
| error: |
| LEAVE(); |
| return ret; |
| } |
| #endif /* STA_SUPPORT && UAP_SUPPORT */ |
| #endif /* WIFI_DIRECT_SUPPORT */ |
| |
| #ifdef STA_SUPPORT |
| /** |
| * @brief Set user scan |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_setuserscan(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| wlan_user_scan_cfg scan_cfg; |
| int ret = 0; |
| |
| ENTER(); |
| |
| /* Create the scan_cfg structure */ |
| memset(&scan_cfg, 0, sizeof(scan_cfg)); |
| |
| /* We expect the scan_cfg structure to be passed in respbuf */ |
| moal_memcpy_ext(priv->phandle, (char *)&scan_cfg, |
| respbuf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_SETUSERSCAN), |
| sizeof(wlan_user_scan_cfg), sizeof(wlan_user_scan_cfg)); |
| moal_memcpy_ext(priv->phandle, scan_cfg.random_mac, priv->random_mac, |
| ETH_ALEN, MLAN_MAC_ADDR_LENGTH); |
| /* Call for scan */ |
| if (MLAN_STATUS_FAILURE == woal_do_scan(priv, &scan_cfg)) |
| ret = -EFAULT; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get channel statistics |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_get_chanstats(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_scan_resp scan_resp; |
| chan_stats *stats = NULL; |
| int ret = 0; |
| ENTER(); |
| |
| if (!respbuf) { |
| PRINTM(MERROR, "response buffer is not available!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| memset(&scan_resp, 0, sizeof(scan_resp)); |
| if (MLAN_STATUS_SUCCESS != |
| woal_get_scan_table(priv, MOAL_IOCTL_WAIT, &scan_resp)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| memset(respbuf, 0, respbuflen); |
| stats = (chan_stats *) respbuf; |
| stats->num_in_chan_stats = scan_resp.num_in_chan_stats; |
| ret = sizeof(ChanStatistics_t) * stats->num_in_chan_stats; |
| moal_memcpy_ext(priv->phandle, (t_u8 *)stats->stats, |
| (t_u8 *)scan_resp.pchan_stats, ret, respbuflen); |
| ret += sizeof(stats->num_in_chan_stats); |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Retrieve the scan response/beacon table |
| * |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * @param scan_resp A pointer to mlan_scan_resp structure |
| * @param scan_start Argument |
| * |
| * @return MLAN_STATUS_SUCCESS --success, otherwise fail |
| */ |
| static int |
| moal_ret_get_scan_table_ioctl(t_u8 *respbuf, t_u32 respbuflen, |
| mlan_scan_resp *scan_resp, t_u32 scan_start) |
| { |
| pBSSDescriptor_t pbss_desc, scan_table; |
| wlan_ioctl_get_scan_table_info *prsp_info; |
| int ret_code; |
| int ret_len; |
| int space_left; |
| t_u8 *pcurrent; |
| t_u8 *pbuffer_end; |
| t_u32 num_scans_done; |
| |
| ENTER(); |
| |
| num_scans_done = 0; |
| ret_code = MLAN_STATUS_SUCCESS; |
| |
| prsp_info = (wlan_ioctl_get_scan_table_info *)respbuf; |
| pcurrent = (t_u8 *)prsp_info->scan_table_entry_buf; |
| |
| pbuffer_end = respbuf + respbuflen - 1; |
| space_left = pbuffer_end - pcurrent; |
| scan_table = (BSSDescriptor_t *)(scan_resp->pscan_table); |
| |
| PRINTM(MINFO, "GetScanTable: scan_start req = %d\n", scan_start); |
| PRINTM(MINFO, "GetScanTable: length avail = %d\n", respbuflen); |
| |
| if (!scan_start) { |
| PRINTM(MINFO, "GetScanTable: get current BSS Descriptor\n"); |
| |
| /* Use to get current association saved descriptor */ |
| pbss_desc = scan_table; |
| |
| ret_code = wlan_get_scan_table_ret_entry(pbss_desc, &pcurrent, |
| &space_left); |
| |
| if (ret_code == MLAN_STATUS_SUCCESS) |
| num_scans_done = 1; |
| |
| } else { |
| scan_start--; |
| |
| while (space_left && |
| (scan_start + num_scans_done < |
| scan_resp->num_in_scan_table) && |
| (ret_code == MLAN_STATUS_SUCCESS)) { |
| pbss_desc = |
| (scan_table + (scan_start + num_scans_done)); |
| |
| PRINTM(MINFO, |
| "GetScanTable: get current BSS Descriptor [%d]\n", |
| scan_start + num_scans_done); |
| |
| ret_code = |
| wlan_get_scan_table_ret_entry(pbss_desc, |
| &pcurrent, |
| &space_left); |
| |
| if (ret_code == MLAN_STATUS_SUCCESS) |
| num_scans_done++; |
| } |
| } |
| |
| prsp_info->scan_number = num_scans_done; |
| ret_len = pcurrent - respbuf; |
| |
| LEAVE(); |
| return ret_len; |
| } |
| |
| /** |
| * @brief Get scan table |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_getscantable(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_scan *scan = NULL; |
| t_u32 scan_start; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| moal_handle *handle = priv->phandle; |
| |
| ENTER(); |
| |
| /* First make sure scanning is not in progress */ |
| if (handle->scan_pending_on_block == MTRUE) { |
| ret = -EAGAIN; |
| goto done; |
| } |
| |
| /* Allocate an IOCTL request buffer */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| /* Fill request buffer */ |
| scan = (mlan_ds_scan *)req->pbuf; |
| req->req_id = MLAN_IOCTL_SCAN; |
| req->action = MLAN_ACT_GET; |
| |
| /* Get the whole command from user */ |
| moal_memcpy_ext(handle, &scan_start, |
| respbuf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_GETSCANTABLE), |
| sizeof(scan_start), sizeof(scan_start)); |
| if (scan_start) |
| scan->sub_command = MLAN_OID_SCAN_NORMAL; |
| else |
| scan->sub_command = MLAN_OID_SCAN_GET_CURRENT_BSS; |
| |
| /* Send IOCTL request to MLAN */ |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status == MLAN_STATUS_SUCCESS) { |
| ret = moal_ret_get_scan_table_ioctl(respbuf, respbuflen, |
| &scan->param.scan_resp, |
| scan_start); |
| } |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Extended capabilities configuration |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_extcapcfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret, header; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *cfg = NULL; |
| IEEEtypes_Header_t *ie; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (!respbuf) { |
| LEAVE(); |
| return 0; |
| } |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| cfg = (mlan_ds_misc_cfg *)req->pbuf; |
| cfg->sub_command = MLAN_OID_MISC_EXT_CAP_CFG; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| header = strlen(CMD_NXP) + strlen(PRIV_CMD_EXTCAPCFG); |
| if ((int)strlen(respbuf) == header) |
| /* GET operation */ |
| req->action = MLAN_ACT_GET; |
| else { |
| /* SET operation */ |
| ie = (IEEEtypes_Header_t *)(respbuf + header); |
| if (ie->len > sizeof(ExtCap_t)) { |
| PRINTM(MERROR, |
| "Extended Capability lenth is invalid\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| req->action = MLAN_ACT_SET; |
| memset(&cfg->param.ext_cap, 0, sizeof(ExtCap_t)); |
| moal_memcpy_ext(priv->phandle, &cfg->param.ext_cap, ie + 1, |
| ie->len, sizeof(ExtCap_t)); |
| } |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| memset(respbuf, 0, respbuflen); |
| ie = (IEEEtypes_Header_t *)respbuf; |
| ie->element_id = EXT_CAPABILITY; |
| ie->len = sizeof(ExtCap_t); |
| moal_memcpy_ext(priv->phandle, ie + 1, &cfg->param.ext_cap, |
| sizeof(ExtCap_t), |
| respbuflen - sizeof(IEEEtypes_Header_t)); |
| |
| ret = sizeof(IEEEtypes_Header_t) + ie->len; |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| |
| /** |
| * @brief Set/Get deep sleep mode configurations |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_setgetdeepsleep(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| t_u32 data[2]; |
| int ret = 0; |
| int user_data_len = 0; |
| |
| ENTER(); |
| |
| if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_DEEPSLEEP))) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| memset((char *)data, 0, sizeof(data)); |
| parse_arguments(respbuf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_DEEPSLEEP), |
| data, ARRAY_SIZE(data), &user_data_len); |
| } |
| |
| if (user_data_len >= 3) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| if (user_data_len == 0) { |
| if (MLAN_STATUS_SUCCESS != woal_get_deep_sleep(priv, data)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| sprintf(respbuf, "%d %d", data[0], data[1]); |
| ret = strlen(respbuf) + 1; |
| } else { |
| if (data[0] == DEEP_SLEEP_OFF) { |
| PRINTM(MINFO, "Exit Deep Sleep Mode\n"); |
| ret = woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MFALSE, |
| 0); |
| if (ret != MLAN_STATUS_SUCCESS) { |
| ret = -EINVAL; |
| goto done; |
| } |
| } else if (data[0] == DEEP_SLEEP_ON) { |
| PRINTM(MINFO, "Enter Deep Sleep Mode\n"); |
| if (user_data_len != 2) |
| data[1] = 0; |
| ret = woal_set_deep_sleep(priv, MOAL_IOCTL_WAIT, MTRUE, |
| data[1]); |
| if (ret != MLAN_STATUS_SUCCESS) { |
| ret = -EINVAL; |
| goto done; |
| } |
| } else { |
| PRINTM(MERROR, "Unknown option = %u\n", data[0]); |
| ret = -EINVAL; |
| goto done; |
| } |
| ret = sprintf(respbuf, "OK\n") + 1; |
| } |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get IP address configurations |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_setgetipaddr(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| int ret = 0, op_code = 0, data_length = 0, header = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (priv->bss_type != MLAN_BSS_TYPE_STA) { |
| PRINTM(MIOCTL, "Bss type[%d]: Not STA, ignore it\n", |
| priv->bss_type); |
| ret = sprintf(respbuf, "OK\n") + 1; |
| goto done; |
| } |
| |
| header = strlen(CMD_NXP) + strlen(PRIV_CMD_IPADDR); |
| data_length = strlen(respbuf) - header; |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| misc = (mlan_ds_misc_cfg *)req->pbuf; |
| |
| if (data_length < 1) { /* GET */ |
| req->action = MLAN_ACT_GET; |
| } else { |
| /* Make sure we have the operation argument */ |
| if (data_length > 2 && respbuf[header + 1] != ';') { |
| PRINTM(MERROR, |
| "No operation argument. Separate with ';'\n"); |
| ret = -EINVAL; |
| goto done; |
| } else { |
| respbuf[header + 1] = '\0'; |
| } |
| req->action = MLAN_ACT_SET; |
| |
| /* Only one IP is supported in current firmware */ |
| memset(misc->param.ipaddr_cfg.ip_addr[0], 0, IPADDR_LEN); |
| if (data_length > 2) |
| in4_pton(&respbuf[header + 2], |
| MIN((IPADDR_MAX_BUF - 3), (data_length - 2)), |
| misc->param.ipaddr_cfg.ip_addr[0], ' ', NULL); |
| misc->param.ipaddr_cfg.ip_addr_num = 1; |
| misc->param.ipaddr_cfg.ip_addr_type = IPADDR_TYPE_IPV4; |
| |
| if (woal_atoi(&op_code, &respbuf[header]) != |
| MLAN_STATUS_SUCCESS) { |
| ret = -EINVAL; |
| goto done; |
| } |
| misc->param.ipaddr_cfg.op_code = (t_u32)op_code; |
| } |
| |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| misc->sub_command = MLAN_OID_MISC_IP_ADDR; |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| if (req->action == MLAN_ACT_GET) { |
| snprintf(respbuf, IPADDR_MAX_BUF, "%d;%d.%d.%d.%d", |
| misc->param.ipaddr_cfg.op_code, |
| misc->param.ipaddr_cfg.ip_addr[0][0], |
| misc->param.ipaddr_cfg.ip_addr[0][1], |
| misc->param.ipaddr_cfg.ip_addr[0][2], |
| misc->param.ipaddr_cfg.ip_addr[0][3]); |
| ret = IPADDR_MAX_BUF + 1; |
| } else { |
| ret = sprintf(respbuf, "OK\n") + 1; |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get WPS session configurations |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_setwpssession(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_wps_cfg *pwps = NULL; |
| t_u32 data[1]; |
| int ret = 0; |
| int user_data_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| memset((char *)data, 0, sizeof(data)); |
| if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_WPSSESSION))) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_WPSSESSION), |
| data, ARRAY_SIZE(data), &user_data_len); |
| } |
| |
| if (user_data_len > 1) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wps_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| pwps = (mlan_ds_wps_cfg *)req->pbuf; |
| |
| req->req_id = MLAN_IOCTL_WPS_CFG; |
| req->action = MLAN_ACT_SET; |
| pwps->sub_command = MLAN_OID_WPS_CFG_SESSION; |
| |
| if (data[0] == 1) |
| pwps->param.wps_session = MLAN_WPS_CFG_SESSION_START; |
| else |
| pwps->param.wps_session = MLAN_WPS_CFG_SESSION_END; |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| ret = sprintf(respbuf, "OK\n") + 1; |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get OTP user data |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_otpuserdata(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int data[1]; |
| int user_data_len = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| mlan_ds_misc_otp_user_data *otp = NULL; |
| int ret = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_OTPUSERDATA))) { |
| PRINTM(MERROR, "Invalid number of arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| memset((char *)data, 0, sizeof(data)); |
| parse_arguments(respbuf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_OTPUSERDATA), |
| data, ARRAY_SIZE(data), &user_data_len); |
| |
| if (user_data_len != 1) { |
| PRINTM(MERROR, "Invalid number of arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| req->action = MLAN_ACT_GET; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| |
| misc = (mlan_ds_misc_cfg *)req->pbuf; |
| misc->sub_command = MLAN_OID_MISC_OTP_USER_DATA; |
| misc->param.otp_user_data.user_data_length = data[0]; |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| otp = (mlan_ds_misc_otp_user_data *)req->pbuf; |
| |
| if (req->action == MLAN_ACT_GET) { |
| ret = MIN(otp->user_data_length, data[0]); |
| moal_memcpy_ext(priv->phandle, respbuf, otp->user_data, ret, |
| respbuflen); |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set / Get country code |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_set_get_countrycode(moal_private *priv, t_u8 *respbuf, |
| t_u32 respbuflen) |
| { |
| int ret = 0; |
| /* char data[COUNTRY_CODE_LEN] = {0, 0, 0}; */ |
| int header = 0, data_length = 0; /* wrq->u.data.length; */ |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *pcfg_misc = NULL; |
| mlan_ds_misc_country_code *country_code = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| header = strlen(CMD_NXP) + strlen(PRIV_CMD_COUNTRYCODE); |
| data_length = strlen(respbuf) - header; |
| |
| if (data_length > COUNTRY_CODE_LEN) { |
| PRINTM(MERROR, "Invalid argument!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| /* Allocate an IOCTL request buffer */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| /* Fill request buffer */ |
| pcfg_misc = (mlan_ds_misc_cfg *)req->pbuf; |
| country_code = &pcfg_misc->param.country_code; |
| pcfg_misc->sub_command = MLAN_OID_MISC_COUNTRY_CODE; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| |
| if (data_length <= 1) { |
| req->action = MLAN_ACT_GET; |
| } else { |
| memset(country_code->country_code, 0, COUNTRY_CODE_LEN); |
| moal_memcpy_ext(priv->phandle, country_code->country_code, |
| respbuf + header, COUNTRY_CODE_LEN, |
| COUNTRY_CODE_LEN); |
| 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; |
| } |
| |
| if (req->action == MLAN_ACT_GET) { |
| ret = data_length = COUNTRY_CODE_LEN; |
| memset(respbuf + header, 0, COUNTRY_CODE_LEN); |
| moal_memcpy_ext(priv->phandle, respbuf, |
| country_code->country_code, COUNTRY_CODE_LEN, |
| respbuflen); |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get cfp information |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_get_cfpinfo(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *cfp_misc = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (!respbuf) { |
| PRINTM(MERROR, "response buffer is not available!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| /* Allocate an IOCTL request buffer */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| /* Fill request buffer */ |
| cfp_misc = (mlan_ds_misc_cfg *)req->pbuf; |
| cfp_misc->sub_command = MLAN_OID_MISC_CFP_INFO; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| req->action = MLAN_ACT_GET; |
| |
| /* Send IOCTL request to MLAN */ |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| if (respbuflen < req->data_read_written) { |
| PRINTM(MERROR, "response buffer length is too short!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)req->pbuf, |
| req->data_read_written, respbuflen); |
| ret = req->data_read_written; |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get TCP Ack enhancement configurations |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_setgettcpackenh(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| t_u32 data[2] = { 0, 0 }; |
| int ret = 0; |
| int user_data_len = 0; |
| |
| ENTER(); |
| if (!priv || !priv->phandle) { |
| PRINTM(MERROR, "priv or handle is null\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_TCPACKENH))) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| memset((char *)data, 0, sizeof(data)); |
| parse_arguments(respbuf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_TCPACKENH), |
| data, ARRAY_SIZE(data), &user_data_len); |
| } |
| |
| if (user_data_len == 0) { |
| /* get operation */ |
| data[0] = priv->enable_tcp_ack_enh; |
| data[1] = priv->tcp_ack_max_hold; |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, |
| sizeof(data), respbuflen); |
| ret = sizeof(data); |
| } else { |
| /* set operation */ |
| if (user_data_len >= 3) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (data[0] > 1 || data[1] > TCP_ACK_MAX_HOLD) { |
| PRINTM(MERROR, "Invalid argument\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (data[0] == MTRUE) { |
| PRINTM(MINFO, "Enabling TCP Ack enhancement\n"); |
| priv->enable_tcp_ack_enh = MTRUE; |
| } else if (data[0] == MFALSE) { |
| PRINTM(MINFO, "Disabling TCP Ack enhancement\n"); |
| priv->enable_tcp_ack_enh = MFALSE; |
| /* release the tcp sessions if any */ |
| woal_flush_tcp_sess_queue(priv); |
| } |
| if (user_data_len >= 2) { |
| PRINTM(MINFO, "TCP drop Ack configure: %d\n", data[1]); |
| priv->tcp_ack_max_hold = data[1]; |
| } |
| data[0] = priv->enable_tcp_ack_enh; |
| data[1] = priv->tcp_ack_max_hold; |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, |
| sizeof(data), respbuflen); |
| ret = sizeof(data); |
| } |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| #ifdef REASSOCIATION |
| /** |
| * @brief Set Asynced ESSID |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * @param bBSSID A variable that bssid is set or not |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_assocessid(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen, |
| t_u8 bBSSID) |
| { |
| mlan_ssid_bssid ssid_bssid; |
| moal_handle *handle = priv->phandle; |
| int ret = 0; |
| int header_len = 0; |
| int copy_len = 0; |
| char buf[64]; |
| t_u8 buflen = 0; |
| t_u8 i = 0; |
| t_u8 mac_idx = 0; |
| |
| ENTER(); |
| |
| if (bBSSID) |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ASSOCBSSID); |
| else |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ASSOCESSID); |
| |
| if ((int)strlen(respbuf) == header_len) { |
| PRINTM(MERROR, "No argument, invalid operation!\n"); |
| ret = -EINVAL; |
| LEAVE(); |
| return ret; |
| } |
| copy_len = strlen(respbuf) - header_len; |
| buflen = MIN(copy_len, (int)(sizeof(buf) - 1)); |
| memset(buf, 0, sizeof(buf)); |
| memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid)); |
| moal_memcpy_ext(handle, buf, respbuf + header_len, buflen, sizeof(buf)); |
| priv->assoc_with_mac = MFALSE; |
| |
| /* check if has parameter BSSID */ |
| if (bBSSID) { |
| if (buflen < (3 * ETH_ALEN) + 2) { |
| PRINTM(MERROR, |
| "Associate: Insufficient length in IOCTL input\n"); |
| /* buffer should be at least 3 characters per BSSID |
| *octet "00:" |
| ** plus a space separater and at least 1 char in the |
| *SSID |
| */ |
| ret = -EINVAL; |
| goto setessid_ret; |
| } |
| for (; (i < buflen) && (mac_idx < ETH_ALEN) && (buf[i] != ' '); |
| i++) { |
| if (buf[i] == ':') { |
| mac_idx++; |
| } else { |
| ssid_bssid.bssid[mac_idx] = |
| (t_u8)woal_atox(buf + i); |
| while ((i < buflen) && isxdigit(buf[i + 1])) |
| /* Skip entire hex value */ |
| i++; |
| } |
| } |
| /* Skip one space between the BSSID and start of the SSID */ |
| i++; |
| PRINTM(MMSG, "Trying to associate AP BSSID = [" MACSTR "]\n", |
| MAC2STR(ssid_bssid.bssid)); |
| priv->assoc_with_mac = MTRUE; |
| } |
| |
| ssid_bssid.ssid.ssid_len = buflen - i; |
| /* Check the size of the ssid_len */ |
| if (ssid_bssid.ssid.ssid_len > MLAN_MAX_SSID_LENGTH + 1) { |
| PRINTM(MERROR, "ssid_bssid.ssid.ssid_len = %d\n", |
| ssid_bssid.ssid.ssid_len); |
| ret = -E2BIG; |
| goto setessid_ret; |
| } |
| |
| /* Copy the SSID */ |
| moal_memcpy_ext(handle, ssid_bssid.ssid.ssid, buf + i, |
| ssid_bssid.ssid.ssid_len, MLAN_MAX_SSID_LENGTH); |
| |
| if (!ssid_bssid.ssid.ssid_len || |
| (MFALSE == woal_ssid_valid(&ssid_bssid.ssid))) { |
| PRINTM(MERROR, "Invalid SSID - aborting set_essid\n"); |
| ret = -EINVAL; |
| goto setessid_ret; |
| } |
| |
| PRINTM(MMSG, "Trying to associate AP SSID = %s\n", |
| (char *)ssid_bssid.ssid.ssid); |
| |
| /* Cancel re-association */ |
| priv->reassoc_required = MFALSE; |
| |
| if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) { |
| PRINTM(MERROR, "Acquire semaphore error, woal_set_essid\n"); |
| ret = -EBUSY; |
| LEAVE(); |
| return ret; |
| } |
| |
| if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE) |
| woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE); |
| |
| if (MTRUE == woal_is_connected(priv, &ssid_bssid)) { |
| PRINTM(MIOCTL, "Already connect to the network\n"); |
| ret = sprintf(respbuf, |
| "Has already connected to this ESSID!\n") + 1; |
| goto setessid_ret; |
| } |
| moal_memcpy_ext(handle, &priv->prev_ssid_bssid, &ssid_bssid, |
| sizeof(mlan_ssid_bssid), sizeof(mlan_ssid_bssid)); |
| /* disconnect before driver assoc */ |
| woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL, DEF_DEAUTH_REASON_CODE); |
| priv->set_asynced_essid_flag = MTRUE; |
| priv->reassoc_required = MTRUE; |
| priv->phandle->is_reassoc_timer_set = MTRUE; |
| woal_mod_timer(&priv->phandle->reassoc_timer, 0); |
| ret = sprintf(respbuf, "%s\n", buf) + 1; |
| |
| setessid_ret: |
| if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE) |
| woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE); |
| MOAL_REL_SEMAPHORE(&handle->reassoc_sem); |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| |
| /** |
| * @brief Get wakeup reason |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_getwakeupreason(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_pm_cfg *pm_cfg = NULL; |
| t_u32 data; |
| int ret = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (strlen(respbuf) == |
| (strlen(CMD_NXP) + strlen(PRIV_CMD_WAKEUPREASON))) { |
| /* GET operation */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg)); |
| if (req == NULL) { |
| LEAVE(); |
| return -ENOMEM; |
| } |
| |
| pm_cfg = (mlan_ds_pm_cfg *)req->pbuf; |
| pm_cfg->sub_command = MLAN_OID_PM_HS_WAKEUP_REASON; |
| 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; |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| goto done; |
| } else { |
| data = pm_cfg->param.wakeup_reason.hs_wakeup_reason; |
| sprintf(respbuf, " %d", data); |
| ret = strlen(respbuf) + 1; |
| kfree(req); |
| } |
| } else { |
| PRINTM(MERROR, "Not need argument, invalid operation!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| #ifdef STA_SUPPORT |
| /** |
| * @brief Set / Get listen interval |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_set_get_listeninterval(moal_private *priv, t_u8 *respbuf, |
| t_u32 respbuflen) |
| { |
| int data[1]; |
| int user_data_len = 0; |
| int ret = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_bss *pcfg_bss = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (strlen(respbuf) == |
| (strlen(CMD_NXP) + strlen(PRIV_CMD_LISTENINTERVAL))) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| memset((char *)data, 0, sizeof(data)); |
| parse_arguments(respbuf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_LISTENINTERVAL), |
| data, ARRAY_SIZE(data), &user_data_len); |
| } |
| |
| if (user_data_len > 1) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| /* Allocate an IOCTL request buffer */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| /* Fill request buffer */ |
| pcfg_bss = (mlan_ds_bss *)req->pbuf; |
| pcfg_bss->sub_command = MLAN_OID_BSS_LISTEN_INTERVAL; |
| req->req_id = MLAN_IOCTL_BSS; |
| |
| if (user_data_len) { |
| pcfg_bss->param.listen_interval = (t_u16)data[0]; |
| req->action = MLAN_ACT_SET; |
| } else { |
| req->action = MLAN_ACT_GET; |
| } |
| |
| /* Send IOCTL request to MLAN */ |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| if (req->action == MLAN_ACT_GET) { |
| sprintf(respbuf, "%d", pcfg_bss->param.listen_interval); |
| ret = strlen(respbuf) + 1; |
| } else { |
| ret = sprintf(respbuf, "OK\n") + 1; |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| |
| #ifdef DEBUG_LEVEL1 |
| /** |
| * @brief Set / Get driver debug level |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_set_get_drvdbg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int data[4]; |
| int user_data_len = 0; |
| int ret = 0; |
| |
| ENTER(); |
| |
| if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_DRVDBG))) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| memset((char *)data, 0, sizeof(data)); |
| parse_arguments(respbuf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_DRVDBG), |
| data, ARRAY_SIZE(data), &user_data_len); |
| } |
| |
| if (user_data_len > 1) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| if (user_data_len) { |
| /* Get the driver debug bit masks from user */ |
| drvdbg = data[0]; |
| /* Set the driver debug bit masks into mlan */ |
| if (woal_set_drvdbg(priv, drvdbg)) { |
| PRINTM(MERROR, "Set drvdbg failed!\n"); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| } |
| |
| ret = sizeof(drvdbg); |
| |
| moal_memcpy_ext(priv->phandle, respbuf, &drvdbg, sizeof(drvdbg), |
| respbuflen); |
| |
| printk(KERN_ALERT "drvdbg = 0x%08x\n", drvdbg); |
| #ifdef DEBUG_LEVEL2 |
| printk(KERN_ALERT "MINFO (%08x) %s\n", MINFO, |
| (drvdbg & MINFO) ? "X" : ""); |
| printk(KERN_ALERT "MWARN (%08x) %s\n", MWARN, |
| (drvdbg & MWARN) ? "X" : ""); |
| printk(KERN_ALERT "MENTRY (%08x) %s\n", MENTRY, |
| (drvdbg & MENTRY) ? "X" : ""); |
| #endif |
| printk(KERN_ALERT "MMPA_D (%08x) %s\n", MMPA_D, |
| (drvdbg & MMPA_D) ? "X" : ""); |
| printk(KERN_ALERT "MIF_D (%08x) %s\n", MIF_D, |
| (drvdbg & MIF_D) ? "X" : ""); |
| printk(KERN_ALERT "MFW_D (%08x) %s\n", MFW_D, |
| (drvdbg & MFW_D) ? "X" : ""); |
| printk(KERN_ALERT "MEVT_D (%08x) %s\n", MEVT_D, |
| (drvdbg & MEVT_D) ? "X" : ""); |
| printk(KERN_ALERT "MCMD_D (%08x) %s\n", MCMD_D, |
| (drvdbg & MCMD_D) ? "X" : ""); |
| printk(KERN_ALERT "MDAT_D (%08x) %s\n", MDAT_D, |
| (drvdbg & MDAT_D) ? "X" : ""); |
| printk(KERN_ALERT "MREG_D (%08x) %s\n", MREG_D, |
| (drvdbg & MREG_D) ? "X" : ""); |
| printk(KERN_ALERT "MIOCTL (%08x) %s\n", MIOCTL, |
| (drvdbg & MIOCTL) ? "X" : ""); |
| printk(KERN_ALERT "MINTR (%08x) %s\n", MINTR, |
| (drvdbg & MINTR) ? "X" : ""); |
| printk(KERN_ALERT "MEVENT (%08x) %s\n", MEVENT, |
| (drvdbg & MEVENT) ? "X" : ""); |
| printk(KERN_ALERT "MCMND (%08x) %s\n", MCMND, |
| (drvdbg & MCMND) ? "X" : ""); |
| printk(KERN_ALERT "MDATA (%08x) %s\n", MDATA, |
| (drvdbg & MDATA) ? "X" : ""); |
| printk(KERN_ALERT "MERROR (%08x) %s\n", MERROR, |
| (drvdbg & MERROR) ? "X" : ""); |
| printk(KERN_ALERT "MFATAL (%08x) %s\n", MFATAL, |
| (drvdbg & MFATAL) ? "X" : ""); |
| printk(KERN_ALERT "MMSG (%08x) %s\n", MMSG, |
| (drvdbg & MMSG) ? "X" : ""); |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| #endif |
| |
| /** |
| * @brief management frame filter wakeup config |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return 0 --success, otherwise fail |
| */ |
| static int |
| woal_priv_mgmt_filter(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ioctl_req *ioctl_req = NULL; |
| mlan_ds_pm_cfg *pm_cfg = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| int header_len = 0, data_len = 0; |
| int ret = 0; |
| t_u16 action; |
| t_u8 *argument; |
| |
| ENTER(); |
| |
| if (!priv || !priv->phandle) { |
| PRINTM(MERROR, "priv or handle is null\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; |
| } |
| |
| pm_cfg = (mlan_ds_pm_cfg *)ioctl_req->pbuf; |
| pm_cfg->sub_command = MLAN_OID_PM_MGMT_FILTER; |
| ioctl_req->req_id = MLAN_IOCTL_PM_CFG; |
| |
| header_len = strlen(PRIV_CMD_MGMT_FILTER) + strlen(CMD_NXP); |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| argument = (t_u8 *)(respbuf + header_len); |
| data_len = respbuflen - header_len; |
| if (data_len > |
| (int)(MAX_MGMT_FRAME_FILTER * |
| sizeof(mlan_mgmt_frame_wakeup))) { |
| PRINTM(MERROR, "%d: Invalid arguments\n", __LINE__); |
| ret = -EINVAL; |
| goto done; |
| } |
| moal_memcpy_ext(priv->phandle, |
| (t_u8 *)pm_cfg->param.mgmt_filter, argument, |
| data_len, sizeof(pm_cfg->param.mgmt_filter)); |
| action = MLAN_ACT_SET; |
| } |
| |
| ioctl_req->action = action; |
| status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(ioctl_req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| #define PARAMETER_GPIO_INDICATION 1 |
| #define PARAMETER_EXTEND_HSCFG 2 |
| #define PARAMETER_HS_WAKEUP_INTERVAL 3 |
| /** |
| * @brief Set/Get Host Sleep configuration |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * @param invoke_hostcmd MTRUE --invoke HostCmd, otherwise MFALSE |
| * |
| * @return 0 --success, otherwise fail |
| */ |
| static int |
| woal_priv_hscfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen, |
| BOOLEAN invoke_hostcmd) |
| { |
| int data[13] = { 0 }; |
| int *temp_data, type; |
| int user_data_len = 0; |
| int ret = 0; |
| mlan_ds_hs_cfg hscfg, hscfg_temp; |
| t_u16 action; |
| mlan_bss_info bss_info; |
| int is_negative = MFALSE; |
| t_u8 *arguments = NULL; |
| |
| ENTER(); |
| |
| memset(data, 0, sizeof(data)); |
| memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg)); |
| memset(&hscfg_temp, 0, sizeof(mlan_ds_hs_cfg)); |
| |
| if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_HSCFG))) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| memset((char *)data, 0, sizeof(data)); |
| arguments = respbuf + strlen(CMD_NXP) + strlen(PRIV_CMD_HSCFG); |
| if (*arguments == '-') { |
| is_negative = MTRUE; |
| arguments += 1; |
| } |
| parse_arguments(arguments, data, ARRAY_SIZE(data), |
| &user_data_len); |
| |
| if (is_negative == MTRUE) { |
| if (data[0] == 1) { |
| data[0] = -1; |
| } else { |
| PRINTM(MERROR, "Invalid arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| } |
| |
| if (sizeof(int) * user_data_len > sizeof(data)) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| LEAVE(); |
| return -EINVAL; |
| } |
| |
| if (user_data_len == 0) { |
| action = MLAN_ACT_GET; |
| } else { |
| if (user_data_len >= 1 && user_data_len <= 13) { |
| action = MLAN_ACT_SET; |
| } else { |
| PRINTM(MERROR, "Invalid arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| |
| /* HS config is blocked if HS is already activated */ |
| if (user_data_len && |
| (data[0] != (int)HOST_SLEEP_CFG_CANCEL || |
| invoke_hostcmd == MFALSE)) { |
| memset(&bss_info, 0, sizeof(bss_info)); |
| woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info); |
| if (bss_info.is_hs_configured) { |
| PRINTM(MERROR, "HS already configured\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| } |
| |
| /* Do a GET first if some arguments are not provided */ |
| if (user_data_len >= 1 && user_data_len < 11) { |
| woal_set_get_hs_params(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT, |
| &hscfg_temp); |
| } |
| hscfg.conditions = hscfg_temp.conditions; |
| hscfg.gpio = hscfg_temp.gpio; |
| hscfg.gap = hscfg_temp.gap; |
| |
| if (user_data_len) |
| hscfg.conditions = data[0]; |
| if (user_data_len >= 2) |
| hscfg.gpio = data[1]; |
| if (user_data_len >= 3) |
| hscfg.gap = data[2]; |
| user_data_len = user_data_len - 3; |
| if (user_data_len > 0) { |
| temp_data = data + 3; |
| while ((user_data_len > 0) && temp_data) { |
| type = *temp_data; |
| switch (type) { |
| case PARAMETER_GPIO_INDICATION: |
| if (user_data_len >= 2) |
| hscfg.ind_gpio = *(++temp_data); |
| else { |
| PRINTM(MERROR, |
| "Invaild number of parameters\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (user_data_len >= 3) { |
| hscfg.level = *(++temp_data); |
| if (hscfg.level != 0 && |
| hscfg.level != 1) { |
| PRINTM(MERROR, |
| "Invalid indication gpio arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| hscfg.param_type_ind = type; |
| user_data_len = user_data_len - 3; |
| temp_data++; |
| break; |
| case PARAMETER_EXTEND_HSCFG: |
| if (user_data_len >= 4) { |
| hscfg.event_force_ignore = |
| *(++temp_data); |
| hscfg.event_use_ext_gap = |
| *(++temp_data); |
| hscfg.ext_gap = *(++temp_data); |
| hscfg.gpio_wave = *(++temp_data); |
| } else { |
| PRINTM(MERROR, |
| "Invaild number of parameters\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| /* Force_ignore_gpio and ext_gap_gpio should not |
| * set the same bit(s)*/ |
| if ((hscfg.event_force_ignore & |
| hscfg.event_use_ext_gap) || |
| (hscfg.gpio_wave != 1 && |
| hscfg.gpio_wave != 0)) { |
| PRINTM(MERROR, |
| "Invalid arguments for extend hscfg\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| hscfg.param_type_ext = type; |
| user_data_len = user_data_len - 5; |
| temp_data++; |
| break; |
| case PARAMETER_HS_WAKEUP_INTERVAL: |
| if (user_data_len >= 2) |
| hscfg.hs_wake_interval = *(++temp_data); |
| else { |
| PRINTM(MERROR, |
| "Invaild number of parameters\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| user_data_len = user_data_len - 2; |
| temp_data++; |
| break; |
| default: |
| PRINTM(MERROR, "Unsupported type\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| } |
| |
| if ((invoke_hostcmd == MTRUE) && (action == MLAN_ACT_SET)) { |
| /* Need to issue an extra IOCTL first to set up parameters */ |
| hscfg.is_invoke_hostcmd = MFALSE; |
| if (MLAN_STATUS_SUCCESS != |
| woal_set_get_hs_params(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT, |
| &hscfg)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| } |
| hscfg.is_invoke_hostcmd = invoke_hostcmd; |
| if (MLAN_STATUS_SUCCESS != |
| woal_set_get_hs_params(priv, action, MOAL_IOCTL_WAIT, &hscfg)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| if (action == MLAN_ACT_GET) { |
| /* Return the current driver host sleep configurations */ |
| moal_memcpy_ext(priv->phandle, respbuf, &hscfg, |
| sizeof(mlan_ds_hs_cfg), respbuflen); |
| ret = sizeof(mlan_ds_hs_cfg); |
| } |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set Host Sleep parameters |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return 0 --success, otherwise fail |
| */ |
| static int |
| woal_priv_hssetpara(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int data[13] = { 0 }; |
| int user_data_len = 0; |
| int ret = 0; |
| |
| ENTER(); |
| |
| if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_HSSETPARA))) { |
| PRINTM(MERROR, "Invalid arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } else { |
| /* SET operation */ |
| memset((char *)data, 0, sizeof(data)); |
| parse_arguments(respbuf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_HSSETPARA), |
| data, ARRAY_SIZE(data), &user_data_len); |
| } |
| |
| if (sizeof(int) * user_data_len > sizeof(data)) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| LEAVE(); |
| return -EINVAL; |
| } |
| |
| if (user_data_len >= 1 && user_data_len <= 13) { |
| sprintf(respbuf, "%s%s%s", CMD_NXP, PRIV_CMD_HSCFG, |
| respbuf + |
| (strlen(CMD_NXP) + strlen(PRIV_CMD_HSSETPARA))); |
| respbuflen = strlen(respbuf); |
| ret = woal_priv_hscfg(priv, respbuf, respbuflen, MFALSE); |
| goto done; |
| } |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get scan configuration parameters |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return 0 --success, otherwise fail |
| */ |
| static int |
| woal_priv_set_get_scancfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| int user_data_len = 0; |
| int data[9]; |
| mlan_ds_scan *scan = NULL; |
| mlan_ioctl_req *req = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| memset(data, 0, sizeof(data)); |
| if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_SCANCFG))) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| memset((char *)data, 0, sizeof(data)); |
| parse_arguments(respbuf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_SCANCFG), |
| data, ARRAY_SIZE(data), &user_data_len); |
| } |
| |
| if (sizeof(int) * user_data_len > sizeof(data)) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| LEAVE(); |
| return -EINVAL; |
| } |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_scan)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| scan = (mlan_ds_scan *)req->pbuf; |
| scan->sub_command = MLAN_OID_SCAN_CONFIG; |
| req->req_id = MLAN_IOCTL_SCAN; |
| |
| if (user_data_len) { |
| if ((data[0] < 0) || (data[0] > MLAN_SCAN_TYPE_PASSIVE)) { |
| PRINTM(MERROR, "Invalid argument for scan type\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if ((data[1] < 0) || (data[1] > MLAN_SCAN_MODE_ANY)) { |
| PRINTM(MERROR, "Invalid argument for scan mode\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if ((data[2] < 0) || (data[2] > MAX_PROBES)) { |
| PRINTM(MERROR, "Invalid argument for scan probes\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (((data[3] < 0) || |
| (data[3] > MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME)) || |
| ((data[4] < 0) || |
| (data[4] > MRVDRV_MAX_ACTIVE_SCAN_CHAN_TIME)) || |
| ((data[5] < 0) || |
| (data[5] > MRVDRV_MAX_PASSIVE_SCAN_CHAN_TIME))) { |
| PRINTM(MERROR, "Invalid argument for scan time\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if ((data[6] < 0) || (data[6] > MLAN_PASS_TO_ACT_SCAN_DIS)) { |
| PRINTM(MERROR, |
| "Invalid argument for Passive to Active Scan\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if ((data[7] < 0) || (data[7] > 3)) { |
| PRINTM(MERROR, "Invalid argument for extended scan\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if ((data[8] < 0) || (data[8] > MRVDRV_MAX_SCAN_CHAN_GAP_TIME)) { |
| PRINTM(MERROR, |
| "Invalid argument for scan channel gap\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| req->action = MLAN_ACT_SET; |
| moal_memcpy_ext(priv->phandle, &scan->param.scan_cfg, data, |
| sizeof(data), sizeof(scan->param.scan_cfg)); |
| } else |
| req->action = MLAN_ACT_GET; |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| moal_memcpy_ext(priv->phandle, respbuf, &scan->param.scan_cfg, |
| sizeof(mlan_scan_cfg), respbuflen); |
| ret = sizeof(mlan_scan_cfg); |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get Netlink Number |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_getnlnum(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| int data = 0; |
| |
| ENTER(); |
| |
| if (!priv || !priv->phandle) { |
| PRINTM(MERROR, "priv or handle is null in %s\n", __FUNCTION__); |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| data = priv->phandle->netlink_num; |
| moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data), |
| respbuflen); |
| ret = sizeof(data); |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set / Get packet aggregation control |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_set_get_aggrctrl(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int data[1]; |
| int user_data_len = 0; |
| int ret = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *pcfg_misc = NULL; |
| moal_handle *handle = priv->phandle; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (!handle || !handle->card) { |
| PRINTM(MERROR, "Handle or card is null\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| memset((char *)data, 0, sizeof(data)); |
| if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_AGGRCTRL))) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| if (woal_is_any_interface_active(priv->phandle)) { |
| PRINTM(MERROR, |
| "aggrctrl are not allowed to change after BSS active!\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| /* SET operation */ |
| parse_arguments(respbuf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_AGGRCTRL), |
| data, ARRAY_SIZE(data), &user_data_len); |
| |
| if (sizeof(int) * user_data_len > sizeof(data)) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| |
| /* Allocate an IOCTL request buffer */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| /* Fill request buffer */ |
| pcfg_misc = (mlan_ds_misc_cfg *)req->pbuf; |
| pcfg_misc->sub_command = MLAN_OID_MISC_AGGR_CTRL; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| |
| /* Get the values first, then modify these values if user had modified |
| * them */ |
| if (user_data_len == 0) |
| req->action = MLAN_ACT_GET; |
| else { |
| req->action = MLAN_ACT_SET; |
| pcfg_misc->param.aggr_params.tx.enable = (t_u16)data[0]; |
| } |
| |
| /* Send IOCTL request to MLAN */ |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| /* MLAN will return CMD_INVALID if FW does not support this |
| * feature */ |
| if (MLAN_ERROR_CMD_INVALID == req->status_code) |
| ret = -EOPNOTSUPP; |
| else |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| moal_memcpy_ext(handle, respbuf, (t_u8 *)&pcfg_misc->param.aggr_params, |
| sizeof(mlan_ds_misc_aggr_ctrl), respbuflen); |
| ret = sizeof(mlan_ds_misc_aggr_ctrl); |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| #ifdef USB |
| /** |
| * @brief Set / Get USB packet aggregation control |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_set_get_usbaggrctrl(moal_private *priv, t_u8 *respbuf, |
| t_u32 respbuflen) |
| { |
| int data[8]; |
| int user_data_len = 0; |
| int ret = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *pcfg_misc = NULL; |
| moal_handle *handle = priv->phandle; |
| struct usb_card_rec *cardp = NULL; |
| int i = 0, usb_resubmit_urbs = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (!handle || !handle->card) { |
| PRINTM(MERROR, "Handle or card is null\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| cardp = (struct usb_card_rec *)handle->card; |
| |
| memset((char *)data, 0, sizeof(data)); |
| if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_USBAGGRCTRL))) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_USBAGGRCTRL), |
| data, ARRAY_SIZE(data), &user_data_len); |
| |
| if (sizeof(int) * user_data_len > sizeof(data)) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| |
| /* Allocate an IOCTL request buffer */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| /* Fill request buffer */ |
| 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; |
| |
| /* Get the values first, then modify these values if user had modified |
| * them */ |
| req->action = MLAN_ACT_GET; |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| /* MLAN will return CMD_INVALID if FW does not support this |
| * feature */ |
| if (MLAN_ERROR_CMD_INVALID == req->status_code) |
| ret = -EOPNOTSUPP; |
| else |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| if (user_data_len == 0) { |
| moal_memcpy_ext(handle, respbuf, |
| (t_u8 *)&pcfg_misc->param.usb_aggr_params, |
| sizeof(mlan_ds_misc_usb_aggr_ctrl), respbuflen); |
| ret = sizeof(mlan_ds_misc_usb_aggr_ctrl); |
| goto done; |
| } |
| |
| switch (user_data_len) { |
| case 8: |
| if (data[7] < 0) { |
| PRINTM(MERROR, "Invalid Rx timeout value (%d)\n", |
| data[7]); |
| ret = -EINVAL; |
| goto done; |
| } |
| pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.aggr_tmo = |
| (t_u16)data[7]; |
| /* fall through */ |
| case 7: |
| if (data[6] < 0 || (data[6] > 10000 && |
| data[6] != MLAN_USB_TX_AGGR_TIMEOUT_DYN)) { |
| PRINTM(MERROR, "Invalid Tx timeout value (%d)\n", |
| data[6]); |
| ret = -EINVAL; |
| goto done; |
| } |
| pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.aggr_tmo = |
| (t_u16)data[6]; |
| /* fall through */ |
| case 6: |
| if ((data[5] < 512) || ((data[5] % 512) != 0)) { |
| PRINTM(MERROR, "Invalid Rx alignment value (%d)\n", |
| data[5]); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (cardp->rx_deaggr_ctrl.enable && |
| pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl. |
| aggr_align != (t_u16)data[5]) |
| usb_resubmit_urbs = 1; |
| pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.aggr_align = |
| (t_u16)data[5]; |
| /* fall through */ |
| case 5: |
| if ((data[4] < 2048) || ((data[4] % 2048) != 0)) { |
| PRINTM(MERROR, "Invalid Tx alignment value (%d)\n", |
| data[4]); |
| ret = -EINVAL; |
| goto done; |
| } |
| pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.aggr_align = |
| (t_u16)data[4]; |
| /* fall through */ |
| case 4: |
| if ((data[3] == 2) || (data[3] == 4) || (data[3] == 8) || |
| (data[3] == 16)) { |
| pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl. |
| aggr_mode = MLAN_USB_AGGR_MODE_NUM; |
| } else if ((data[3] == 4096) || (data[3] == 8192) || |
| (data[3] == 16384) || (data[3] == 32768)) { |
| pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl. |
| aggr_mode = MLAN_USB_AGGR_MODE_LEN; |
| } else { |
| PRINTM(MERROR, "Invalid Rx max size/num value (%d)\n", |
| data[3]); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (cardp->rx_deaggr_ctrl.enable && |
| pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.aggr_max != |
| (t_u16)data[3]) |
| usb_resubmit_urbs = 1; |
| pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.aggr_max = |
| (t_u16)data[3]; |
| /* fall through */ |
| case 3: |
| if ((data[2] == 2) || (data[2] == 4) || (data[2] == 8) || |
| (data[2] == 16)) { |
| pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl. |
| aggr_mode = MLAN_USB_AGGR_MODE_NUM; |
| } else if ((data[2] == 4096) || (data[2] == 8192) || |
| (data[2] == 16384) || (data[2] == 32768)) { |
| pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl. |
| aggr_mode = MLAN_USB_AGGR_MODE_LEN; |
| } else { |
| PRINTM(MERROR, "Invalid Tx max size/num value (%d)\n", |
| data[2]); |
| ret = -EINVAL; |
| goto done; |
| } |
| pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.aggr_max = |
| (t_u16)data[2]; |
| /* fall through */ |
| case 2: |
| if ((data[1] != 0) && (data[1] != 1)) { |
| PRINTM(MERROR, "Invalid Rx enable value (%d)\n", |
| data[1]); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.enable != |
| (t_u16)data[1]) |
| usb_resubmit_urbs = 1; |
| pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl.enable = |
| (t_u16)data[1]; |
| /* fall through */ |
| case 1: |
| if ((data[0] != 0) && (data[0] != 1)) { |
| PRINTM(MERROR, "Invalid Tx enable value (%d)\n", |
| data[0]); |
| ret = -EINVAL; |
| goto done; |
| } |
| pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl.enable = |
| (t_u16)data[0]; |
| default: |
| break; |
| } |
| |
| pcfg_misc->sub_command = MLAN_OID_MISC_USB_AGGR_CTRL; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| 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; |
| } |
| |
| moal_memcpy_ext(handle, respbuf, |
| (t_u8 *)&pcfg_misc->param.usb_aggr_params, |
| sizeof(mlan_ds_misc_usb_aggr_ctrl), respbuflen); |
| ret = sizeof(mlan_ds_misc_usb_aggr_ctrl); |
| |
| /* Keep a copy of the latest Tx aggregation parameters in MOAL */ |
| moal_memcpy_ext(handle, &cardp->tx_aggr_ctrl, |
| &pcfg_misc->param.usb_aggr_params.tx_aggr_ctrl, |
| sizeof(usb_aggr_ctrl_cfg), sizeof(usb_aggr_ctrl_cfg)); |
| |
| if (usb_resubmit_urbs) { |
| /* Indicate resubmition from here */ |
| cardp->resubmit_urbs = 1; |
| /* Rx SG parameters has changed or disabled, 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); |
| } |
| } |
| } |
| } |
| |
| /* Keep a copy of the latest Rx deaggregation parameters in MOAL */ |
| moal_memcpy_ext(handle, &cardp->rx_deaggr_ctrl, |
| &pcfg_misc->param.usb_aggr_params.rx_deaggr_ctrl, |
| sizeof(usb_aggr_ctrl_cfg), sizeof(usb_aggr_ctrl_cfg)); |
| |
| if (usb_resubmit_urbs) { |
| /* 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 (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| |
| #ifdef STA_SUPPORT |
| /** |
| * @brief Set AP settings |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written if successful, otherwise fail |
| */ |
| static int |
| woal_priv_set_ap(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| t_u8 *data_ptr; |
| const t_u8 bcast[MLAN_MAC_ADDR_LENGTH] = |
| { 255, 255, 255, 255, 255, 255 }; |
| const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = { 0, 0, 0, 0, 0, 0 }; |
| mlan_ssid_bssid ssid_bssid; |
| mlan_bss_info bss_info; |
| struct mwreq *mwr; |
| struct sockaddr *awrq; |
| |
| ENTER(); |
| data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_SET_AP)); |
| |
| mwr = (struct mwreq *)data_ptr; |
| |
| if (mwr->u.ap_addr.sa_family != ARPHRD_ETHER) { |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| awrq = (struct sockaddr *)&(mwr->u.ap_addr); |
| |
| PRINTM(MINFO, "ASSOC: WAP: sa_data: " MACSTR "\n", |
| MAC2STR((t_u8 *)awrq->sa_data)); |
| |
| if (MLAN_STATUS_SUCCESS != |
| woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| #ifdef REASSOCIATION |
| /* Cancel re-association */ |
| priv->reassoc_required = MFALSE; |
| #endif |
| |
| /* zero_mac means disconnect */ |
| if (!memcmp(zero_mac, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) { |
| woal_disconnect(priv, MOAL_IOCTL_WAIT, NULL, |
| DEF_DEAUTH_REASON_CODE); |
| goto done; |
| } |
| |
| /* Broadcast MAC means search for best network */ |
| memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid)); |
| |
| if (memcmp(bcast, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) { |
| /* Check if we are already assoicated to the AP */ |
| if (bss_info.media_connected == MTRUE) { |
| if (!memcmp(awrq->sa_data, &bss_info.bssid, ETH_ALEN)) |
| goto done; |
| } |
| moal_memcpy_ext(priv->phandle, &ssid_bssid.bssid, awrq->sa_data, |
| ETH_ALEN, sizeof(mlan_802_11_mac_addr)); |
| } |
| |
| if (MLAN_STATUS_SUCCESS != |
| woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) { |
| PRINTM(MERROR, |
| "ASSOC: WAP: MAC address not found in BSSID List\n"); |
| ret = -ENETUNREACH; |
| goto done; |
| } |
| /* Zero SSID implies use BSSID to connect */ |
| memset(&ssid_bssid.ssid, 0, sizeof(mlan_802_11_ssid)); |
| if (MLAN_STATUS_SUCCESS != |
| woal_bss_start(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| #ifdef REASSOCIATION |
| memset(&bss_info, 0, sizeof(bss_info)); |
| if (MLAN_STATUS_SUCCESS != |
| woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.ssid, |
| &bss_info.ssid, sizeof(mlan_802_11_ssid), |
| sizeof(mlan_802_11_ssid)); |
| moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.bssid, |
| &bss_info.bssid, MLAN_MAC_ADDR_LENGTH, |
| sizeof(mlan_802_11_mac_addr)); |
| #endif /* REASSOCIATION */ |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| |
| /** |
| * @brief Set BSS mode |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written if successful, otherwise fail |
| */ |
| static int |
| woal_priv_set_bss_mode(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| mlan_ds_bss *bss = NULL; |
| mlan_ioctl_req *req = NULL; |
| struct mwreq *mwr; |
| t_u8 *data_ptr; |
| t_u32 mode; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_SET_BSS_MODE)); |
| |
| mwr = (struct mwreq *)data_ptr; |
| mode = mwr->u.mode; |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| bss = (mlan_ds_bss *)req->pbuf; |
| bss->sub_command = MLAN_OID_BSS_MODE; |
| req->req_id = MLAN_IOCTL_BSS; |
| req->action = MLAN_ACT_SET; |
| |
| switch (mode) { |
| case MW_MODE_INFRA: |
| bss->param.bss_mode = MLAN_BSS_MODE_INFRA; |
| break; |
| case MW_MODE_ADHOC: |
| bss->param.bss_mode = MLAN_BSS_MODE_IBSS; |
| break; |
| case MW_MODE_AUTO: |
| bss->param.bss_mode = MLAN_BSS_MODE_AUTO; |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| if (ret) |
| goto done; |
| 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; |
| } |
| |
| #ifdef STA_SUPPORT |
| /** |
| * @brief Set power management |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written if successful, otherwise fail |
| */ |
| static int |
| woal_priv_set_power(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| struct mwreq *mwr; |
| t_u8 *data_ptr; |
| int ret = 0, disabled; |
| |
| ENTER(); |
| |
| if (moal_extflg_isset(priv->phandle, EXT_HW_TEST)) { |
| PRINTM(MIOCTL, "block set power in hw_test mode\n"); |
| LEAVE(); |
| return ret; |
| } |
| |
| data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_SET_POWER)); |
| |
| mwr = (struct mwreq *)data_ptr; |
| disabled = mwr->u.power.disabled; |
| |
| if (MLAN_STATUS_SUCCESS != |
| woal_set_get_power_mgmt(priv, MLAN_ACT_SET, &disabled, |
| mwr->u.power.flags, MOAL_IOCTL_WAIT)) { |
| return -EFAULT; |
| } |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set essid |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written if successful, otherwise fail |
| */ |
| static int |
| woal_priv_set_essid(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_802_11_ssid req_ssid; |
| mlan_ssid_bssid ssid_bssid; |
| #ifdef REASSOCIATION |
| moal_handle *handle = priv->phandle; |
| mlan_bss_info bss_info; |
| #endif |
| int ret = 0; |
| t_u32 mode = 0; |
| struct mwreq *mwr; |
| t_u8 *data_ptr; |
| |
| ENTER(); |
| |
| data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_SET_ESSID)); |
| |
| mwr = (struct mwreq *)data_ptr; |
| |
| #ifdef REASSOCIATION |
| /* Cancel re-association */ |
| priv->reassoc_required = MFALSE; |
| |
| if (MOAL_ACQ_SEMAPHORE_BLOCK(&handle->reassoc_sem)) { |
| PRINTM(MERROR, "Acquire semaphore error, woal_set_essid\n"); |
| LEAVE(); |
| return -EBUSY; |
| } |
| #endif /* REASSOCIATION */ |
| |
| /* Check the size of the string */ |
| if (mwr->u.essid.length > MW_ESSID_MAX_SIZE - 1) { |
| ret = -E2BIG; |
| goto setessid_ret; |
| } |
| if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE) |
| woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE); |
| memset(&req_ssid, 0, sizeof(mlan_802_11_ssid)); |
| memset(&ssid_bssid, 0, sizeof(mlan_ssid_bssid)); |
| |
| req_ssid.ssid_len = mwr->u.essid.length; |
| |
| /* Check if we asked for 'any' or 'particular' */ |
| if (!mwr->u.essid.flags) { |
| #ifdef REASSOCIATION |
| if (!req_ssid.ssid_len) { |
| memset(&priv->prev_ssid_bssid.ssid, 0x00, |
| sizeof(mlan_802_11_ssid)); |
| memset(&priv->prev_ssid_bssid.bssid, 0x00, |
| MLAN_MAC_ADDR_LENGTH); |
| goto setessid_ret; |
| } |
| #endif |
| /* Do normal SSID scanning */ |
| if (MLAN_STATUS_SUCCESS != |
| woal_request_scan(priv, MOAL_IOCTL_WAIT, NULL)) { |
| ret = -EFAULT; |
| goto setessid_ret; |
| } |
| } else { |
| /* Set the SSID */ |
| moal_memcpy_ext(handle, req_ssid.ssid, mwr->u.essid.pointer, |
| req_ssid.ssid_len, MLAN_MAX_SSID_LENGTH); |
| if (!req_ssid.ssid_len || |
| (MFALSE == woal_ssid_valid(&req_ssid))) { |
| PRINTM(MERROR, "Invalid SSID - aborting set_essid\n"); |
| ret = -EINVAL; |
| goto setessid_ret; |
| } |
| |
| PRINTM(MINFO, "Requested new SSID = %s\n", |
| (char *)req_ssid.ssid); |
| moal_memcpy_ext(handle, &ssid_bssid.ssid, &req_ssid, |
| sizeof(mlan_802_11_ssid), |
| sizeof(mlan_802_11_ssid)); |
| if (MTRUE == woal_is_connected(priv, &ssid_bssid)) { |
| PRINTM(MIOCTL, "Already connect to the network\n"); |
| goto setessid_ret; |
| } |
| |
| if (mwr->u.essid.flags != 0xFFFF) { |
| if (MLAN_STATUS_SUCCESS != |
| woal_find_essid(priv, &ssid_bssid, |
| MOAL_IOCTL_WAIT)) { |
| /* Do specific SSID scanning */ |
| if (MLAN_STATUS_SUCCESS != |
| woal_request_scan(priv, MOAL_IOCTL_WAIT, |
| &req_ssid)) { |
| ret = -EFAULT; |
| goto setessid_ret; |
| } |
| } |
| } |
| } |
| |
| mode = woal_get_mode(priv, MOAL_IOCTL_WAIT); |
| |
| if (mode != MW_MODE_ADHOC) { |
| if (MLAN_STATUS_SUCCESS != |
| woal_find_best_network(priv, MOAL_IOCTL_WAIT, |
| &ssid_bssid)) { |
| ret = -EFAULT; |
| goto setessid_ret; |
| } |
| } |
| #ifdef UAP_SUPPORT |
| else if (MLAN_STATUS_SUCCESS != |
| woal_find_best_network(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) |
| /* Adhoc start, Check the channel command */ |
| woal_11h_channel_check_ioctl(priv, MOAL_IOCTL_WAIT); |
| #endif |
| |
| /* Connect to BSS by ESSID */ |
| memset(&ssid_bssid.bssid, 0, MLAN_MAC_ADDR_LENGTH); |
| |
| if (MLAN_STATUS_SUCCESS != |
| woal_bss_start(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) { |
| ret = -EFAULT; |
| goto setessid_ret; |
| } |
| #ifdef REASSOCIATION |
| memset(&bss_info, 0, sizeof(bss_info)); |
| if (MLAN_STATUS_SUCCESS != |
| woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) { |
| ret = -EFAULT; |
| goto setessid_ret; |
| } |
| moal_memcpy_ext(handle, &priv->prev_ssid_bssid.ssid, &bss_info.ssid, |
| sizeof(mlan_802_11_ssid), sizeof(mlan_802_11_ssid)); |
| moal_memcpy_ext(handle, &priv->prev_ssid_bssid.bssid, &bss_info.bssid, |
| MLAN_MAC_ADDR_LENGTH, sizeof(mlan_802_11_mac_addr)); |
| #endif /* REASSOCIATION */ |
| |
| setessid_ret: |
| if (priv->scan_type == MLAN_SCAN_TYPE_PASSIVE) |
| woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE); |
| #ifdef REASSOCIATION |
| MOAL_REL_SEMAPHORE(&handle->reassoc_sem); |
| #endif |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set authentication mode parameters |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written if successful, otherwise fail |
| */ |
| static int |
| woal_priv_set_auth(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| struct mwreq *mwr; |
| t_u8 *data_ptr; |
| int ret = 0; |
| t_u32 auth_mode = 0; |
| t_u32 encrypt_mode = 0; |
| |
| ENTER(); |
| |
| data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_SET_AUTH)); |
| |
| mwr = (struct mwreq *)data_ptr; |
| |
| switch (mwr->u.param.flags & MW_AUTH_INDEX) { |
| case MW_AUTH_CIPHER_PAIRWISE: |
| case MW_AUTH_CIPHER_GROUP: |
| if (mwr->u.param.value & MW_AUTH_CIPHER_NONE) |
| encrypt_mode = MLAN_ENCRYPTION_MODE_NONE; |
| else if (mwr->u.param.value & MW_AUTH_CIPHER_WEP40) |
| encrypt_mode = MLAN_ENCRYPTION_MODE_WEP40; |
| else if (mwr->u.param.value & MW_AUTH_CIPHER_WEP104) |
| encrypt_mode = MLAN_ENCRYPTION_MODE_WEP104; |
| else if (mwr->u.param.value & MW_AUTH_CIPHER_TKIP) |
| encrypt_mode = MLAN_ENCRYPTION_MODE_TKIP; |
| else if (mwr->u.param.value & MW_AUTH_CIPHER_CCMP) |
| encrypt_mode = MLAN_ENCRYPTION_MODE_CCMP; |
| if (MLAN_STATUS_SUCCESS != |
| woal_set_encrypt_mode(priv, MOAL_IOCTL_WAIT, encrypt_mode)) |
| ret = -EFAULT; |
| break; |
| case MW_AUTH_80211_AUTH_ALG: |
| switch (mwr->u.param.value) { |
| case MW_AUTH_ALG_SHARED_KEY: |
| PRINTM(MINFO, "Auth mode shared key!\n"); |
| auth_mode = MLAN_AUTH_MODE_SHARED; |
| break; |
| case MW_AUTH_ALG_LEAP: |
| PRINTM(MINFO, "Auth mode LEAP!\n"); |
| auth_mode = MLAN_AUTH_MODE_NETWORKEAP; |
| break; |
| case MW_AUTH_ALG_OPEN_SYSTEM: |
| PRINTM(MINFO, "Auth mode open!\n"); |
| auth_mode = MLAN_AUTH_MODE_OPEN; |
| break; |
| case MW_AUTH_ALG_SHARED_KEY | MW_AUTH_ALG_OPEN_SYSTEM: |
| default: |
| PRINTM(MINFO, "Auth mode auto!\n"); |
| auth_mode = MLAN_AUTH_MODE_AUTO; |
| break; |
| } |
| if (MLAN_STATUS_SUCCESS != |
| woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, auth_mode)) |
| ret = -EFAULT; |
| break; |
| case MW_AUTH_WPA_ENABLED: |
| if (MLAN_STATUS_SUCCESS != |
| woal_set_wpa_enable(priv, MOAL_IOCTL_WAIT, |
| mwr->u.param.value)) |
| ret = -EFAULT; |
| break; |
| #define MW_AUTH_WAPI_ENABLED 0x20 |
| case MW_AUTH_WAPI_ENABLED: |
| if (MLAN_STATUS_SUCCESS != |
| woal_set_wapi_enable(priv, MOAL_IOCTL_WAIT, |
| mwr->u.param.value)) |
| ret = -EFAULT; |
| break; |
| case MW_AUTH_WPA_VERSION: |
| /* set WPA_VERSION_DISABLED/VERSION_WPA/VERSION_WP2 */ |
| priv->wpa_version = mwr->u.param.value; |
| break; |
| case MW_AUTH_KEY_MGMT: |
| /* set KEY_MGMT_802_1X/KEY_MGMT_PSK */ |
| priv->key_mgmt = mwr->u.param.value; |
| break; |
| case MW_AUTH_TKIP_COUNTERMEASURES: |
| case MW_AUTH_DROP_UNENCRYPTED: |
| case MW_AUTH_RX_UNENCRYPTED_EAPOL: |
| case MW_AUTH_ROAMING_CONTROL: |
| case MW_AUTH_PRIVACY_INVOKED: |
| break; |
| default: |
| ret = -EOPNOTSUPP; |
| break; |
| } |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get current BSSID |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written if successful else negative value |
| */ |
| static int |
| woal_priv_get_ap(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| struct mwreq *mwr; |
| t_u8 *data_ptr; |
| int ret = 0; |
| mlan_bss_info bss_info; |
| |
| ENTER(); |
| |
| data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_GET_AP)); |
| |
| mwr = (struct mwreq *)data_ptr; |
| |
| memset(&bss_info, 0, sizeof(bss_info)); |
| |
| ret = woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info); |
| if (ret != MLAN_STATUS_SUCCESS) |
| return -EFAULT; |
| |
| if (bss_info.media_connected == MTRUE) { |
| moal_memcpy_ext(priv->phandle, mwr->u.ap_addr.sa_data, |
| &bss_info.bssid, MLAN_MAC_ADDR_LENGTH, |
| sizeof(mwr->u.ap_addr.sa_data)); |
| } else { |
| memset(mwr->u.ap_addr.sa_data, 0, MLAN_MAC_ADDR_LENGTH); |
| } |
| mwr->u.ap_addr.sa_family = ARPHRD_ETHER; |
| ret = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_AP) + sizeof(struct mwreq); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get power management |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written if successful else negative value |
| */ |
| static int |
| woal_priv_get_power(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| struct mwreq *mwr; |
| t_u8 *data_ptr; |
| int ret = 0, ps_mode; |
| |
| ENTER(); |
| |
| data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_GET_POWER)); |
| |
| mwr = (struct mwreq *)data_ptr; |
| |
| if (MLAN_STATUS_SUCCESS != woal_set_get_power_mgmt(priv, MLAN_ACT_GET, |
| &ps_mode, 0, |
| MOAL_IOCTL_WAIT)) { |
| return -EFAULT; |
| } |
| |
| if (ps_mode) |
| mwr->u.power.disabled = 0; |
| else |
| mwr->u.power.disabled = 1; |
| |
| mwr->u.power.value = 0; |
| ret = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_POWER) + |
| sizeof(struct mwreq); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get power save mode |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return 0 --success, otherwise fail |
| */ |
| static int |
| woal_priv_set_get_psmode(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| int data = 0; |
| int user_data_len = 0, header_len = 0; |
| t_u32 action = MLAN_ACT_GET; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PSMODE); |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &data, |
| sizeof(data) / sizeof(int), &user_data_len); |
| action = MLAN_ACT_SET; |
| } |
| |
| if (sizeof(int) * user_data_len > sizeof(data)) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| if (data != 0 && data != 1) { |
| PRINTM(MERROR, "Invalid psmode=%d\n", data); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| /* Flip the value */ |
| data = !data; |
| |
| if (MLAN_STATUS_SUCCESS != |
| woal_set_get_power_mgmt(priv, action, &data, 0, MOAL_IOCTL_WAIT)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| if (action == MLAN_ACT_SET) |
| data = !data; |
| |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data, sizeof(data), |
| respbuflen); |
| ret = sizeof(data); |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| #endif /* STA_SUPPORT */ |
| |
| /** |
| * @brief Performs warm reset |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written if successful else negative value |
| */ |
| static int |
| woal_priv_warmreset(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| moal_handle *handle = priv->phandle; |
| moal_handle *ref_handle; |
| moal_private *ref_priv; |
| ENTER(); |
| ret = woal_pre_warmreset(priv); |
| if (ret) |
| goto done; |
| ref_handle = (moal_handle *)handle->pref_mac; |
| if (ref_handle) { |
| ref_priv = woal_get_priv(ref_handle, MLAN_BSS_ROLE_ANY); |
| if (ref_priv) { |
| ret = woal_pre_warmreset(ref_priv); |
| if (ret) |
| goto done; |
| ret = woal_warmreset(ref_priv); |
| if (ret) |
| goto done; |
| } |
| } |
| ret = woal_warmreset(priv); |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get TX power configurations |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return 0 --success, otherwise fail |
| */ |
| static int |
| woal_priv_txpowercfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int data[5]; |
| int user_data_len; |
| int ret = 0; |
| mlan_bss_info bss_info; |
| mlan_ds_power_cfg *pcfg = NULL; |
| mlan_ioctl_req *req = NULL; |
| t_u8 *arguments = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| ENTER(); |
| |
| memset(data, 0, sizeof(data)); |
| memset(&bss_info, 0, sizeof(bss_info)); |
| woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info); |
| |
| if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_TXPOWERCFG))) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| arguments = |
| respbuf + strlen(CMD_NXP) + strlen(PRIV_CMD_TXPOWERCFG); |
| parse_arguments(arguments, data, ARRAY_SIZE(data), |
| &user_data_len); |
| } |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_power_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| pcfg = (mlan_ds_power_cfg *)req->pbuf; |
| pcfg->sub_command = MLAN_OID_POWER_CFG_EXT; |
| req->req_id = MLAN_IOCTL_POWER_CFG; |
| |
| if (!user_data_len) |
| req->action = MLAN_ACT_GET; |
| else { |
| /* SET operation */ |
| req->action = MLAN_ACT_SET; |
| if (sizeof(int) * user_data_len > sizeof(data)) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| switch (user_data_len) { |
| case 1: |
| if (data[0] == 0xFF) |
| pcfg->param.power_ext.power_group[0] |
| .rate_format = TX_PWR_CFG_AUTO_CTRL_OFF; |
| else |
| ret = -EINVAL; |
| break; |
| case 3: |
| case 5: |
| switch (data[0]) { |
| case 0: /* LG */ |
| pcfg->param.power_ext.power_group[0] |
| .rate_format = MLAN_RATE_FORMAT_LG; |
| pcfg->param.power_ext.power_group[0].bandwidth = |
| MLAN_HT_BW20; |
| break; |
| case 1: /* 20 MHz HT */ |
| pcfg->param.power_ext.power_group[0] |
| .rate_format = MLAN_RATE_FORMAT_HT; |
| pcfg->param.power_ext.power_group[0].bandwidth = |
| MLAN_HT_BW20; |
| break; |
| case 2: /* 40 MHz HT */ |
| pcfg->param.power_ext.power_group[0] |
| .rate_format = MLAN_RATE_FORMAT_HT; |
| pcfg->param.power_ext.power_group[0].bandwidth = |
| MLAN_HT_BW40; |
| break; |
| case 3: /* 1 NSS 20 MHZ VHT */ |
| pcfg->param.power_ext.power_group[0] |
| .rate_format = MLAN_RATE_FORMAT_VHT; |
| pcfg->param.power_ext.power_group[0].bandwidth = |
| MLAN_HT_BW20; |
| pcfg->param.power_ext.power_group[0].nss = 1; |
| break; |
| case 4: /* 2 NSS 20 MHZ VHT */ |
| pcfg->param.power_ext.power_group[0] |
| .rate_format = MLAN_RATE_FORMAT_VHT; |
| pcfg->param.power_ext.power_group[0].bandwidth = |
| MLAN_HT_BW20; |
| pcfg->param.power_ext.power_group[0].nss = 2; |
| break; |
| case 5: /* 1 NSS 40 MHZ VHT */ |
| pcfg->param.power_ext.power_group[0] |
| .rate_format = MLAN_RATE_FORMAT_VHT; |
| pcfg->param.power_ext.power_group[0].bandwidth = |
| MLAN_HT_BW40; |
| pcfg->param.power_ext.power_group[0].nss = 1; |
| break; |
| case 6: /* 2 NSS 40 MHZ VHT */ |
| pcfg->param.power_ext.power_group[0] |
| .rate_format = MLAN_RATE_FORMAT_VHT; |
| pcfg->param.power_ext.power_group[0].bandwidth = |
| MLAN_HT_BW40; |
| pcfg->param.power_ext.power_group[0].nss = 2; |
| break; |
| case 7: /* 1 NSS 80 MHZ VHT */ |
| pcfg->param.power_ext.power_group[0] |
| .rate_format = MLAN_RATE_FORMAT_VHT; |
| pcfg->param.power_ext.power_group[0].bandwidth = |
| MLAN_VHT_BW80; |
| pcfg->param.power_ext.power_group[0].nss = 1; |
| break; |
| case 8: /* 2 NSS 80 MHZ VHT */ |
| pcfg->param.power_ext.power_group[0] |
| .rate_format = MLAN_RATE_FORMAT_VHT; |
| pcfg->param.power_ext.power_group[0].bandwidth = |
| MLAN_VHT_BW80; |
| pcfg->param.power_ext.power_group[0].nss = 2; |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| pcfg->param.power_ext.power_group[0].first_rate_ind = |
| data[1]; |
| pcfg->param.power_ext.power_group[0].last_rate_ind = |
| data[1]; |
| if (data[2] < bss_info.min_power_level) { |
| PRINTM(MERROR, |
| "The set powercfg rate value %d dBm is out of range (%d dBm-%d dBm)!\n", |
| data[2], (int)bss_info.min_power_level, |
| (int)bss_info.max_power_level); |
| ret = -EINVAL; |
| break; |
| } |
| if (data[2] > bss_info.max_power_level) { |
| PRINTM(MERROR, |
| "The set powercfg rate value %d dBm is out of range (%d dBm-%d dBm)!\n", |
| data[2], (int)bss_info.min_power_level, |
| (int)bss_info.max_power_level); |
| ret = -EINVAL; |
| break; |
| } |
| pcfg->param.power_ext.power_group[0].power_min = |
| data[2]; |
| pcfg->param.power_ext.power_group[0].power_max = |
| data[2]; |
| pcfg->param.power_ext.power_group[0].power_step = 0; |
| pcfg->param.power_ext.num_pwr_grp = 1; |
| |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| if (ret) |
| goto done; |
| } |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| if (!user_data_len) { |
| /* GET operation */ |
| moal_memcpy_ext(priv->phandle, respbuf, |
| (t_u8 *)&pcfg->param.power_ext, |
| sizeof(pcfg->param.power_ext.num_pwr_grp) + |
| (MIN(pcfg->param.power_ext.num_pwr_grp, |
| MAX_POWER_GROUP) * |
| sizeof(mlan_power_group)), respbuflen); |
| ret = sizeof(pcfg->param.power_ext.num_pwr_grp) + |
| (MIN(pcfg->param.power_ext.num_pwr_grp, MAX_POWER_GROUP) |
| * sizeof(mlan_power_group)); |
| } |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get PS configuration parameters |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return 0 --success, otherwise fail |
| */ |
| static int |
| woal_priv_pscfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int data[7] = { 0 }, ret = 0; |
| mlan_ds_pm_cfg *pm_cfg = NULL; |
| mlan_ioctl_req *req = NULL; |
| int allowed = 3; |
| int i = 3; |
| int user_data_len = 0, header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| allowed++; /* For beacon missing timeout parameter */ |
| allowed += 2; /* For delay to PS and PS mode parameters */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PSCFG); |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| memset((char *)data, 0, sizeof(data)); |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| } |
| |
| if (user_data_len && user_data_len > allowed) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| pm_cfg = (mlan_ds_pm_cfg *)req->pbuf; |
| pm_cfg->sub_command = MLAN_OID_PM_CFG_PS_CFG; |
| req->req_id = MLAN_IOCTL_PM_CFG; |
| if (user_data_len) { |
| if ((data[0] < PS_NULL_DISABLE)) { |
| PRINTM(MERROR, |
| "Invalid argument for PS null interval\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if ((data[1] != MRVDRV_IGNORE_MULTIPLE_DTIM) && |
| (data[1] != MRVDRV_MATCH_CLOSEST_DTIM) && |
| ((data[1] < MRVDRV_MIN_MULTIPLE_DTIM) || |
| (data[1] > MRVDRV_MAX_MULTIPLE_DTIM))) { |
| PRINTM(MERROR, "Invalid argument for multiple DTIM\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| if ((data[2] < MRVDRV_MIN_LISTEN_INTERVAL) && |
| (data[2] != MRVDRV_LISTEN_INTERVAL_DISABLE)) { |
| PRINTM(MERROR, |
| "Invalid argument for listen interval\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| if ((data[i] != DISABLE_BCN_MISS_TO) && |
| ((data[i] < MIN_BCN_MISS_TO) || |
| (data[i] > MAX_BCN_MISS_TO))) { |
| PRINTM(MERROR, |
| "Invalid argument for beacon miss timeout\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| i++; |
| if (user_data_len < allowed - 1) |
| data[i] = DELAY_TO_PS_UNCHANGED; |
| else if ((data[i] < MIN_DELAY_TO_PS) || |
| (data[i] > MAX_DELAY_TO_PS)) { |
| PRINTM(MERROR, "Invalid argument for delay to PS\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| i++; |
| if ((data[i] != PS_MODE_UNCHANGED) && |
| (data[i] != PS_MODE_AUTO) && (data[i] != PS_MODE_POLL) && |
| (data[i] != PS_MODE_NULL)) { |
| PRINTM(MERROR, "Invalid argument for PS mode\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| i++; |
| req->action = MLAN_ACT_SET; |
| moal_memcpy_ext(priv->phandle, &pm_cfg->param.ps_cfg, data, |
| sizeof(data), sizeof(pm_cfg->param.ps_cfg)); |
| } else |
| req->action = MLAN_ACT_GET; |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| moal_memcpy_ext(priv->phandle, data, &pm_cfg->param.ps_cfg, |
| MIN((sizeof(int) * allowed), |
| sizeof(pm_cfg->param.ps_cfg)), sizeof(data)); |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, |
| sizeof(int) * allowed, respbuflen); |
| ret = sizeof(int) * allowed; |
| if (req->action == MLAN_ACT_SET) { |
| pm_cfg = (mlan_ds_pm_cfg *)req->pbuf; |
| pm_cfg->sub_command = MLAN_OID_PM_CFG_IEEE_PS; |
| pm_cfg->param.ps_mode = 1; |
| req->req_id = MLAN_IOCTL_PM_CFG; |
| req->action = MLAN_ACT_SET; |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get PS configuration parameters |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return 0 --success, otherwise fail |
| */ |
| static int |
| woal_priv_bcntimeoutcfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int data[4] = { 0 }, ret = 0; |
| mlan_ds_pm_cfg *pm_cfg = NULL; |
| mlan_ioctl_req *req = NULL; |
| int allowed = 4; |
| int i = 0; |
| int user_data_len = 0, header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_BCNTIMEOUTCFG); |
| |
| memset((char *)data, 0, sizeof(data)); |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| if (user_data_len != allowed) { |
| PRINTM(MERROR, "Invalid args num: input=%d allowed=%d\n", |
| user_data_len, allowed); |
| ret = -EINVAL; |
| goto done; |
| } |
| for (i = 0; i < allowed; i++) { |
| if (data[i] <= 0) { |
| PRINTM(MERROR, "Invalid data[%d]=%d\n", i, data[i]); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| pm_cfg = (mlan_ds_pm_cfg *)req->pbuf; |
| pm_cfg->sub_command = MLAN_OID_PM_CFG_BCN_TIMEOUT; |
| req->req_id = MLAN_IOCTL_PM_CFG; |
| req->action = MLAN_ACT_SET; |
| pm_cfg->param.bcn_timeout.bcn_miss_tmo_window = (t_u16)data[0]; |
| pm_cfg->param.bcn_timeout.bcn_miss_tmo_period = (t_u16)data[1]; |
| pm_cfg->param.bcn_timeout.bcn_rq_tmo_window = (t_u16)data[2]; |
| pm_cfg->param.bcn_timeout.bcn_rq_tmo_period = (t_u16)data[3]; |
| |
| 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/Get sleep period |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return 0 --success, otherwise fail |
| */ |
| static int |
| woal_priv_sleeppd(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| mlan_ds_pm_cfg *pm_cfg = NULL; |
| mlan_ioctl_req *req = NULL; |
| int data = 0; |
| int user_data_len = 0, header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| pm_cfg = (mlan_ds_pm_cfg *)req->pbuf; |
| pm_cfg->sub_command = MLAN_OID_PM_CFG_SLEEP_PD; |
| req->req_id = MLAN_IOCTL_PM_CFG; |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SLEEPPD); |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &data, |
| sizeof(data) / sizeof(int), &user_data_len); |
| } |
| |
| if (sizeof(int) * user_data_len > sizeof(data)) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| if (user_data_len) { |
| if ((data <= MAX_SLEEP_PERIOD && data >= MIN_SLEEP_PERIOD) || |
| (data == 0) |
| || (data == SLEEP_PERIOD_RESERVED_FF) |
| ) { |
| req->action = MLAN_ACT_SET; |
| pm_cfg->param.sleep_period = data; |
| } else { |
| ret = -EINVAL; |
| goto done; |
| } |
| } else |
| req->action = MLAN_ACT_GET; |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| if (!user_data_len) { |
| data = pm_cfg->param.sleep_period; |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data, |
| sizeof(data), respbuflen); |
| ret = sizeof(data); |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get Tx control flag |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return 0 --success, otherwise fail |
| */ |
| static int |
| woal_priv_txcontrol(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| mlan_ds_misc_cfg *misc_cfg = NULL; |
| mlan_ioctl_req *req = NULL; |
| int data = 0; |
| int user_data_len = 0, header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| misc_cfg = (mlan_ds_misc_cfg *)req->pbuf; |
| misc_cfg->sub_command = MLAN_OID_MISC_TXCONTROL; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TXCONTROL); |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &data, |
| sizeof(data) / sizeof(int), &user_data_len); |
| } |
| |
| if (sizeof(int) * user_data_len > sizeof(data)) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| if (user_data_len) { |
| req->action = MLAN_ACT_SET; |
| misc_cfg->param.tx_control = (t_u32)data; |
| } else { |
| req->action = MLAN_ACT_GET; |
| } |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| if (!user_data_len) { |
| data = misc_cfg->param.tx_control; |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data, |
| sizeof(data), respbuflen); |
| ret = sizeof(data); |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Read/Write adapter registers value |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return 0 --success, otherwise fail |
| */ |
| static int |
| woal_priv_regrdwr(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int data[3]; |
| int ret = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_reg_mem *reg_mem = NULL; |
| int user_data_len = 0, header_len = 0; |
| t_u8 *arguments = NULL, *space_ind = NULL; |
| t_u32 is_negative_val = MFALSE; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| gfp_t flag; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| reg_mem = (mlan_ds_reg_mem *)req->pbuf; |
| reg_mem->sub_command = MLAN_OID_REG_RW; |
| req->req_id = MLAN_IOCTL_REG_MEM; |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_REGRDWR); |
| |
| if ((int)strlen(respbuf) == header_len) { |
| ret = -EINVAL; |
| goto done; |
| } |
| /* SET operation */ |
| memset((char *)data, 0, sizeof(data)); |
| flag = (in_atomic() || irqs_disabled())? GFP_ATOMIC : GFP_KERNEL; |
| arguments = kzalloc(strlen(respbuf) * sizeof(char), flag); |
| if (arguments == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| strcpy(arguments, respbuf + header_len); |
| space_ind = strstr((char *)arguments, " "); |
| if (space_ind) |
| space_ind = strstr(space_ind + 1, " "); |
| if (space_ind) { |
| if (*(char *)(space_ind + 1) == '-') { |
| is_negative_val = MTRUE; |
| arguments[space_ind + 1 - arguments] = '\0'; |
| strcat(arguments, space_ind + 2); |
| } |
| } |
| parse_arguments(arguments, data, ARRAY_SIZE(data), &user_data_len); |
| if (is_negative_val == MTRUE) |
| data[2] *= -1; |
| |
| if (user_data_len == 2) { |
| req->action = MLAN_ACT_GET; |
| } else if (user_data_len == 3) { |
| req->action = MLAN_ACT_SET; |
| } else { |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| reg_mem->param.reg_rw.type = (t_u32)data[0]; |
| reg_mem->param.reg_rw.offset = (t_u32)data[1]; |
| if (user_data_len == 3) |
| reg_mem->param.reg_rw.value = (t_u32)data[2]; |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| if (req->action == MLAN_ACT_GET) { |
| moal_memcpy_ext(priv->phandle, respbuf, ®_mem->param.reg_rw, |
| sizeof(reg_mem->param.reg_rw), respbuflen); |
| ret = sizeof(reg_mem->param.reg_rw); |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| kfree(arguments); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Read the EEPROM contents of the card |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return 0 --success, otherwise fail |
| */ |
| static int |
| woal_priv_rdeeprom(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int data[2]; |
| int ret = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_reg_mem *reg_mem = NULL; |
| int user_data_len = 0, header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| reg_mem = (mlan_ds_reg_mem *)req->pbuf; |
| reg_mem->sub_command = MLAN_OID_EEPROM_RD; |
| req->req_id = MLAN_IOCTL_REG_MEM; |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RDEEPROM); |
| |
| if ((int)strlen(respbuf) == header_len) { |
| ret = -EINVAL; |
| goto done; |
| } |
| /* SET operation */ |
| memset((char *)data, 0, sizeof(data)); |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| |
| if (user_data_len == 2) { |
| req->action = MLAN_ACT_GET; |
| } else { |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| reg_mem->param.rd_eeprom.offset = (t_u16)data[0]; |
| reg_mem->param.rd_eeprom.byte_count = (t_u16)data[1]; |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| if (req->action == MLAN_ACT_GET) { |
| moal_memcpy_ext(priv->phandle, respbuf, |
| ®_mem->param.rd_eeprom, |
| sizeof(reg_mem->param.rd_eeprom), respbuflen); |
| ret = sizeof(reg_mem->param.rd_eeprom); |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Read/Write device memory value |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return 0 --success, otherwise fail |
| */ |
| static int |
| woal_priv_memrdwr(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int data[2]; |
| int ret = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_reg_mem *reg_mem = NULL; |
| int user_data_len = 0, header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_reg_mem)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| reg_mem = (mlan_ds_reg_mem *)req->pbuf; |
| reg_mem->sub_command = MLAN_OID_MEM_RW; |
| req->req_id = MLAN_IOCTL_REG_MEM; |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MEMRDWR); |
| |
| if ((int)strlen(respbuf) == header_len) { |
| ret = -EINVAL; |
| goto done; |
| } |
| /* SET operation */ |
| memset((char *)data, 0, sizeof(data)); |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| |
| if (user_data_len == 1) { |
| PRINTM(MINFO, "MEM_RW: GET\n"); |
| req->action = MLAN_ACT_GET; |
| } else if (user_data_len == 2) { |
| PRINTM(MINFO, "MEM_RW: SET\n"); |
| req->action = MLAN_ACT_SET; |
| } else { |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| reg_mem->param.mem_rw.addr = (t_u32)data[0]; |
| if (user_data_len == 2) |
| reg_mem->param.mem_rw.value = (t_u32)data[1]; |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| if (req->action == MLAN_ACT_GET) { |
| moal_memcpy_ext(priv->phandle, respbuf, ®_mem->param.mem_rw, |
| sizeof(reg_mem->param.mem_rw), respbuflen); |
| ret = sizeof(reg_mem->param.mem_rw); |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| #ifdef SDIO |
| /** |
| * @brief Cmd52 read/write register |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return MLAN_STATUS_SUCCESS --success, otherwise fail |
| */ |
| static int |
| woal_priv_sdcmd52rw(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| t_u8 rw = 0, func, data = 0; |
| int buf[3], reg, ret = MLAN_STATUS_SUCCESS; |
| int user_data_len = 0, header_len = 0; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SDCMD52RW); |
| memset((t_u8 *)buf, 0, sizeof(buf)); |
| |
| if ((int)strlen(respbuf) == header_len) { |
| PRINTM(MERROR, "Invalid number of arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| parse_arguments(respbuf + header_len, buf, ARRAY_SIZE(buf), |
| &user_data_len); |
| |
| if (user_data_len < 2 || user_data_len > 3) { |
| PRINTM(MERROR, "Invalid number of arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| func = (t_u8)buf[0]; |
| if (func > 7) { |
| PRINTM(MERROR, "Invalid function number!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| reg = (t_u32)buf[1]; |
| if (user_data_len == 2) { |
| rw = 0; /* CMD52 read */ |
| PRINTM(MINFO, "Cmd52 read, func=%d, reg=0x%08X\n", func, reg); |
| } |
| if (user_data_len == 3) { |
| rw = 1; /* CMD52 write */ |
| data = (t_u8)buf[2]; |
| PRINTM(MINFO, "Cmd52 write, func=%d, reg=0x%08X, data=0x%02X\n", |
| func, reg, data); |
| } |
| |
| if (!rw) { |
| #ifdef SDIO_MMC |
| sdio_claim_host(((struct sdio_mmc_card *)priv->phandle->card)-> |
| func); |
| if (func) |
| data = sdio_readb(((struct sdio_mmc_card *)priv-> |
| phandle->card) |
| ->func, reg, &ret); |
| else |
| data = sdio_f0_readb(((struct sdio_mmc_card *)priv-> |
| phandle->card) |
| ->func, reg, &ret); |
| sdio_release_host(((struct sdio_mmc_card *)priv->phandle-> |
| card)->func); |
| if (ret) { |
| PRINTM(MERROR, |
| "sdio_readb: reading register 0x%X failed\n", |
| reg); |
| goto done; |
| } |
| #else |
| if (sdio_read_ioreg(priv->phandle->card, func, reg, &data) < 0) { |
| PRINTM(MERROR, |
| "sdio_read_ioreg: reading register 0x%X failed\n", |
| reg); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| #endif /* SDIO_MMC */ |
| } else { |
| #ifdef SDIO_MMC |
| sdio_claim_host(((struct sdio_mmc_card *)priv->phandle->card)-> |
| func); |
| if (func) |
| sdio_writeb(((struct sdio_mmc_card *)priv->phandle-> |
| card) |
| ->func, data, reg, &ret); |
| else |
| sdio_f0_writeb(((struct sdio_mmc_card *)priv->phandle-> |
| card) |
| ->func, data, reg, &ret); |
| sdio_release_host(((struct sdio_mmc_card *)priv->phandle-> |
| card)->func); |
| if (ret) { |
| PRINTM(MERROR, |
| "sdio_writeb: writing register 0x%X failed\n", |
| reg); |
| goto done; |
| } |
| #else |
| if (sdio_write_ioreg(priv->phandle->card, func, reg, data) < 0) { |
| PRINTM(MERROR, |
| "sdio_write_ioreg: writing register 0x%X failed\n", |
| reg); |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| #endif /* SDIO_MMC */ |
| } |
| |
| /* Action = GET */ |
| buf[0] = data; |
| |
| moal_memcpy_ext(priv->phandle, respbuf, &buf, sizeof(int), respbuflen); |
| ret = sizeof(int); |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| #endif /* SDIO */ |
| |
| #ifdef STA_SUPPORT |
| /** |
| * @brief arpfilter ioctl function |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return 0 --success, otherwise fail |
| */ |
| static int |
| woal_priv_arpfilter(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| mlan_ds_misc_cfg *misc = NULL; |
| mlan_ioctl_req *req = NULL; |
| t_u8 *data_ptr = NULL; |
| t_u32 buf_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| misc = (mlan_ds_misc_cfg *)req->pbuf; |
| misc->sub_command = MLAN_OID_MISC_GEN_IE; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| req->action = MLAN_ACT_SET; |
| misc->param.gen_ie.type = MLAN_IE_TYPE_ARP_FILTER; |
| |
| data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_ARPFILTER)); |
| buf_len = *((t_u16 *)data_ptr); |
| misc->param.gen_ie.len = buf_len; |
| moal_memcpy_ext(priv->phandle, (void *)(misc->param.gen_ie.ie_data), |
| data_ptr + sizeof(buf_len), buf_len, MAX_IE_SIZE); |
| |
| 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; |
| } |
| #endif /* STA_SUPPORT */ |
| |
| /** |
| * @brief Set / Get Auto ARP Response configuration |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_set_get_auto_arp(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int data[4]; |
| int user_data_len = 0; |
| int ret = 0; |
| moal_handle *handle = NULL; |
| |
| ENTER(); |
| |
| if (priv == NULL) { |
| PRINTM(MERROR, "Invalid priv\n"); |
| goto done; |
| } |
| handle = priv->phandle; |
| |
| if (strlen(respbuf) == (strlen(CMD_NXP) + strlen(PRIV_CMD_AUTO_ARP))) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| memset((char *)data, 0, sizeof(data)); |
| parse_arguments(respbuf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_AUTO_ARP), |
| data, ARRAY_SIZE(data), &user_data_len); |
| } |
| |
| if (user_data_len > 1) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| if (user_data_len) { |
| /* Get the enable/disable value from user */ |
| handle->hs_auto_arp = data[0]; |
| PRINTM(MIOCTL, "Auto ARP : %s\n", |
| handle->hs_auto_arp ? "enable" : "disable"); |
| } |
| |
| moal_memcpy_ext(handle, respbuf, &handle->hs_auto_arp, |
| sizeof(handle->hs_auto_arp), respbuflen); |
| ret = sizeof(handle->hs_auto_arp); |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get/Set deauth control |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_deauth_ctrl(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ds_snmp_mib *cfg = NULL; |
| mlan_ioctl_req *req = NULL; |
| int ret = 0, header_len = 0, data = 0, user_data_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib)); |
| if (req == NULL) { |
| ret = ENOMEM; |
| goto done; |
| } |
| |
| cfg = (mlan_ds_snmp_mib *)req->pbuf; |
| cfg->sub_command = MLAN_OID_SNMP_MIB_CTRL_DEAUTH; |
| req->req_id = MLAN_IOCTL_SNMP_MIB; |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DEAUTH_CTRL); |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| req->action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &data, |
| sizeof(data) / sizeof(int), &user_data_len); |
| if (user_data_len != 1) { |
| PRINTM(MERROR, "Invalid number of args! %d\n", |
| user_data_len); |
| ret = -EINVAL; |
| goto done; |
| } |
| req->action = MLAN_ACT_SET; |
| cfg->param.deauthctrl = (t_u8)data; |
| } |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| data = (int)cfg->param.deauthctrl; |
| moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data), |
| respbuflen); |
| ret = sizeof(data); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| #define MRVL_TLV_HEADER_SIZE 4 |
| /** |
| * @brief Get/Set per packet Txctl and Rxinfo configuration |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_per_pkt_cfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ds_misc_cfg *misc = NULL; |
| mlan_ioctl_req *req = NULL; |
| int ret = 0; |
| t_u8 *pos = NULL; |
| int left_len, header_len = 0; |
| mlan_per_pkt_cfg *perpkt = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PER_PKT_CFG); |
| pos = respbuf + header_len; |
| left_len = respbuflen - header_len; |
| |
| if (priv->phandle->card_info->per_pkt_cfg_support == 0) { |
| PRINTM(MERROR, "Device not support per packet configuration\n"); |
| ret = -EFAULT; |
| 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; |
| misc->sub_command = MLAN_OID_MISC_PER_PKT_CFG; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| |
| if (*pos == 0) { |
| /* GET operation */ |
| pos++; |
| if (priv->tx_protocols.protocol_num) { |
| perpkt = (mlan_per_pkt_cfg *) pos; |
| perpkt->type = TLV_TYPE_PER_PKT_CFG; |
| perpkt->tx_rx_control = TX_PKT_CTRL; |
| perpkt->proto_type_num = |
| priv->tx_protocols.protocol_num; |
| moal_memcpy_ext(priv->phandle, perpkt->ether_type, |
| priv->tx_protocols.protocols, |
| perpkt->proto_type_num * sizeof(t_u16), |
| MAX_NUM_ETHER_TYPE * sizeof(t_u16)); |
| perpkt->len = |
| (perpkt->proto_type_num + 1) * sizeof(t_u16); |
| pos += perpkt->len + MRVL_TLV_HEADER_SIZE; |
| } |
| if (priv->rx_protocols.protocol_num) { |
| perpkt = (mlan_per_pkt_cfg *) pos; |
| perpkt->type = TLV_TYPE_PER_PKT_CFG; |
| perpkt->tx_rx_control = RX_PKT_INFO; |
| perpkt->proto_type_num = |
| priv->rx_protocols.protocol_num; |
| moal_memcpy_ext(priv->phandle, perpkt->ether_type, |
| priv->rx_protocols.protocols, |
| perpkt->proto_type_num * sizeof(t_u16), |
| MAX_NUM_ETHER_TYPE * sizeof(t_u16)); |
| perpkt->len = |
| (perpkt->proto_type_num + 1) * sizeof(t_u16); |
| pos += perpkt->len + MRVL_TLV_HEADER_SIZE; |
| } |
| ret = pos - respbuf; |
| goto done; |
| } else if (*pos == 1) { |
| /* SET operation */ |
| req->action = MLAN_ACT_SET; |
| pos++; |
| left_len--; |
| while (*pos == TLV_TYPE_PER_PKT_CFG && (left_len > 2)) { |
| perpkt = (mlan_per_pkt_cfg *) pos; |
| if (perpkt->tx_rx_control & TX_PKT_CTRL) { |
| priv->tx_protocols.protocol_num = |
| perpkt->proto_type_num; |
| if (perpkt->proto_type_num <= |
| MAX_NUM_ETHER_TYPE) |
| moal_memcpy_ext(priv->phandle, |
| priv->tx_protocols. |
| protocols, |
| perpkt->ether_type, |
| perpkt->proto_type_num * |
| sizeof(t_u16), |
| MAX_NUM_ETHER_TYPE * |
| sizeof(t_u16)); |
| } |
| if (perpkt->tx_rx_control & RX_PKT_INFO) { |
| priv->rx_protocols.protocol_num = |
| perpkt->proto_type_num; |
| if (perpkt->proto_type_num <= |
| MAX_NUM_ETHER_TYPE) |
| moal_memcpy_ext(priv->phandle, |
| priv->rx_protocols. |
| protocols, |
| perpkt->ether_type, |
| perpkt->proto_type_num * |
| sizeof(t_u16), |
| MAX_NUM_ETHER_TYPE * |
| sizeof(t_u16)); |
| } |
| if (!perpkt->tx_rx_control) { |
| memset(&priv->tx_protocols, 0, |
| sizeof(dot11_protocol)); |
| memset(&priv->rx_protocols, 0, |
| sizeof(dot11_protocol)); |
| } |
| pos += perpkt->len + MRVL_TLV_HEADER_SIZE; |
| left_len -= (perpkt->len + MRVL_TLV_HEADER_SIZE); |
| } |
| } else |
| goto done; |
| |
| if (perpkt != NULL) |
| misc->param.txrx_pkt_ctrl = perpkt->tx_rx_control; |
| 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 Get Region Channel Power |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_get_chnrgpwr(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| int header_len = 0; |
| t_u8 *pos = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| header_len = strlen(PRIV_CMD_GET_CHNRGPWR); |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| misc = (mlan_ds_misc_cfg *)req->pbuf; |
| misc->sub_command = MLAN_OID_MISC_GET_REGIONPWR_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 done; |
| } |
| ret = header_len + sizeof(t_u16) + misc->param.rgchnpwr_cfg.length; |
| pos = respbuf + header_len; |
| moal_memcpy_ext(priv->phandle, pos, &misc->param.rgchnpwr_cfg, |
| sizeof(t_u16) + misc->param.rgchnpwr_cfg.length, |
| respbuflen - header_len); |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get TX/RX histogram statistic |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_get_txpwrlimit(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| mlan_ds_misc_chan_trpc_cfg *trpc_cfg = NULL; |
| int header_len = 0; |
| t_u8 *pos = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| header_len = strlen(PRIV_CMD_GET_TXPWR_LIMIT); |
| trpc_cfg = (mlan_ds_misc_chan_trpc_cfg *) (respbuf + header_len); |
| if ((trpc_cfg->sub_band != 0) && (trpc_cfg->sub_band != 0x10) && |
| (trpc_cfg->sub_band != 0x11) && (trpc_cfg->sub_band != 0x12) && |
| (trpc_cfg->sub_band != 0x13)) { |
| PRINTM(MERROR, "Invalid subband=0x%x\n", trpc_cfg->sub_band); |
| 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; |
| misc->sub_command = MLAN_OID_MISC_GET_CHAN_TRPC_CFG; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| req->action = MLAN_ACT_GET; |
| misc->param.trpc_cfg.sub_band = trpc_cfg->sub_band; |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| ret = header_len + sizeof(t_u16) + sizeof(t_u16) + |
| misc->param.trpc_cfg.length; |
| pos = respbuf + header_len; |
| moal_memcpy_ext(priv->phandle, pos, &misc->param.trpc_cfg, |
| sizeof(t_u16) + sizeof(t_u16) + |
| misc->param.trpc_cfg.length, respbuflen - header_len); |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| #if defined(STA_CFG80211) || defined(UAP_CFG80211) |
| /** |
| * @brief Get TX/RX histogram statistic |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_getcfgchanlist(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| int num_chan = 0; |
| wlan_ieee80211_chan_list *plist = NULL; |
| struct ieee80211_supported_band *sband; |
| struct wiphy *wiphy = NULL; |
| int i; |
| |
| ENTER(); |
| if (priv && priv->wdev) |
| wiphy = priv->wdev->wiphy; |
| if (!wiphy) { |
| PRINTM(MERROR, "wiphy is NULL\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| plist = (wlan_ieee80211_chan_list *) respbuf; |
| sband = wiphy->bands[NL80211_BAND_2GHZ]; |
| if (sband) { |
| num_chan += sband->n_channels; |
| for (i = 0; i < sband->n_channels; i++) { |
| plist->chan_list[i].center_freq = |
| sband->channels[i].center_freq; |
| plist->chan_list[i].hw_value = |
| sband->channels[i].hw_value; |
| plist->chan_list[i].flags = sband->channels[i].flags; |
| plist->chan_list[i].max_power = |
| sband->channels[i].max_power; |
| } |
| } |
| sband = wiphy->bands[NL80211_BAND_5GHZ]; |
| if (sband) { |
| for (i = 0; i < sband->n_channels; i++) { |
| plist->chan_list[i + num_chan].center_freq = |
| sband->channels[i].center_freq; |
| plist->chan_list[i + num_chan].hw_value = |
| sband->channels[i].hw_value; |
| plist->chan_list[i + num_chan].flags = |
| sband->channels[i].flags; |
| plist->chan_list[i + num_chan].max_power = |
| sband->channels[i].max_power; |
| #if LINUX_VERSION_CODE > KERNEL_VERSION(3, 8, 13) |
| plist->chan_list[i + num_chan].dfs_state = |
| sband->channels[i].dfs_state; |
| #endif |
| } |
| num_chan += sband->n_channels; |
| } |
| plist->num_chan = num_chan; |
| ret = sizeof(wlan_ieee80211_chan_list) + |
| sizeof(wlan_ieee80211_chan) * num_chan; |
| done: |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| |
| /** |
| * @brief Get TX/RX histogram statistic |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_get_rx_tx_histogram(moal_private *priv, t_u8 *respbuf, |
| t_u32 respbuflen) |
| { |
| int ret = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| tx_rx_histogram *tx_rx_info = NULL; |
| int header_len = 0; |
| t_u8 *pos = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| header_len = strlen(PRIV_CMD_TX_RX_HISTOGRAM); |
| tx_rx_info = (tx_rx_histogram *) (respbuf + header_len); |
| if (tx_rx_info->enable > 2 || |
| (tx_rx_info->enable == GET_TX_RX_HISTOGRAM && |
| (tx_rx_info->action > 3 || tx_rx_info->action <= 0))) { |
| PRINTM(MERROR, "Invalid parameters\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; |
| misc->sub_command = MLAN_OID_MISC_GET_TX_RX_HISTOGRAM; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| if (tx_rx_info->enable == GET_TX_RX_HISTOGRAM) { |
| misc->param.tx_rx_histogram.enable = ENABLE_TX_RX_HISTOGRAM; |
| misc->param.tx_rx_histogram.action = (t_u16)tx_rx_info->action; |
| } else { |
| misc->param.tx_rx_histogram.enable = tx_rx_info->enable; |
| misc->param.tx_rx_histogram.action |= |
| FLAG_TX_HISTOGRAM | FLAG_RX_HISTOGRAM; |
| } |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| ret = header_len + 2 * sizeof(t_u8); |
| if (tx_rx_info->enable & GET_TX_RX_HISTOGRAM) { |
| pos = respbuf + header_len + 2 * sizeof(t_u8); |
| /* Save tx/rx histogram size */ |
| moal_memcpy_ext(priv->phandle, pos, |
| &misc->param.tx_rx_histogram.size, |
| sizeof(misc->param.tx_rx_histogram.size), |
| respbuflen - (header_len + 2 * sizeof(t_u8))); |
| ret += sizeof(misc->param.tx_rx_histogram.size); |
| pos += sizeof(misc->param.tx_rx_histogram.size); |
| moal_memcpy_ext(priv->phandle, pos, |
| &misc->param.tx_rx_histogram.value, |
| misc->param.tx_rx_histogram.size, |
| respbuflen - (header_len + 2 * sizeof(t_u8)) - |
| sizeof(misc->param.tx_rx_histogram.size)); |
| ret += misc->param.tx_rx_histogram.size; |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get hotspot mode configurations |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return 0 --success, otherwise fail |
| */ |
| static int |
| woal_priv_hotspotcfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *cfg = NULL; |
| int data = 0; |
| int user_data_len = 0, header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_HOTSPOTCFG); |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &data, 1, &user_data_len); |
| } |
| if (user_data_len >= 2) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } else { |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| cfg = (mlan_ds_misc_cfg *)req->pbuf; |
| if (user_data_len == 0) { |
| req->action = MLAN_ACT_GET; |
| } else { |
| cfg->param.hotspot_cfg = data; |
| req->action = MLAN_ACT_SET; |
| } |
| } |
| cfg->sub_command = MLAN_OID_MISC_HOTSPOT_CFG; |
| 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; |
| } |
| data = cfg->param.hotspot_cfg; |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data, sizeof(data), |
| respbuflen); |
| ret = sizeof(data); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get Mgmt Frame passthru mask |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return 0 --success, otherwise fail |
| */ |
| static int |
| woal_priv_mgmt_frame_passthru_ctrl(moal_private *priv, t_u8 *respbuf, |
| t_u32 respbuflen) |
| { |
| int ret = 0; |
| int data = 0; |
| int user_data_len = 0, header_len = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *mgmt_cfg = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MGMT_FRAME_CTRL); |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &data, 1, &user_data_len); |
| } |
| |
| if (user_data_len >= 2) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } else { |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| mgmt_cfg = (mlan_ds_misc_cfg *)req->pbuf; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| mgmt_cfg->sub_command = MLAN_OID_MISC_RX_MGMT_IND; |
| |
| if (user_data_len == 0) { /* Get */ |
| req->action = MLAN_ACT_GET; |
| } else { /* Set */ |
| mgmt_cfg->param.mgmt_subtype_mask = data; |
| req->action = MLAN_ACT_SET; |
| } |
| } |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| data = mgmt_cfg->param.mgmt_subtype_mask; |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data, sizeof(data), |
| respbuflen); |
| ret = sizeof(data); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Private IOCTL entry to send an ADDTS TSPEC |
| * |
| * Receive a ADDTS command from the application. The command structure |
| * contains a TSPEC and timeout in milliseconds. The timeout is performed |
| * in the firmware after the ADDTS command frame is sent. |
| * |
| * The TSPEC is received in the API as an opaque block. The firmware will |
| * send the entire data block, including the bytes after the TSPEC. This |
| * is done to allow extra IEs to be packaged with the TSPEC in the ADDTS |
| * action frame. |
| * |
| * The IOCTL structure contains two return fields: |
| * - The firmware command result, which indicates failure and timeouts |
| * - The IEEE Status code which contains the corresponding value from |
| * any ADDTS response frame received. |
| * |
| * In addition, the opaque TSPEC data block passed in is replaced with the |
| * TSPEC received in the ADDTS response frame. In case of failure, the |
| * AP may modify the TSPEC on return and in the case of success, the |
| * medium time is returned as calculated by the AP. Along with the TSPEC, |
| * any IEs that are sent in the ADDTS response are also returned and can be |
| * parsed using the IOCTL length as an indicator of extra elements. |
| * |
| * The return value to the application layer indicates a driver execution |
| * success or failure. A successful return could still indicate a firmware |
| * failure or AP negotiation failure via the commandResult field copied |
| * back to the application. |
| * |
| * @param priv Pointer to the mlan_private driver data struct |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written if successful else negative value |
| */ |
| static int |
| woal_priv_wmm_addts_req_ioctl(moal_private *priv, t_u8 *respbuf, |
| t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_wmm_cfg *cfg = NULL; |
| wlan_ioctl_wmm_addts_req_t addts_ioctl; |
| int ret = 0, header_len = 0, copy_len = sizeof(addts_ioctl); |
| t_u8 *data_ptr; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ADDTS); |
| data_ptr = respbuf + header_len; |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| req->req_id = MLAN_IOCTL_WMM_CFG; |
| cfg = (mlan_ds_wmm_cfg *)req->pbuf; |
| cfg->sub_command = MLAN_OID_WMM_CFG_ADDTS; |
| |
| memset(&addts_ioctl, 0x00, sizeof(addts_ioctl)); |
| |
| moal_memcpy_ext(priv->phandle, (t_u8 *)&addts_ioctl, data_ptr, |
| sizeof(addts_ioctl), sizeof(addts_ioctl)); |
| |
| cfg->param.addts.timeout = addts_ioctl.timeout_ms; |
| cfg->param.addts.ie_data_len = addts_ioctl.ie_data_len; |
| |
| moal_memcpy_ext(priv->phandle, cfg->param.addts.ie_data, |
| addts_ioctl.ie_data, cfg->param.addts.ie_data_len, |
| MLAN_WMM_TSPEC_SIZE + MLAN_WMM_ADDTS_EXTRA_IE_BYTES); |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| addts_ioctl.cmd_result = cfg->param.addts.result; |
| addts_ioctl.ieee_status_code = (t_u8)cfg->param.addts.status_code; |
| addts_ioctl.ie_data_len = cfg->param.addts.ie_data_len; |
| |
| moal_memcpy_ext(priv->phandle, addts_ioctl.ie_data, |
| cfg->param.addts.ie_data, cfg->param.addts.ie_data_len, |
| MLAN_WMM_TSPEC_SIZE + MLAN_WMM_ADDTS_EXTRA_IE_BYTES); |
| |
| copy_len = (sizeof(addts_ioctl) - sizeof(addts_ioctl.ie_data) + |
| cfg->param.addts.ie_data_len); |
| |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&addts_ioctl, copy_len, |
| respbuflen); |
| ret = copy_len; |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Private IOCTL entry to send a DELTS TSPEC |
| * |
| * Receive a DELTS command from the application. The command structure |
| * contains a TSPEC and reason code along with space for a command result |
| * to be returned. The information is packaged is sent to the wlan_cmd.c |
| * firmware command prep and send routines for execution in the firmware. |
| * |
| * The reason code is not used for WMM implementations but is indicated in |
| * the 802.11e specification. |
| * |
| * The return value to the application layer indicates a driver execution |
| * success or failure. A successful return could still indicate a firmware |
| * failure via the cmd_result field copied back to the application. |
| * |
| * @param priv Pointer to the mlan_private driver data struct |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written if successful else negative value |
| */ |
| static int |
| woal_priv_wmm_delts_req_ioctl(moal_private *priv, t_u8 *respbuf, |
| t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_wmm_cfg *cfg = NULL; |
| wlan_ioctl_wmm_delts_req_t delts_ioctl; |
| int ret = 0, header_len = 0, copy_len = 0; |
| t_u8 *data_ptr; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DELTS); |
| data_ptr = respbuf + header_len; |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| req->req_id = MLAN_IOCTL_WMM_CFG; |
| cfg = (mlan_ds_wmm_cfg *)req->pbuf; |
| cfg->sub_command = MLAN_OID_WMM_CFG_DELTS; |
| |
| memset(&delts_ioctl, 0x00, sizeof(delts_ioctl)); |
| |
| if ((int)strlen(respbuf) > header_len) { |
| copy_len = MIN(strlen(data_ptr), sizeof(delts_ioctl)); |
| moal_memcpy_ext(priv->phandle, (t_u8 *)&delts_ioctl, data_ptr, |
| copy_len, sizeof(delts_ioctl)); |
| |
| cfg->param.delts.status_code = |
| (t_u32)delts_ioctl.ieee_reason_code; |
| cfg->param.delts.ie_data_len = (t_u8)delts_ioctl.ie_data_len; |
| |
| moal_memcpy_ext(priv->phandle, cfg->param.delts.ie_data, |
| delts_ioctl.ie_data, |
| cfg->param.delts.ie_data_len, |
| MLAN_WMM_TSPEC_SIZE); |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| /* Return the firmware command result back to the application |
| * layer */ |
| delts_ioctl.cmd_result = cfg->param.delts.result; |
| copy_len = sizeof(delts_ioctl); |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&delts_ioctl, |
| copy_len, respbuflen); |
| ret = copy_len; |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Private IOCTL entry to get/set a specified AC Queue's parameters |
| * |
| * Receive a AC Queue configuration command which is used to get, set, or |
| * default the parameters associated with a specific WMM AC Queue. |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return 0 --success, otherwise fail |
| */ |
| static int |
| woal_priv_qconfig(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_wmm_cfg *pwmm = NULL; |
| mlan_ds_wmm_queue_config *pqcfg = NULL; |
| wlan_ioctl_wmm_queue_config_t qcfg_ioctl; |
| t_u8 *data_ptr; |
| int ret = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| req->req_id = MLAN_IOCTL_WMM_CFG; |
| pwmm = (mlan_ds_wmm_cfg *)req->pbuf; |
| pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_CONFIG; |
| |
| memset(&qcfg_ioctl, 0x00, sizeof(qcfg_ioctl)); |
| pqcfg = (mlan_ds_wmm_queue_config *)&pwmm->param.q_cfg; |
| data_ptr = respbuf + (strlen(CMD_NXP) + strlen(PRIV_CMD_QCONFIG)); |
| |
| moal_memcpy_ext(priv->phandle, (t_u8 *)&qcfg_ioctl, data_ptr, |
| sizeof(qcfg_ioctl), sizeof(qcfg_ioctl)); |
| pqcfg->action = qcfg_ioctl.action; |
| pqcfg->access_category = qcfg_ioctl.access_category; |
| pqcfg->msdu_lifetime_expiry = qcfg_ioctl.msdu_lifetime_expiry; |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| memset(&qcfg_ioctl, 0x00, sizeof(qcfg_ioctl)); |
| qcfg_ioctl.action = pqcfg->action; |
| qcfg_ioctl.access_category = pqcfg->access_category; |
| qcfg_ioctl.msdu_lifetime_expiry = pqcfg->msdu_lifetime_expiry; |
| moal_memcpy_ext(priv->phandle, data_ptr, (t_u8 *)&qcfg_ioctl, |
| sizeof(qcfg_ioctl), |
| respbuflen - |
| (strlen(CMD_NXP) + strlen(PRIV_CMD_QCONFIG))); |
| ret = strlen(CMD_NXP) + strlen(PRIV_CMD_QCONFIG) + sizeof(qcfg_ioctl); |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Private IOCTL entry to get the status of the WMM queues |
| * |
| * Return the following information for each WMM AC: |
| * - WMM IE Acm Required |
| * - Firmware Flow Required |
| * - Firmware Flow Established |
| * - Firmware Queue Enabled |
| * - Firmware Delivery Enabled |
| * - Firmware Trigger Enabled |
| * |
| * @param priv Pointer to the moal_private driver data struct |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written if successful else negative value |
| */ |
| static int |
| woal_priv_wmm_queue_status_ioctl(moal_private *priv, t_u8 *respbuf, |
| t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_wmm_cfg *pwmm = NULL; |
| wlan_ioctl_wmm_queue_status_t qstatus_ioctl; |
| int ret = 0, header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_QSTATUS); |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| req->req_id = MLAN_IOCTL_WMM_CFG; |
| pwmm = (mlan_ds_wmm_cfg *)req->pbuf; |
| pwmm->sub_command = MLAN_OID_WMM_CFG_QUEUE_STATUS; |
| |
| if ((int)strlen(respbuf) == header_len) { |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| memset(&qstatus_ioctl, 0x00, sizeof(qstatus_ioctl)); |
| moal_memcpy_ext(priv->phandle, (void *)&qstatus_ioctl, |
| (void *)&pwmm->param.q_status, |
| sizeof(qstatus_ioctl), sizeof(qstatus_ioctl)); |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&qstatus_ioctl, |
| sizeof(qstatus_ioctl), respbuflen); |
| ret = sizeof(qstatus_ioctl); |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Private IOCTL entry to get the status of the WMM Traffic Streams |
| * |
| * @param priv Pointer to the moal_private driver data struct |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written if successful else negative value |
| */ |
| static int |
| woal_priv_wmm_ts_status_ioctl(moal_private *priv, t_u8 *respbuf, |
| t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_wmm_cfg *pwmm = NULL; |
| wlan_ioctl_wmm_ts_status_t ts_status_ioctl; |
| int ret = 0, header_len = 0; |
| t_u8 *data_ptr; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TS_STATUS); |
| data_ptr = respbuf + header_len; |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| req->req_id = MLAN_IOCTL_WMM_CFG; |
| pwmm = (mlan_ds_wmm_cfg *)req->pbuf; |
| pwmm->sub_command = MLAN_OID_WMM_CFG_TS_STATUS; |
| |
| memset(&ts_status_ioctl, 0x00, sizeof(ts_status_ioctl)); |
| |
| moal_memcpy_ext(priv->phandle, (t_u8 *)&ts_status_ioctl, data_ptr, |
| sizeof(ts_status_ioctl), sizeof(ts_status_ioctl)); |
| |
| memset(&pwmm->param.ts_status, 0x00, sizeof(ts_status_ioctl)); |
| pwmm->param.ts_status.tid = ts_status_ioctl.tid; |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| memset(&ts_status_ioctl, 0x00, sizeof(ts_status_ioctl)); |
| moal_memcpy_ext(priv->phandle, (void *)&ts_status_ioctl, |
| (void *)&pwmm->param.ts_status, sizeof(ts_status_ioctl), |
| sizeof(ts_status_ioctl)); |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&ts_status_ioctl, |
| sizeof(ts_status_ioctl), respbuflen); |
| ret = sizeof(ts_status_ioctl); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get MAC control |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_macctrl(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int data = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *cfg = NULL; |
| int ret = 0; |
| int user_data_len = 0, header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MAC_CTRL); |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &data, 1, &user_data_len); |
| } |
| |
| if (user_data_len > 1) { |
| PRINTM(MERROR, "Invalid number of arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| cfg = (mlan_ds_misc_cfg *)req->pbuf; |
| cfg->sub_command = MLAN_OID_MISC_MAC_CONTROL; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| |
| if (user_data_len == 0) |
| req->action = MLAN_ACT_GET; |
| else { |
| cfg->param.mac_ctrl = (t_u32)data; |
| req->action = MLAN_ACT_SET; |
| } |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&cfg->param.mac_ctrl, |
| sizeof(data), respbuflen); |
| ret = sizeof(data); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get connection status |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return 0 --success, otherwise fail |
| */ |
| static int |
| woal_priv_getwap(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| #ifdef STA_SUPPORT |
| mlan_bss_info bss_info; |
| #endif |
| |
| ENTER(); |
| |
| #ifdef STA_SUPPORT |
| if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_STA) { |
| memset(&bss_info, 0, sizeof(bss_info)); |
| |
| woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info); |
| |
| if (bss_info.media_connected == MTRUE) { |
| moal_memcpy_ext(priv->phandle, respbuf, |
| (t_u8 *)&bss_info.bssid, |
| MLAN_MAC_ADDR_LENGTH, respbuflen); |
| } else { |
| memset(respbuf, 0, MLAN_MAC_ADDR_LENGTH); |
| } |
| } |
| #endif |
| #ifdef UAP_SUPPORT |
| if (GET_BSS_ROLE(priv) == MLAN_BSS_ROLE_UAP) { |
| if (priv->bss_started) { |
| moal_memcpy_ext(priv->phandle, respbuf, |
| priv->current_addr, |
| MLAN_MAC_ADDR_LENGTH, respbuflen); |
| } else { |
| memset(respbuf, 0, MLAN_MAC_ADDR_LENGTH); |
| } |
| } |
| #endif |
| ret = MLAN_MAC_ADDR_LENGTH; |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get Region Code |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_region_code(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int data = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *cfg = NULL; |
| int ret = 0; |
| int user_data_len = 0, header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_REGION_CODE); |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &data, 1, &user_data_len); |
| } |
| |
| if (user_data_len > 1) { |
| PRINTM(MERROR, "Invalid number of arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| cfg = (mlan_ds_misc_cfg *)req->pbuf; |
| cfg->sub_command = MLAN_OID_MISC_REGION; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| |
| if (user_data_len == 0) |
| req->action = MLAN_ACT_GET; |
| else { |
| cfg->param.region_code = (t_u32)data; |
| req->action = MLAN_ACT_SET; |
| } |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&cfg->param.region_code, |
| sizeof(data), respbuflen); |
| ret = sizeof(data); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| #ifdef RX_PACKET_COALESCE |
| /** |
| * @brief Set/Get RX packet coalesceing setting |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_rx_pkt_coalesce_cfg(moal_private *priv, t_u8 *respbuf, |
| t_u32 respbuflen) |
| { |
| int ret = 0; |
| t_u32 data[2]; |
| int user_data_len = 0, header_len = 0; |
| mlan_ds_misc_cfg *cfg = NULL; |
| t_u8 *data_ptr; |
| mlan_ioctl_req *req = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| data_ptr = respbuf + strlen(CMD_NXP) + strlen(PRIV_CMD_RX_COAL_CFG); |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RX_COAL_CFG); |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| } |
| |
| if (sizeof(int) * user_data_len > sizeof(data)) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| if ((user_data_len != 0) && (user_data_len != 2)) { |
| PRINTM(MERROR, "Invalid arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| cfg = (mlan_ds_misc_cfg *)req->pbuf; |
| cfg->sub_command = MLAN_OID_MISC_RX_PACKET_COALESCE; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| |
| if (user_data_len == 0) { |
| req->action = MLAN_ACT_GET; |
| } else { |
| req->action = MLAN_ACT_SET; |
| cfg->param.rx_coalesce.packet_threshold = data[0]; |
| cfg->param.rx_coalesce.delay = data[1]; |
| } |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| moal_memcpy_ext(priv->phandle, respbuf, |
| (mlan_ds_misc_rx_packet_coalesce *)&cfg->param. |
| rx_coalesce, req->buf_len, respbuflen); |
| ret = req->buf_len; |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| /** |
| * @brief Set/Get FW side mac address |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return 0 --success, otherwise fail |
| */ |
| static int |
| woal_priv_fwmacaddr(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| t_u8 data[ETH_ALEN]; |
| int ret = 0; |
| int header_len = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_bss *bss = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_FWMACADDR); |
| |
| /* Allocate an IOCTL request buffer */ |
| req = (mlan_ioctl_req *)woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| /* Fill request buffer */ |
| bss = (mlan_ds_bss *)req->pbuf; |
| bss->sub_command = MLAN_OID_BSS_MAC_ADDR; |
| req->req_id = MLAN_IOCTL_BSS; |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| req->action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| req->action = MLAN_ACT_SET; |
| memset(data, 0, sizeof(data)); |
| woal_mac2u8(data, respbuf + header_len); |
| moal_memcpy_ext(priv->phandle, bss->param.mac_addr, data, |
| ETH_ALEN, sizeof(mlan_802_11_mac_addr)); |
| } |
| |
| /* Send IOCTL request to MLAN */ |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| moal_memcpy_ext(priv->phandle, respbuf, bss->param.mac_addr, |
| sizeof(data), respbuflen); |
| ret = sizeof(data); |
| HEXDUMP("FW MAC Addr:", respbuf, ETH_ALEN); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| #if defined(STA_CFG80211) || defined(UAP_CFG80211) |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) |
| /** |
| * @brief Set offchannel |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return 0 --success, otherwise fail |
| */ |
| static int |
| woal_priv_offchannel(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int data[4]; |
| int ret = 0; |
| t_u8 status = 1; |
| t_u8 chan_type = CHAN_NO_HT; |
| int user_data_len = 0, header_len = 0; |
| |
| ENTER(); |
| |
| memset(data, 0, sizeof(data)); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_OFFCHANNEL); |
| |
| if (header_len == (int)strlen(respbuf)) { |
| /* Query current remain on channel status */ |
| if (priv->phandle->remain_on_channel) |
| ret = sprintf(respbuf, |
| "There is pending remain on channel from bss %d\n", |
| priv->phandle->remain_bss_index) + 1; |
| else |
| ret = sprintf(respbuf, |
| "There is no pending remain on channel\n") |
| + 1; |
| goto done; |
| } else |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| |
| if (sizeof(int) * user_data_len > sizeof(data)) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| if (user_data_len >= 1) { |
| if ((data[0] != 0) && (data[0] != 1)) { |
| PRINTM(MERROR, "action (%d) must be either 0 or 1\n", |
| data[0]); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| if (user_data_len == 2) { |
| if (data[0] == 1) { |
| PRINTM(MERROR, |
| "channel and duration must both the mentioned\n"); |
| ret = -EINVAL; |
| goto done; |
| } else { |
| PRINTM(MWARN, |
| "extra arguments are ignored since action is 'cancel'\n"); |
| } |
| } |
| if (user_data_len >= 3) { |
| if (data[0] == 1) { |
| if (data[1] < 0) { |
| PRINTM(MERROR, "channel cannot be negative\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (data[2] < 0) { |
| PRINTM(MERROR, "duration cannot be negative\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (user_data_len == 4) { |
| if (data[3] && |
| (data[3] != CHANNEL_BW_40MHZ_ABOVE) && |
| (data[3] != CHANNEL_BW_40MHZ_BELOW) |
| && (data[3] != CHANNEL_BW_80MHZ) |
| ) { |
| PRINTM(MERROR, "invalid bandwidth"); |
| ret = -EINVAL; |
| goto done; |
| } |
| switch (data[3]) { |
| case CHANNEL_BW_40MHZ_ABOVE: |
| chan_type = CHAN_HT40PLUS; |
| break; |
| case CHANNEL_BW_40MHZ_BELOW: |
| chan_type = CHAN_HT40MINUS; |
| break; |
| case CHANNEL_BW_80MHZ: |
| chan_type = CHAN_VHT80; |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| } |
| |
| if (data[0] == 0) { |
| if (!priv->phandle->remain_on_channel) { |
| ret = sprintf(respbuf, |
| "There is no pending remain on channel to be canceled\n") |
| + 1; |
| goto done; |
| } |
| if (woal_cfg80211_remain_on_channel_cfg(priv, MOAL_IOCTL_WAIT, |
| MTRUE, &status, NULL, 0, |
| 0)) { |
| PRINTM(MERROR, "remain_on_channel: Failed to cancel\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| if (status == MLAN_STATUS_SUCCESS) |
| priv->phandle->remain_on_channel = MFALSE; |
| } else if (data[0] == 1) { |
| if (woal_cfg80211_remain_on_channel_cfg |
| (priv, MOAL_IOCTL_WAIT, MFALSE, &status, |
| ieee80211_get_channel(priv->wdev->wiphy, |
| ieee80211_channel_to_frequency(data |
| [1] |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) |
| , |
| (data |
| [1] |
| <= |
| 14 ? |
| IEEE80211_BAND_2GHZ |
| : |
| IEEE80211_BAND_5GHZ) |
| #endif |
| )), chan_type, (t_u32)data[2])) { |
| PRINTM(MERROR, "remain_on_channel: Failed to start\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| if (status == MLAN_STATUS_SUCCESS) { |
| priv->phandle->remain_on_channel = MTRUE; |
| priv->phandle->remain_bss_index = priv->bss_index; |
| } |
| } |
| |
| if (status != MLAN_STATUS_SUCCESS) |
| ret = -EFAULT; |
| else |
| ret = sprintf(respbuf, "OK\n") + 1; |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| #endif |
| |
| /** |
| * @brief Set/Get dscp map |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return 0 --success, otherwise fail |
| */ |
| static int |
| woal_priv_set_get_dscp_map(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = MLAN_STATUS_SUCCESS; |
| t_u8 *pos = NULL; |
| int copy_size = 0, header_len = 0; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DSCP_MAP); |
| if ((int)strlen(respbuf) != header_len) { |
| /* SET operation */ |
| pos = respbuf + header_len; |
| moal_memcpy_ext(priv->phandle, priv->dscp_map, pos, |
| sizeof(priv->dscp_map), sizeof(priv->dscp_map)); |
| } |
| |
| copy_size = MIN(sizeof(priv->dscp_map), respbuflen); |
| moal_memcpy_ext(priv->phandle, respbuf, priv->dscp_map, copy_size, |
| respbuflen); |
| ret = copy_size; |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get extended driver version |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_get_driver_verext(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int data = 0; |
| mlan_ds_get_info *info = NULL; |
| mlan_ioctl_req *req = NULL; |
| int ret = 0; |
| int copy_size = 0; |
| int user_data_len = 0, header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info)); |
| if (req == NULL) { |
| ret = ENOMEM; |
| goto done; |
| } |
| |
| 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; |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_VEREXT); |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &data, 1, &user_data_len); |
| } |
| |
| if (user_data_len > 1) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| info->param.ver_ext.version_str_sel = data; |
| 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; |
| } |
| |
| /* |
| * Set the amount to copy back to the application as the minimum of the |
| * available assoc resp data or the buffer provided by the application |
| */ |
| copy_size = MIN(strlen(info->param.ver_ext.version_str), respbuflen); |
| moal_memcpy_ext(priv->phandle, respbuf, info->param.ver_ext.version_str, |
| copy_size, respbuflen); |
| ret = copy_size; |
| PRINTM(MINFO, "MOAL EXTENDED VERSION: %s\n", |
| info->param.ver_ext.version_str); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| #ifdef USB |
| #ifdef CONFIG_USB_SUSPEND |
| /** |
| * @brief This function makes USB device to suspend. |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_enter_usb_suspend(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| |
| ENTER(); |
| ret = woal_enter_usb_suspend(priv->phandle); |
| moal_memcpy_ext(priv->phandle, respbuf, &ret, sizeof(int), respbuflen); |
| ret = sizeof(int); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief This function makes USB device to resume. |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_exit_usb_suspend(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| |
| ENTER(); |
| ret = woal_exit_usb_suspend(priv->phandle); |
| moal_memcpy_ext(priv->phandle, respbuf, &ret, sizeof(int), respbuflen); |
| ret = sizeof(int); |
| |
| LEAVE(); |
| return ret; |
| } |
| #endif /* CONFIG_USB_SUSPEND */ |
| #endif |
| |
| #if defined(STA_SUPPORT) && defined(STA_WEXT) |
| /** |
| * @brief SET/Get radio |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_radio_ctrl(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0, option = 0; |
| int user_data_len = 0, header_len = 0; |
| mlan_bss_info bss_info; |
| |
| ENTER(); |
| |
| memset(&bss_info, 0, sizeof(bss_info)); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RADIO_CTRL); |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &option, 1, |
| &user_data_len); |
| } |
| |
| if (user_data_len > 1) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (user_data_len == 1) { |
| /* Set radio */ |
| if (option < 0 || option > 1) { |
| PRINTM(MERROR, "Invalid arguments!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (MLAN_STATUS_SUCCESS != woal_set_radio(priv, (t_u8)option)) |
| ret = -EFAULT; |
| goto done; |
| } else { |
| /* Get radio status */ |
| woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info); |
| moal_memcpy_ext(priv->phandle, respbuf, &bss_info.radio_on, |
| sizeof(bss_info.radio_on), respbuflen); |
| ret = sizeof(bss_info.radio_on); |
| } |
| done: |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| |
| /** |
| * @brief Implement WMM enable command |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_wmm_cfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int data = 0; |
| mlan_ds_wmm_cfg *wmm = NULL; |
| mlan_ioctl_req *req = NULL; |
| int ret = 0; |
| int user_data_len = 0, header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_wmm_cfg)); |
| if (req == NULL) { |
| ret = ENOMEM; |
| goto done; |
| } |
| |
| wmm = (mlan_ds_wmm_cfg *)req->pbuf; |
| wmm->sub_command = MLAN_OID_WMM_CFG_ENABLE; |
| req->req_id = MLAN_IOCTL_WMM_CFG; |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_WMM_CFG); |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| req->action = MLAN_ACT_GET; |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &data, 1, &user_data_len); |
| if (user_data_len == 1) { |
| /* Set wmm */ |
| if ((data < CMD_DISABLED) || (data > CMD_ENABLED)) { |
| PRINTM(MERROR, "Invalid arguments!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| req->action = MLAN_ACT_SET; |
| if (data == CMD_DISABLED) |
| wmm->param.wmm_enable = MFALSE; |
| else |
| wmm->param.wmm_enable = MTRUE; |
| } else { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| moal_memcpy_ext(priv->phandle, respbuf, &wmm->param.wmm_enable, |
| sizeof(wmm->param.wmm_enable), respbuflen); |
| ret = sizeof(wmm->param.wmm_enable); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Implement Mininum BA Threshold cfg command |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_min_ba_threshold_cfg(moal_private *priv, t_u8 *respbuf, |
| t_u32 respbuflen) |
| { |
| int data = 0; |
| mlan_ds_11n_cfg *cfg_11n = NULL; |
| mlan_ioctl_req *req = NULL; |
| int ret = 0; |
| int user_data_len = 0, header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); |
| if (req == NULL) { |
| ret = ENOMEM; |
| goto done; |
| } |
| cfg_11n = (mlan_ds_11n_cfg *)req->pbuf; |
| cfg_11n->sub_command = MLAN_OID_11N_CFG_MIN_BA_THRESHOLD; |
| req->req_id = MLAN_IOCTL_11N_CFG; |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MIN_BA_THRESH_CFG); |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| req->action = MLAN_ACT_GET; |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &data, 1, &user_data_len); |
| if (user_data_len == 1) { |
| /* Set minimum BA Threshold */ |
| if ((data < 0) || (data > 16)) { |
| PRINTM(MERROR, |
| "Error: Valid minimum BA threshold range (0-16)!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| req->action = MLAN_ACT_SET; |
| cfg_11n->param.min_ba_threshold = data; |
| } else { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| moal_memcpy_ext(priv->phandle, respbuf, |
| &cfg_11n->param.min_ba_threshold, |
| sizeof(cfg_11n->param.min_ba_threshold), respbuflen); |
| ret = sizeof(cfg_11n->param.min_ba_threshold); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| #if defined(STA_SUPPORT) |
| /** |
| * @brief Implement 802.11D enable command |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_11d_cfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int data = 0; |
| mlan_ds_11d_cfg *pcfg_11d = NULL; |
| mlan_ioctl_req *req = NULL; |
| int ret = 0; |
| int user_data_len = 0, header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg)); |
| if (req == NULL) { |
| ret = ENOMEM; |
| goto done; |
| } |
| |
| pcfg_11d = (mlan_ds_11d_cfg *)req->pbuf; |
| pcfg_11d->sub_command = MLAN_OID_11D_CFG_ENABLE; |
| req->req_id = MLAN_IOCTL_11D_CFG; |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_11D_CFG); |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| req->action = MLAN_ACT_GET; |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &data, 1, &user_data_len); |
| if (user_data_len == 1) { |
| if ((data < CMD_DISABLED) || (data > CMD_ENABLED)) { |
| PRINTM(MERROR, "Invalid arguments!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| req->action = MLAN_ACT_SET; |
| if (data == CMD_DISABLED) |
| pcfg_11d->param.enable_11d = MFALSE; |
| else |
| pcfg_11d->param.enable_11d = MTRUE; |
| } else { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| moal_memcpy_ext(priv->phandle, respbuf, &pcfg_11d->param.enable_11d, |
| sizeof(pcfg_11d->param.enable_11d), respbuflen); |
| ret = sizeof(pcfg_11d->param.enable_11d); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Implement 802.11D clear chan table command |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return 0 --success, otherwise fail |
| */ |
| static int |
| woal_priv_11d_clr_chan_tbl(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ds_11d_cfg *pcfg_11d = NULL; |
| mlan_ioctl_req *req = NULL; |
| int ret = 0; |
| int header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg)); |
| if (req == NULL) { |
| ret = ENOMEM; |
| goto done; |
| } |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_11D_CLR_TBL); |
| |
| if ((int)strlen(respbuf) != header_len) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| pcfg_11d = (mlan_ds_11d_cfg *)req->pbuf; |
| pcfg_11d->sub_command = MLAN_OID_11D_CLR_CHAN_TABLE; |
| req->req_id = MLAN_IOCTL_11D_CFG; |
| req->action = MLAN_ACT_SET; |
| |
| 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; |
| } |
| #endif |
| |
| #ifndef OPCHAN |
| /** |
| * @brief Set/Get WWS mode |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_wws_cfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int data = 0; |
| mlan_ds_misc_cfg *wws = NULL; |
| mlan_ioctl_req *req = NULL; |
| int ret = 0; |
| int user_data_len = 0, header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = ENOMEM; |
| goto done; |
| } |
| |
| wws = (mlan_ds_misc_cfg *)req->pbuf; |
| wws->sub_command = MLAN_OID_MISC_WWS; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_WWS_CFG); |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| req->action = MLAN_ACT_GET; |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &data, 1, &user_data_len); |
| if (user_data_len == 1) { |
| if ((data < CMD_DISABLED) || (data > CMD_ENABLED)) { |
| PRINTM(MERROR, |
| "Invalid arguments, WWS config not changed!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| req->action = MLAN_ACT_SET; |
| wws->param.wws_cfg = (t_u16)data; |
| } else { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| moal_memcpy_ext(priv->phandle, respbuf, &wws->param.wws_cfg, |
| sizeof(wws->param.wws_cfg), respbuflen); |
| ret = sizeof(wws->param.wws_cfg); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| |
| #if defined(REASSOCIATION) |
| /** |
| * @brief Set/Get reassociation settings |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_set_get_reassoc(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| moal_handle *handle = priv->phandle; |
| int data = 0; |
| int ret = 0; |
| int user_data_len = 0, header_len = 0; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_REASSOCTRL); |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| data = (int)(priv->reassoc_on); |
| moal_memcpy_ext(handle, respbuf, &data, sizeof(data), |
| respbuflen); |
| ret = sizeof(data); |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &data, 1, &user_data_len); |
| if (user_data_len == 1) { |
| if (data == 0) { |
| handle->reassoc_on &= ~MBIT(priv->bss_index); |
| priv->reassoc_on = MFALSE; |
| priv->reassoc_required = MFALSE; |
| if (!handle->reassoc_on && |
| handle->is_reassoc_timer_set == MTRUE) { |
| woal_cancel_timer(&handle-> |
| reassoc_timer); |
| handle->is_reassoc_timer_set = MFALSE; |
| } |
| } else if (data == 1) { |
| handle->reassoc_on |= MBIT(priv->bss_index); |
| priv->reassoc_on = MTRUE; |
| } else { |
| PRINTM(MERROR, "Invalid arguments!\n"); |
| ret = -EINVAL; |
| } |
| } else { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| } |
| } |
| |
| LEAVE(); |
| return ret; |
| } |
| #endif /* REASSOCIATION */ |
| |
| /** |
| * @brief Get Transmit buffer size |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_txbuf_cfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ds_11n_cfg *cfg_11n = NULL; |
| mlan_ioctl_req *req = NULL; |
| int ret = 0; |
| int buf_size = 0, header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); |
| if (req == NULL) { |
| ret = ENOMEM; |
| goto done; |
| } |
| |
| cfg_11n = (mlan_ds_11n_cfg *)req->pbuf; |
| cfg_11n->sub_command = MLAN_OID_11N_CFG_MAX_TX_BUF_SIZE; |
| req->req_id = MLAN_IOCTL_11N_CFG; |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TXBUF_CFG); |
| |
| if ((int)strlen(respbuf) != header_len) { |
| PRINTM(MERROR, |
| "Don't support set Tx buffer size after driver loaded!\n"); |
| ret = -EINVAL; |
| goto done; |
| } else { |
| /* Get Tx buffer size from MLAN */ |
| req->action = MLAN_ACT_GET; |
| } |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| buf_size = cfg_11n->param.tx_buf_size; |
| moal_memcpy_ext(priv->phandle, respbuf, &buf_size, sizeof(buf_size), |
| respbuflen); |
| ret = sizeof(buf_size); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| #ifdef STA_SUPPORT |
| /** |
| * @brief Set/Get auth type |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_auth_type(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int auth_type = 0; |
| t_u32 auth_mode; |
| int ret = 0; |
| int user_data_len = 0, header_len = 0; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_AUTH_TYPE); |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| if (MLAN_STATUS_SUCCESS != |
| woal_get_auth_mode(priv, MOAL_IOCTL_WAIT, &auth_mode)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| user_data_len = 0; |
| auth_type = auth_mode; |
| moal_memcpy_ext(priv->phandle, respbuf, &auth_type, |
| sizeof(auth_type), respbuflen); |
| ret = sizeof(auth_type); |
| goto done; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &auth_type, 1, |
| &user_data_len); |
| if (user_data_len == 1) { |
| PRINTM(MINFO, "SET: auth_type %d\n", auth_type); |
| if (((auth_type < MLAN_AUTH_MODE_OPEN) || |
| (auth_type > MLAN_AUTH_MODE_SAE)) |
| && (auth_type != MLAN_AUTH_MODE_AUTO) |
| ) { |
| ret = -EINVAL; |
| goto done; |
| } |
| auth_mode = auth_type; |
| if (MLAN_STATUS_SUCCESS != |
| woal_set_auth_mode(priv, MOAL_IOCTL_WAIT, |
| auth_mode)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| } else { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| } |
| } |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| |
| /** |
| * @brief Set/get user provisioned local power constraint |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_11h_local_pwr_constraint(moal_private *priv, t_u8 *respbuf, |
| t_u32 respbuflen) |
| { |
| int data = 0; |
| mlan_ds_11h_cfg *ds_11hcfg = NULL; |
| mlan_ioctl_req *req = NULL; |
| int ret = 0; |
| int user_data_len = 0, header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg)); |
| if (req == NULL) { |
| ret = ENOMEM; |
| goto done; |
| } |
| |
| ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf; |
| ds_11hcfg->sub_command = MLAN_OID_11H_LOCAL_POWER_CONSTRAINT; |
| req->req_id = MLAN_IOCTL_11H_CFG; |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_POWER_CONS); |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| req->action = MLAN_ACT_GET; |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &data, 1, &user_data_len); |
| if (user_data_len == 1) { |
| req->action = MLAN_ACT_SET; |
| ds_11hcfg->param.usr_local_power_constraint = |
| (t_s8)data; |
| } else { |
| PRINTM(MERROR, "Too many 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 (req->action == MLAN_ACT_GET) { |
| data = (int)ds_11hcfg->param.usr_local_power_constraint; |
| moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data), |
| respbuflen); |
| ret = sizeof(data); |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/get HT stream configurations |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_ht_stream_cfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int data = 0; |
| mlan_ds_11n_cfg *cfg = NULL; |
| mlan_ioctl_req *req = NULL; |
| int ret = 0; |
| int user_data_len = 0, header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); |
| if (req == NULL) { |
| ret = ENOMEM; |
| goto done; |
| } |
| |
| cfg = (mlan_ds_11n_cfg *)req->pbuf; |
| cfg->sub_command = MLAN_OID_11N_CFG_STREAM_CFG; |
| req->req_id = MLAN_IOCTL_11N_CFG; |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_HT_STREAM_CFG); |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| req->action = MLAN_ACT_GET; |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &data, 1, &user_data_len); |
| if (user_data_len == 1) { |
| if (data != HT_STREAM_MODE_1X1 && |
| data != HT_STREAM_MODE_2X2) { |
| PRINTM(MERROR, "Invalid arguments!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| req->action = MLAN_ACT_SET; |
| cfg->param.stream_cfg = data; |
| } else { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| data = ((mlan_ds_11n_cfg *)req->pbuf)->param.stream_cfg; |
| moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data), |
| respbuflen); |
| ret = sizeof(data); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set mimo switch configurations |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_mimo_switch(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int data[2] = { 0 }; |
| mlan_ds_radio_cfg *radio = NULL; |
| mlan_ioctl_req *req = NULL; |
| int ret = 0; |
| int user_data_len = 0, header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| 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_MIMO_SWITCH; |
| req->req_id = MLAN_IOCTL_RADIO_CFG; |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MIMO_SWITCH); |
| |
| if ((int)strlen(respbuf) > header_len) { |
| /* SET operation */ |
| req->action = MLAN_ACT_SET; |
| parse_arguments(respbuf + header_len, data, 2, &user_data_len); |
| if (user_data_len == 2) { |
| radio->param.mimo_switch_cfg.txpath_antmode = data[0]; |
| radio->param.mimo_switch_cfg.rxpath_antmode = data[1]; |
| } else { |
| 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; |
| } |
| } else { |
| PRINTM(MERROR, "Invalid arguments!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get thermal reading |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_thermal(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ds_misc_cfg *cfg = NULL; |
| mlan_ioctl_req *req = NULL; |
| int ret = 0, header_len = 0, data = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = ENOMEM; |
| goto done; |
| } |
| |
| cfg = (mlan_ds_misc_cfg *)req->pbuf; |
| cfg->sub_command = MLAN_OID_MISC_THERMAL; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_THERMAL); |
| |
| if ((int)strlen(respbuf) != header_len) { |
| PRINTM(MERROR, "Set is not supported for this command\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| req->action = MLAN_ACT_GET; |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| data = (int)cfg->param.thermal; |
| moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data), |
| respbuflen); |
| ret = sizeof(data); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get beacon interval |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_beacon_interval(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int data = 0; |
| mlan_ds_bss *bss = NULL; |
| mlan_ioctl_req *req = NULL; |
| int ret = 0; |
| int user_data_len = 0, header_len = 0; |
| 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_IBSS_BCN_INTERVAL; |
| req->req_id = MLAN_IOCTL_BSS; |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_BCN_INTERVAL); |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| req->action = MLAN_ACT_GET; |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &data, 1, &user_data_len); |
| if (user_data_len == 1) { |
| if ((data < MLAN_MIN_BEACON_INTERVAL) || |
| (data > MLAN_MAX_BEACON_INTERVAL)) { |
| PRINTM(MERROR, "Invalid arguments!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| req->action = MLAN_ACT_SET; |
| bss->param.bcn_interval = data; |
| } else { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| data = ((mlan_ds_bss *)req->pbuf)->param.bcn_interval; |
| moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data), |
| respbuflen); |
| ret = sizeof(data); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| #ifdef STA_SUPPORT |
| /** |
| * @brief Get signal |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_get_signal(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| /** Input data size */ |
| #define IN_DATA_SIZE 2 |
| /** Output data size */ |
| #define OUT_DATA_SIZE 12 |
| int ret = 0; |
| int in_data[IN_DATA_SIZE]; |
| int out_data[OUT_DATA_SIZE]; |
| mlan_ds_get_signal signal; |
| int data_length = 0; |
| int user_data_len = 0, header_len = 0; |
| |
| ENTER(); |
| |
| memset(in_data, 0, sizeof(in_data)); |
| memset(out_data, 0, sizeof(out_data)); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_SIGNAL); |
| |
| if ((int)strlen(respbuf) != header_len) |
| parse_arguments(respbuf + header_len, in_data, IN_DATA_SIZE, |
| &user_data_len); |
| |
| if (priv->media_connected == MFALSE) { |
| PRINTM(MERROR, "Can not get RSSI in disconnected state\n"); |
| ret = -ENOTSUPP; |
| goto done; |
| } |
| |
| if (user_data_len) { |
| if (user_data_len > IN_DATA_SIZE) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| |
| switch (user_data_len) { |
| case 0: /* No checking, get everything */ |
| break; |
| case 2: /* Check subtype range */ |
| if (in_data[1] < 1 || in_data[1] > 4) { |
| ret = -EINVAL; |
| goto done; |
| } |
| /* Fall through */ |
| case 1: /* Check type range */ |
| if (in_data[0] < 1 || in_data[0] > 3) { |
| ret = -EINVAL; |
| goto done; |
| } |
| break; |
| default: |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| memset(&signal, 0, sizeof(mlan_ds_get_signal)); |
| if (MLAN_STATUS_SUCCESS != |
| woal_get_signal_info(priv, MOAL_IOCTL_WAIT, &signal)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| PRINTM(MINFO, "RSSI Beacon Last : %d\n", (int)signal.bcn_rssi_last); |
| PRINTM(MINFO, "RSSI Beacon Average: %d\n", (int)signal.bcn_rssi_avg); |
| PRINTM(MINFO, "RSSI Data Last : %d\n", (int)signal.data_rssi_last); |
| PRINTM(MINFO, "RSSI Data Average : %d\n", (int)signal.data_rssi_avg); |
| PRINTM(MINFO, "SNR Beacon Last : %d\n", (int)signal.bcn_snr_last); |
| PRINTM(MINFO, "SNR Beacon Average : %d\n", (int)signal.bcn_snr_avg); |
| PRINTM(MINFO, "SNR Data Last : %d\n", (int)signal.data_snr_last); |
| PRINTM(MINFO, "SNR Data Average : %d\n", (int)signal.data_snr_avg); |
| PRINTM(MINFO, "NF Beacon Last : %d\n", (int)signal.bcn_nf_last); |
| PRINTM(MINFO, "NF Beacon Average : %d\n", (int)signal.bcn_nf_avg); |
| PRINTM(MINFO, "NF Data Last : %d\n", (int)signal.data_nf_last); |
| PRINTM(MINFO, "NF Data Average : %d\n", (int)signal.data_nf_avg); |
| |
| /* Check type */ |
| switch (in_data[0]) { |
| case 0: /* Send everything */ |
| out_data[data_length++] = signal.bcn_rssi_last; |
| out_data[data_length++] = signal.bcn_rssi_avg; |
| out_data[data_length++] = signal.data_rssi_last; |
| out_data[data_length++] = signal.data_rssi_avg; |
| out_data[data_length++] = signal.bcn_snr_last; |
| out_data[data_length++] = signal.bcn_snr_avg; |
| out_data[data_length++] = signal.data_snr_last; |
| out_data[data_length++] = signal.data_snr_avg; |
| out_data[data_length++] = signal.bcn_nf_last; |
| out_data[data_length++] = signal.bcn_nf_avg; |
| out_data[data_length++] = signal.data_nf_last; |
| out_data[data_length++] = signal.data_nf_avg; |
| break; |
| case 1: /* RSSI */ |
| /* Check subtype */ |
| switch (in_data[1]) { |
| case 0: /* Everything */ |
| out_data[data_length++] = signal.bcn_rssi_last; |
| out_data[data_length++] = signal.bcn_rssi_avg; |
| out_data[data_length++] = signal.data_rssi_last; |
| out_data[data_length++] = signal.data_rssi_avg; |
| break; |
| case 1: /* bcn last */ |
| out_data[data_length++] = signal.bcn_rssi_last; |
| break; |
| case 2: /* bcn avg */ |
| out_data[data_length++] = signal.bcn_rssi_avg; |
| break; |
| case 3: /* data last */ |
| out_data[data_length++] = signal.data_rssi_last; |
| break; |
| case 4: /* data avg */ |
| out_data[data_length++] = signal.data_rssi_avg; |
| break; |
| default: |
| break; |
| } |
| break; |
| case 2: /* SNR */ |
| /* Check subtype */ |
| switch (in_data[1]) { |
| case 0: /* Everything */ |
| out_data[data_length++] = signal.bcn_snr_last; |
| out_data[data_length++] = signal.bcn_snr_avg; |
| out_data[data_length++] = signal.data_snr_last; |
| out_data[data_length++] = signal.data_snr_avg; |
| break; |
| case 1: /* bcn last */ |
| out_data[data_length++] = signal.bcn_snr_last; |
| break; |
| case 2: /* bcn avg */ |
| out_data[data_length++] = signal.bcn_snr_avg; |
| break; |
| case 3: /* data last */ |
| out_data[data_length++] = signal.data_snr_last; |
| break; |
| case 4: /* data avg */ |
| out_data[data_length++] = signal.data_snr_avg; |
| break; |
| default: |
| break; |
| } |
| break; |
| case 3: /* NF */ |
| /* Check subtype */ |
| switch (in_data[1]) { |
| case 0: /* Everything */ |
| out_data[data_length++] = signal.bcn_nf_last; |
| out_data[data_length++] = signal.bcn_nf_avg; |
| out_data[data_length++] = signal.data_nf_last; |
| out_data[data_length++] = signal.data_nf_avg; |
| break; |
| case 1: /* bcn last */ |
| out_data[data_length++] = signal.bcn_nf_last; |
| break; |
| case 2: /* bcn avg */ |
| out_data[data_length++] = signal.bcn_nf_avg; |
| break; |
| case 3: /* data last */ |
| out_data[data_length++] = signal.data_nf_last; |
| break; |
| case 4: /* data avg */ |
| out_data[data_length++] = signal.data_nf_avg; |
| break; |
| default: |
| break; |
| } |
| break; |
| default: |
| break; |
| } |
| |
| moal_memcpy_ext(priv->phandle, respbuf, out_data, |
| (data_length * sizeof(int)), respbuflen); |
| ret = data_length * sizeof(int); |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| static int |
| woal_signal_ext_enable(moal_private *priv, t_u8 enable) |
| { |
| int ret = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_snmp_mib *snmp = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| /* Allocate an IOCTL request buffer */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| snmp = (mlan_ds_snmp_mib *)req->pbuf; |
| snmp->sub_command = MLAN_OID_SNMP_MIB_SIGNALEXT_ENABLE; |
| req->req_id = MLAN_IOCTL_SNMP_MIB; |
| req->action = MLAN_ACT_SET; |
| snmp->param.signalext_enable = enable; |
| |
| /* 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 Get signal |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_get_signal_ext(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| #define PATH_SIZE 13 |
| int ret = 0; |
| int data = 0, path = 0, data_len = 0; |
| int user_data_len = 0, header_len = 0; |
| int out_data[PATH_SIZE * MAX_PATH_NUM] = { 0 }; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_get_info *info = NULL; |
| mlan_ds_get_signal signal_get[MAX_PATH_NUM]; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| int path_num; |
| t_u8 enable = 1; |
| |
| ENTER(); |
| |
| if (priv->media_connected == MFALSE) { |
| PRINTM(MERROR, "Can not get RSSI in disconnected state\n"); |
| ret = -ENOTSUPP; |
| goto done; |
| } |
| |
| /* Allocate an IOCTL request buffer */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_SIGNAL_EXT); |
| |
| if ((int)strlen(respbuf) != header_len) { |
| parse_arguments(respbuf + header_len, &data, |
| sizeof(data) / sizeof(int), &user_data_len); |
| } |
| |
| if (user_data_len > 1) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (data < PATH_ALL || data > PATH_AB) { |
| PRINTM(MERROR, "Wrong arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| /** Enable signalext feature in firmware */ |
| if (MLAN_STATUS_SUCCESS != woal_signal_ext_enable(priv, enable)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| woal_sched_timeout(1000); |
| enable = 0; |
| |
| /* Fill request buffer */ |
| info = (mlan_ds_get_info *)req->pbuf; |
| info->sub_command = MLAN_OID_GET_SIGNAL_EXT; |
| req->req_id = MLAN_IOCTL_GET_INFO; |
| req->action = MLAN_ACT_GET; |
| info->param.path_id = (t_u16)data; |
| |
| /* Send IOCTL request to MLAN */ |
| if (MLAN_STATUS_SUCCESS != |
| woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { |
| woal_signal_ext_enable(priv, enable); |
| ret = -EFAULT; |
| goto done; |
| } |
| if (MLAN_STATUS_SUCCESS != woal_signal_ext_enable(priv, enable)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| path_num = 1; |
| if (data == PATH_ALL) { |
| moal_memcpy_ext(priv->phandle, signal_get, |
| info->param.signal_ext, sizeof(signal_get), |
| sizeof(signal_get)); |
| path_num = MAX_PATH_NUM; |
| } else |
| moal_memcpy_ext(priv->phandle, signal_get, |
| info->param.signal_ext, |
| sizeof(mlan_ds_get_signal), sizeof(signal_get)); |
| |
| for (path = 0; path < path_num; path++) { |
| if (signal_get[path].selector == PATH_AB) |
| PRINTM(MINFO, "PATH A+B:\n"); |
| else if (signal_get[path].selector == PATH_A) |
| PRINTM(MINFO, "PATH A:\n"); |
| else if (signal_get[path].selector == PATH_B) |
| PRINTM(MINFO, "PATH B:\n"); |
| PRINTM(MINFO, "RSSI Beacon Last : %d\n", |
| (int)signal_get[path].bcn_rssi_last); |
| PRINTM(MINFO, "RSSI Beacon Average: %d\n", |
| (int)signal_get[path].bcn_rssi_avg); |
| PRINTM(MINFO, "RSSI Data Last : %d\n", |
| (int)signal_get[path].data_rssi_last); |
| PRINTM(MINFO, "RSSI Data Average : %d\n", |
| (int)signal_get[path].data_rssi_avg); |
| PRINTM(MINFO, "SNR Beacon Last : %d\n", |
| (int)signal_get[path].bcn_snr_last); |
| PRINTM(MINFO, "SNR Beacon Average : %d\n", |
| (int)signal_get[path].bcn_snr_avg); |
| PRINTM(MINFO, "SNR Data Last : %d\n", |
| (int)signal_get[path].data_snr_last); |
| PRINTM(MINFO, "SNR Data Average : %d\n", |
| (int)signal_get[path].data_snr_avg); |
| PRINTM(MINFO, "NF Beacon Last : %d\n", |
| (int)signal_get[path].bcn_nf_last); |
| PRINTM(MINFO, "NF Beacon Average : %d\n", |
| (int)signal_get[path].bcn_nf_avg); |
| PRINTM(MINFO, "NF Data Last : %d\n", |
| (int)signal_get[path].data_nf_last); |
| PRINTM(MINFO, "NF Data Average : %d\n", |
| (int)signal_get[path].data_nf_avg); |
| out_data[data_len++] = (int)signal_get[path].selector; |
| out_data[data_len++] = (int)signal_get[path].bcn_rssi_last; |
| out_data[data_len++] = (int)signal_get[path].bcn_rssi_avg; |
| out_data[data_len++] = (int)signal_get[path].data_rssi_last; |
| out_data[data_len++] = (int)signal_get[path].data_rssi_avg; |
| out_data[data_len++] = (int)signal_get[path].bcn_snr_last; |
| out_data[data_len++] = (int)signal_get[path].bcn_snr_avg; |
| out_data[data_len++] = (int)signal_get[path].data_snr_last; |
| out_data[data_len++] = (int)signal_get[path].data_snr_avg; |
| out_data[data_len++] = (int)signal_get[path].bcn_nf_last; |
| out_data[data_len++] = (int)signal_get[path].bcn_nf_avg; |
| out_data[data_len++] = (int)signal_get[path].data_nf_last; |
| out_data[data_len++] = (int)signal_get[path].data_nf_avg; |
| } |
| moal_memcpy_ext(priv->phandle, respbuf, out_data, |
| (MIN((PATH_SIZE * MAX_PATH_NUM), data_len) * |
| sizeof(int)), respbuflen); |
| ret = data_len * sizeof(int); |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get signalext v2 |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_get_signal_ext_v2(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| #define PATH_SIZE 13 |
| int ret = 0; |
| int data = 0, path = 0, data_len = 0; |
| int user_data_len = 0, header_len = 0; |
| int out_data[PATH_SIZE * MAX_PATH_NUM] = { 0 }; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_get_info *info = NULL; |
| mlan_ds_get_signal signal_get[MAX_PATH_NUM]; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| int path_num; |
| |
| ENTER(); |
| |
| if (priv->media_connected == MFALSE) { |
| PRINTM(MERROR, "Can not get RSSI in disconnected state\n"); |
| ret = -ENOTSUPP; |
| goto done; |
| } |
| |
| /* Allocate an IOCTL request buffer */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_SIGNAL_EXT_V2); |
| if ((int)strlen(respbuf) != header_len) { |
| parse_arguments(respbuf + header_len, &data, |
| sizeof(data) / sizeof(int), &user_data_len); |
| } |
| |
| if (user_data_len > 1) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (data < PATH_ALL || data > PATH_AB) { |
| PRINTM(MERROR, "Wrong arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| /* Fill request buffer */ |
| info = (mlan_ds_get_info *)req->pbuf; |
| info->sub_command = MLAN_OID_GET_SIGNAL_EXT; |
| req->req_id = MLAN_IOCTL_GET_INFO; |
| req->action = MLAN_ACT_GET; |
| info->param.path_id = (t_u16)data; |
| |
| /* Send IOCTL request to MLAN */ |
| if (MLAN_STATUS_SUCCESS != |
| woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) { |
| PRINTM(MERROR, |
| "Enable signalextcfg: mlanutl mlanX signalextcfg 1" |
| " before issuing this command\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| path_num = 1; |
| |
| if (data == PATH_ALL) { |
| moal_memcpy_ext(priv->phandle, signal_get, |
| info->param.signal_ext, sizeof(signal_get), |
| sizeof(signal_get)); |
| path_num = MAX_PATH_NUM; |
| } else |
| moal_memcpy_ext(priv->phandle, signal_get, |
| info->param.signal_ext, |
| sizeof(mlan_ds_get_signal), sizeof(signal_get)); |
| |
| PRINTM(MMSG, "data=%d path_num=%d\n", data, path_num); |
| |
| for (path = 0; path < path_num; path++) { |
| if (signal_get[path].selector == PATH_AB) |
| PRINTM(MINFO, "PATH A+B:\n"); |
| else if (signal_get[path].selector == PATH_A) |
| PRINTM(MINFO, "PATH A:\n"); |
| else if (signal_get[path].selector == PATH_B) |
| PRINTM(MINFO, "PATH B:\n"); |
| PRINTM(MINFO, "RSSI Beacon Last : %d\n", |
| (int)signal_get[path].bcn_rssi_last); |
| PRINTM(MINFO, "RSSI Beacon Average: %d\n", |
| (int)signal_get[path].bcn_rssi_avg); |
| PRINTM(MINFO, "RSSI Data Last : %d\n", |
| (int)signal_get[path].data_rssi_last); |
| PRINTM(MINFO, "RSSI Data Average : %d\n", |
| (int)signal_get[path].data_rssi_avg); |
| PRINTM(MINFO, "SNR Beacon Last : %d\n", |
| (int)signal_get[path].bcn_snr_last); |
| PRINTM(MINFO, "SNR Beacon Average : %d\n", |
| (int)signal_get[path].bcn_snr_avg); |
| PRINTM(MINFO, "SNR Data Last : %d\n", |
| (int)signal_get[path].data_snr_last); |
| PRINTM(MINFO, "SNR Data Average : %d\n", |
| (int)signal_get[path].data_snr_avg); |
| PRINTM(MINFO, "NF Beacon Last : %d\n", |
| (int)signal_get[path].bcn_nf_last); |
| PRINTM(MINFO, "NF Beacon Average : %d\n", |
| (int)signal_get[path].bcn_nf_avg); |
| PRINTM(MINFO, "NF Data Last : %d\n", |
| (int)signal_get[path].data_nf_last); |
| PRINTM(MINFO, "NF Data Average : %d\n", |
| (int)signal_get[path].data_nf_avg); |
| out_data[data_len++] = (int)signal_get[path].selector; |
| out_data[data_len++] = (int)signal_get[path].bcn_rssi_last; |
| out_data[data_len++] = (int)signal_get[path].bcn_rssi_avg; |
| out_data[data_len++] = (int)signal_get[path].data_rssi_last; |
| out_data[data_len++] = (int)signal_get[path].data_rssi_avg; |
| out_data[data_len++] = (int)signal_get[path].bcn_snr_last; |
| out_data[data_len++] = (int)signal_get[path].bcn_snr_avg; |
| out_data[data_len++] = (int)signal_get[path].data_snr_last; |
| out_data[data_len++] = (int)signal_get[path].data_snr_avg; |
| out_data[data_len++] = (int)signal_get[path].bcn_nf_last; |
| out_data[data_len++] = (int)signal_get[path].bcn_nf_avg; |
| out_data[data_len++] = (int)signal_get[path].data_nf_last; |
| out_data[data_len++] = (int)signal_get[path].data_nf_avg; |
| } |
| moal_memcpy_ext(priv->phandle, respbuf, out_data, |
| (MIN((PATH_SIZE * MAX_PATH_NUM), data_len) * |
| sizeof(int)), respbuflen); |
| ret = data_len * sizeof(int); |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set signalext cfg |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return The result of this processing. |
| */ |
| static int |
| woal_priv_signalext_cfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int enable = 0; |
| int ret = 0; |
| int user_data_len = 0, header_len = 0; |
| ENTER(); |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SIGNALEXT_CFG); |
| if ((int)strlen(respbuf) == header_len) { |
| PRINTM(MERROR, "Invalid arguments!\n"); |
| ret = -EINVAL; |
| goto done; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &enable, 1, |
| &user_data_len); |
| if (user_data_len == 1) { |
| if (enable != 0x0 && enable != 0x1) { |
| PRINTM(MERROR, "Invalid arguments!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| ret = woal_signal_ext_enable(priv, enable); |
| } else { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| done: |
| LEAVE(); |
| return ret; |
| } |
| #endif /* #ifdef STA_SUPPORT */ |
| |
| #if defined(STA_SUPPORT) |
| /** |
| * @brief Make PMF bit required/optional |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return 0 -- success, otherwise fail |
| */ |
| static int |
| woal_priv_set_get_pmfcfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int data[2] = { 0, 0 }; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *cfg = NULL; |
| mlan_ds_misc_pmfcfg *pmfcfg; |
| int ret = 0; |
| int user_data_len = 0, header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (!priv->phandle->card_info->embedded_supp) { |
| PRINTM(MERROR, "Not supported cmd on this card\n"); |
| ret = -EOPNOTSUPP; |
| goto done; |
| } |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PMFCFG); |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| } |
| |
| if (user_data_len > 2) { |
| PRINTM(MERROR, "Invalid number of arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| cfg = (mlan_ds_misc_cfg *)req->pbuf; |
| pmfcfg = (mlan_ds_misc_pmfcfg *)&cfg->param.pmfcfg; |
| cfg->sub_command = MLAN_OID_MISC_PMFCFG; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| |
| if (user_data_len == 0) |
| req->action = MLAN_ACT_GET; |
| else { |
| pmfcfg->mfpc = (t_u8)data[0]; |
| pmfcfg->mfpr = (t_u8)data[1]; |
| req->action = MLAN_ACT_SET; |
| } |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&cfg->param.pmfcfg, |
| sizeof(mlan_ds_misc_pmfcfg), respbuflen); |
| ret = sizeof(mlan_ds_misc_pmfcfg); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| |
| /** |
| * @brief Get/Set inactivity timeout extend |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_inactivity_timeout_ext(moal_private *priv, t_u8 *respbuf, |
| t_u32 respbuflen) |
| { |
| int data[4]; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_pm_cfg *pmcfg = NULL; |
| pmlan_ds_inactivity_to inac_to = NULL; |
| int ret = 0; |
| int user_data_len = 0, header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_INACTIVITYTO); |
| memset(data, 0, sizeof(data)); |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| } |
| |
| if (user_data_len != 0 && user_data_len != 3 && user_data_len != 4) { |
| PRINTM(MERROR, "Invalid number of parameters\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| pmcfg = (mlan_ds_pm_cfg *)req->pbuf; |
| inac_to = &pmcfg->param.inactivity_to; |
| pmcfg->sub_command = MLAN_OID_PM_CFG_INACTIVITY_TO; |
| req->req_id = MLAN_IOCTL_PM_CFG; |
| req->action = MLAN_ACT_GET; |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| if (user_data_len) { |
| inac_to->timeout_unit = data[0]; |
| inac_to->unicast_timeout = data[1]; |
| inac_to->mcast_timeout = data[2]; |
| if (user_data_len == 4) |
| inac_to->ps_entry_timeout = data[3]; |
| req->action = MLAN_ACT_SET; |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| } else { |
| data[0] = inac_to->timeout_unit; |
| data[1] = inac_to->unicast_timeout; |
| data[2] = inac_to->mcast_timeout; |
| data[3] = inac_to->ps_entry_timeout; |
| |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, |
| sizeof(data), respbuflen); |
| ret = sizeof(data); |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Enable/Disable amsdu_aggr_ctrl |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_11n_amsdu_aggr_ctrl(moal_private *priv, t_u8 *respbuf, |
| t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_11n_cfg *cfg_11n = NULL; |
| int ret = 0, data[2] = { 0 }; |
| int user_data_len = 0, header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_AMSDU_AGGR_CTRL); |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| cfg_11n = (mlan_ds_11n_cfg *)req->pbuf; |
| cfg_11n->sub_command = MLAN_OID_11N_CFG_AMSDU_AGGR_CTRL; |
| req->req_id = MLAN_IOCTL_11N_CFG; |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| req->action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, data, 1, &user_data_len); |
| |
| if (user_data_len != 1) { |
| PRINTM(MERROR, "Invalid number of parameters\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| req->action = MLAN_ACT_SET; |
| cfg_11n->param.amsdu_aggr_ctrl.enable = data[0]; |
| } |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| data[0] = cfg_11n->param.amsdu_aggr_ctrl.enable; |
| data[1] = cfg_11n->param.amsdu_aggr_ctrl.curr_buf_size; |
| |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data), |
| respbuflen); |
| ret = sizeof(data); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get Transmit beamforming capabilities |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_tx_bf_cap_ioctl(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_11n_cfg *bf_cfg = NULL; |
| int ret = 0, bf_cap = 0; |
| int user_data_len = 0, header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TX_BF_CAP); |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| bf_cfg = (mlan_ds_11n_cfg *)req->pbuf; |
| bf_cfg->sub_command = MLAN_OID_11N_CFG_TX_BF_CAP; |
| req->req_id = MLAN_IOCTL_11N_CFG; |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| req->action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &bf_cap, 1, |
| &user_data_len); |
| |
| if (user_data_len != 1) { |
| PRINTM(MERROR, "Invalid number of parameters\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| req->action = MLAN_ACT_SET; |
| bf_cfg->param.tx_bf_cap = bf_cap; |
| } |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| bf_cap = bf_cfg->param.tx_bf_cap; |
| |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&bf_cap, sizeof(bf_cap), |
| respbuflen); |
| ret = sizeof(bf_cap); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| #ifdef SDIO |
| /** |
| * @brief Turn on/off the sdio clock |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_sdio_clock_ioctl(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| int data = 2; |
| int user_data_len = 0, header_len = 0; |
| /* Initialize the clock state as on */ |
| static int clock_state = 1; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SDIO_CLOCK); |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&clock_state, |
| sizeof(clock_state), respbuflen); |
| ret = sizeof(clock_state); |
| goto done; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &data, 1, &user_data_len); |
| |
| if (user_data_len != 1) { |
| PRINTM(MERROR, "Invalid number of parameters\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| switch (data) { |
| case CMD_DISABLED: |
| PRINTM(MINFO, "SDIO clock is turned off\n"); |
| ret = woal_sdio_set_bus_clock(priv->phandle, MFALSE); |
| clock_state = data; |
| break; |
| case CMD_ENABLED: |
| PRINTM(MINFO, "SDIO clock is turned on\n"); |
| ret = woal_sdio_set_bus_clock(priv->phandle, MTRUE); |
| clock_state = data; |
| break; |
| default: |
| ret = -EINVAL; |
| PRINTM(MINFO, "sdioclock: wrong parameter\n"); |
| break; |
| } |
| done: |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| |
| #ifdef SDIO |
| /** |
| * @brief Set SDIO Multi-point aggregation control parameters |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_sdio_mpa_ctrl(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| int ret = 0, data[6]; |
| int user_data_len = 0, header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| memset(data, 0, sizeof(data)); |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MPA_CTRL); |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| |
| if (user_data_len > 6) { |
| PRINTM(MERROR, "Invalid number of parameters\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; |
| misc->sub_command = MLAN_OID_MISC_SDIO_MPA_CTRL; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| req->action = MLAN_ACT_GET; |
| /* Get the values first, then modify these values if |
| * user had modified them */ |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| PRINTM(MERROR, "woal_request_ioctl returned %d\n", ret); |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| if (user_data_len == 0) { |
| data[0] = misc->param.mpa_ctrl.tx_enable; |
| data[1] = misc->param.mpa_ctrl.rx_enable; |
| data[2] = misc->param.mpa_ctrl.tx_buf_size; |
| data[3] = misc->param.mpa_ctrl.rx_buf_size; |
| data[4] = misc->param.mpa_ctrl.tx_max_ports; |
| data[5] = misc->param.mpa_ctrl.rx_max_ports; |
| |
| PRINTM(MINFO, "Get Param: %d %d %d %d %d %d\n", data[0], |
| data[1], data[2], data[3], data[4], data[5]); |
| |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, |
| sizeof(data), respbuflen); |
| ret = sizeof(data); |
| goto done; |
| } |
| |
| switch (user_data_len) { |
| case 6: |
| misc->param.mpa_ctrl.rx_max_ports = data[5]; |
| /* fall through */ |
| case 5: |
| misc->param.mpa_ctrl.tx_max_ports = data[4]; |
| /* fall through */ |
| case 4: |
| misc->param.mpa_ctrl.rx_buf_size = data[3]; |
| /* fall through */ |
| case 3: |
| misc->param.mpa_ctrl.tx_buf_size = data[2]; |
| /* fall through */ |
| case 2: |
| misc->param.mpa_ctrl.rx_enable = data[1]; |
| /* fall through */ |
| case 1: |
| /* Set cmd */ |
| req->action = MLAN_ACT_SET; |
| |
| PRINTM(MINFO, "Set Param: %d %d %d %d %d %d\n", data[0], |
| data[1], data[2], data[3], data[4], data[5]); |
| |
| misc->param.mpa_ctrl.tx_enable = data[0]; |
| break; |
| default: |
| PRINTM(MERROR, "Default case error\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| 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; |
| } |
| #endif |
| |
| /** |
| * @brief Configure sleep parameters |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_sleep_params_ioctl(moal_private *priv, t_u8 *respbuf, |
| t_u32 respbuflen) |
| { |
| int ret = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_pm_cfg *pm = NULL; |
| mlan_ds_sleep_params *psleep_params = NULL; |
| int data[6] = { 0 }, i; |
| int user_data_len = 0, header_len = 0; |
| #ifdef DEBUG_LEVEL1 |
| char err_str[][36] = { {"sleep clock error in ppm"}, |
| {"wakeup offset in usec"}, |
| {"clock stabilization time in usec"}, |
| {"control periodic calibration(0-2)"}, |
| {"control of external sleepClock(0-2)"}, |
| {"value of reserved for debug"} |
| }; |
| #endif |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| memset(data, 0, sizeof(data)); |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| pm = (mlan_ds_pm_cfg *)req->pbuf; |
| pm->sub_command = MLAN_OID_PM_CFG_SLEEP_PARAMS; |
| req->req_id = MLAN_IOCTL_PM_CFG; |
| psleep_params = (pmlan_ds_sleep_params)&pm->param.sleep_params; |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SLEEP_PARAMS); |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| req->action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| if (user_data_len != 6) { |
| PRINTM(MERROR, "Invalid number of parameters\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| #define MIN_VAL 0x0000 |
| #define MAX_VAL 0xFFFF |
| for (i = 0; i < 6; i++) { |
| if ((i == 3) || (i == 4)) { |
| /* These two cases are handled below the loop */ |
| continue; |
| } |
| if (data[i] < MIN_VAL || data[i] > MAX_VAL) { |
| PRINTM(MERROR, "Invalid %s (0-65535)!\n", |
| err_str[i]); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| if (data[3] < 0 || data[3] > 2) { |
| PRINTM(MERROR, |
| "Invalid control periodic calibration (0-2)!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (data[4] < 0 || data[4] > 2) { |
| PRINTM(MERROR, |
| "Invalid control of external sleep clock (0-2)!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| req->action = MLAN_ACT_SET; |
| psleep_params->error = data[0]; |
| psleep_params->offset = data[1]; |
| psleep_params->stable_time = data[2]; |
| psleep_params->cal_control = data[3]; |
| psleep_params->ext_sleep_clk = data[4]; |
| psleep_params->reserved = data[5]; |
| } |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| data[0] = psleep_params->error; |
| data[1] = psleep_params->offset; |
| data[2] = psleep_params->stable_time; |
| data[3] = psleep_params->cal_control; |
| data[4] = psleep_params->ext_sleep_clk; |
| data[5] = psleep_params->reserved; |
| |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data), |
| respbuflen); |
| ret = sizeof(data); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get DFS Testing settings |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_dfs_testing(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_11h_cfg *ds_11hcfg = NULL; |
| int ret = 0; |
| int data[5] = { 0 }; |
| int user_data_len = 0, header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DFS_TESTING); |
| /* Allocate an IOCTL request buffer */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| /* Fill request buffer */ |
| ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf; |
| ds_11hcfg->sub_command = MLAN_OID_11H_DFS_TESTING; |
| req->req_id = MLAN_IOCTL_11H_CFG; |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| req->action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| if (user_data_len != 5) { |
| PRINTM(MERROR, "Invalid number of args!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if ((unsigned)data[0] > 1800) { |
| PRINTM(MERROR, |
| "The maximum user CAC is 1800 seconds (30 mins).\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if ((unsigned)data[1] > 0xFFFF) { |
| PRINTM(MERROR, "The maximum user NOP is 65535 sec.\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if ((unsigned)data[3] > 0xFF) { |
| PRINTM(MERROR, |
| "The maximum user fixed channel is 255.\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if ((unsigned)data[4] != 0 && ((unsigned)data[4] != 1)) { |
| PRINTM(MERROR, "CAC restart should be 0/1\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| ds_11hcfg->param.dfs_testing.usr_cac_period_msec = |
| (t_u32)data[0] * 1000; |
| ds_11hcfg->param.dfs_testing.usr_nop_period_sec = |
| (t_u16)data[1]; |
| ds_11hcfg->param.dfs_testing.usr_no_chan_change = |
| data[2] ? 1 : 0; |
| ds_11hcfg->param.dfs_testing.usr_fixed_new_chan = (t_u8)data[3]; |
| ds_11hcfg->param.dfs_testing.usr_cac_restart = (t_u8)data[4]; |
| priv->phandle->cac_restart = (t_u8)data[4]; |
| priv->phandle->cac_period_jiffies = (t_u32)data[0] * HZ; |
| priv->phandle->usr_nop_period_sec = (t_u16)data[1]; |
| req->action = MLAN_ACT_SET; |
| #ifdef UAP_SUPPORT |
| priv->user_cac_period_msec = |
| ds_11hcfg->param.dfs_testing.usr_cac_period_msec; |
| #endif |
| } |
| |
| /* Send IOCTL request to MLAN */ |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| if (!user_data_len) { |
| data[0] = |
| ds_11hcfg->param.dfs_testing.usr_cac_period_msec / 1000; |
| data[1] = ds_11hcfg->param.dfs_testing.usr_nop_period_sec; |
| data[2] = ds_11hcfg->param.dfs_testing.usr_no_chan_change; |
| data[3] = ds_11hcfg->param.dfs_testing.usr_fixed_new_chan; |
| data[4] = ds_11hcfg->param.dfs_testing.usr_cac_restart; |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, |
| sizeof(data), respbuflen); |
| ret = sizeof(data); |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get DFS W53 settings |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_dfs53cfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_11h_cfg *ds_11hcfg = NULL; |
| int ret = 0; |
| int data = 0; |
| int user_data_len = 0, header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DFS53_CFG); |
| /* Allocate an IOCTL request buffer */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| /* Fill request buffer */ |
| ds_11hcfg = (mlan_ds_11h_cfg *)req->pbuf; |
| ds_11hcfg->sub_command = MLAN_OID_11H_DFS_W53_CFG; |
| req->req_id = MLAN_IOCTL_11H_CFG; |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| req->action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &data, |
| sizeof(data) / sizeof(int), &user_data_len); |
| if (user_data_len != 1) { |
| PRINTM(MERROR, "Invalid number of args !\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (data > DFS_W53_OLD) { |
| PRINTM(MERROR, "Invalid config !\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| ds_11hcfg->param.dfs_w53_cfg.dfs53cfg = (t_u8)data; |
| 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; |
| } |
| |
| if (!user_data_len) { |
| moal_memcpy_ext(priv->phandle, respbuf, |
| (t_u8 *)&ds_11hcfg->param.dfs_w53_cfg.dfs53cfg, |
| sizeof(ds_11hcfg->param.dfs_w53_cfg.dfs53cfg), |
| respbuflen); |
| ret = sizeof(t_u8); |
| } |
| |
| PRINTM(MIOCTL, "dfs w53 cfg %d\n", |
| ds_11hcfg->param.dfs_w53_cfg.dfs53cfg); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief determine the center frquency center index for bandwidth |
| * of 80 MHz and 160 MHz |
| * |
| ** @param priv Pointer to moal_private structure |
| * @param band band |
| * @param pri_chan primary channel |
| * @param chan_bw channel bandwidth |
| * |
| * @return channel center frequency center, if found; O, otherwise |
| */ |
| |
| static t_u8 |
| woal_get_center_freq_idx(moal_private *priv, t_u8 band, |
| t_u32 pri_chan, t_u8 chan_bw) |
| { |
| t_u8 center_freq_idx = 0; |
| |
| if (band & BAND_AAC) { |
| switch (pri_chan) { |
| case 36: |
| case 40: |
| if (chan_bw == CHANNEL_BW_40MHZ_ABOVE || |
| chan_bw == CHANNEL_BW_40MHZ_BELOW) { |
| center_freq_idx = 38; |
| break; |
| } |
| /* fall through */ |
| case 44: |
| case 48: |
| if (chan_bw == CHANNEL_BW_40MHZ_ABOVE || |
| chan_bw == CHANNEL_BW_40MHZ_BELOW) { |
| center_freq_idx = 46; |
| break; |
| } else if (chan_bw == CHANNEL_BW_80MHZ) { |
| center_freq_idx = 42; |
| break; |
| } |
| /* fall through */ |
| case 52: |
| case 56: |
| if (chan_bw == CHANNEL_BW_40MHZ_ABOVE || |
| chan_bw == CHANNEL_BW_40MHZ_BELOW) { |
| center_freq_idx = 54; |
| break; |
| } |
| /* fall through */ |
| case 60: |
| case 64: |
| if (chan_bw == CHANNEL_BW_40MHZ_ABOVE || |
| chan_bw == CHANNEL_BW_40MHZ_BELOW) { |
| center_freq_idx = 62; |
| break; |
| } else if (chan_bw == CHANNEL_BW_80MHZ) { |
| center_freq_idx = 58; |
| break; |
| } else if (chan_bw == CHANNEL_BW_160MHZ) { |
| center_freq_idx = 50; |
| break; |
| } |
| /* fall through */ |
| case 68: |
| case 72: |
| if (chan_bw == CHANNEL_BW_40MHZ_ABOVE || |
| chan_bw == CHANNEL_BW_40MHZ_BELOW) { |
| center_freq_idx = 70; |
| break; |
| } |
| /* fall through */ |
| case 76: |
| case 80: |
| if (chan_bw == CHANNEL_BW_40MHZ_ABOVE || |
| chan_bw == CHANNEL_BW_40MHZ_BELOW) { |
| center_freq_idx = 78; |
| break; |
| } else if (chan_bw == CHANNEL_BW_80MHZ) { |
| center_freq_idx = 74; |
| break; |
| } |
| /* fall through */ |
| case 84: |
| case 88: |
| if (chan_bw == CHANNEL_BW_40MHZ_ABOVE || |
| chan_bw == CHANNEL_BW_40MHZ_BELOW) { |
| center_freq_idx = 86; |
| break; |
| } |
| /* fall through */ |
| case 92: |
| case 96: |
| if (chan_bw == CHANNEL_BW_40MHZ_ABOVE || |
| chan_bw == CHANNEL_BW_40MHZ_BELOW) { |
| center_freq_idx = 94; |
| break; |
| } else if (chan_bw == CHANNEL_BW_80MHZ) { |
| center_freq_idx = 90; |
| break; |
| } |
| /* fall through */ |
| case 100: |
| case 104: |
| if (chan_bw == CHANNEL_BW_40MHZ_ABOVE || |
| chan_bw == CHANNEL_BW_40MHZ_BELOW) { |
| center_freq_idx = 102; |
| break; |
| } |
| /* fall through */ |
| case 108: |
| case 112: |
| if (chan_bw == CHANNEL_BW_40MHZ_ABOVE || |
| chan_bw == CHANNEL_BW_40MHZ_BELOW) { |
| center_freq_idx = 110; |
| break; |
| } else if (chan_bw == CHANNEL_BW_80MHZ) { |
| center_freq_idx = 106; |
| break; |
| } |
| /* fall through */ |
| case 116: |
| case 120: |
| if (chan_bw == CHANNEL_BW_40MHZ_ABOVE || |
| chan_bw == CHANNEL_BW_40MHZ_BELOW) { |
| center_freq_idx = 118; |
| break; |
| } |
| /* fall through */ |
| case 124: |
| case 128: |
| if (chan_bw == CHANNEL_BW_40MHZ_ABOVE || |
| chan_bw == CHANNEL_BW_40MHZ_BELOW) { |
| center_freq_idx = 126; |
| } else if (chan_bw == CHANNEL_BW_80MHZ) { |
| center_freq_idx = 122; |
| } else if (chan_bw == CHANNEL_BW_160MHZ) { |
| center_freq_idx = 114; |
| } |
| break; |
| case 132: |
| case 136: |
| if (chan_bw == CHANNEL_BW_40MHZ_ABOVE || |
| chan_bw == CHANNEL_BW_40MHZ_BELOW) { |
| center_freq_idx = 134; |
| break; |
| } |
| /* fall through */ |
| case 140: |
| case 144: |
| if (chan_bw == CHANNEL_BW_40MHZ_ABOVE || |
| chan_bw == CHANNEL_BW_40MHZ_BELOW) { |
| center_freq_idx = 126; |
| } else if (chan_bw == CHANNEL_BW_80MHZ) { |
| center_freq_idx = 138; |
| } |
| break; |
| case 149: |
| case 153: |
| if (chan_bw == CHANNEL_BW_40MHZ_ABOVE || |
| chan_bw == CHANNEL_BW_40MHZ_BELOW) { |
| center_freq_idx = 151; |
| break; |
| } |
| /* fall through */ |
| case 157: |
| case 161: |
| if (chan_bw == CHANNEL_BW_40MHZ_ABOVE || |
| chan_bw == CHANNEL_BW_40MHZ_BELOW) { |
| center_freq_idx = 159; |
| break; |
| } else if (chan_bw == CHANNEL_BW_80MHZ) { |
| center_freq_idx = 155; |
| break; |
| } |
| /* fall through */ |
| case 165: |
| case 169: |
| if (chan_bw == CHANNEL_BW_40MHZ_ABOVE || |
| chan_bw == CHANNEL_BW_40MHZ_BELOW) { |
| center_freq_idx = 167; |
| break; |
| } |
| /* fall through */ |
| case 173: |
| case 177: |
| if (chan_bw == CHANNEL_BW_40MHZ_ABOVE || |
| chan_bw == CHANNEL_BW_40MHZ_BELOW) { |
| center_freq_idx = 175; |
| break; |
| } else if (chan_bw == CHANNEL_BW_80MHZ) { |
| center_freq_idx = 171; |
| break; |
| } |
| /* fall through */ |
| case 184: |
| case 188: |
| if (chan_bw == CHANNEL_BW_40MHZ_ABOVE || |
| chan_bw == CHANNEL_BW_40MHZ_BELOW) { |
| center_freq_idx = 186; |
| break; |
| } |
| /* fall through */ |
| case 192: |
| case 196: |
| if (chan_bw == CHANNEL_BW_40MHZ_ABOVE || |
| chan_bw == CHANNEL_BW_40MHZ_BELOW) { |
| center_freq_idx = 194; |
| break; |
| } else if (chan_bw == CHANNEL_BW_80MHZ) { |
| center_freq_idx = 190; |
| break; |
| } |
| /* fall through */ |
| default: /* error. go to the default */ |
| center_freq_idx = 42; |
| } |
| } |
| return center_freq_idx; |
| } |
| |
| #if defined(UAP_SUPPORT) |
| /** |
| * @brief This function handles channel switch with CSA/ECSA IE. |
| * |
| ** @param priv Pointer to moal_private structure |
| * @param block_tx 0-no need block traffic 1- need block traffic |
| * @param oper_class oper_class |
| * @param channel channel |
| * @param switch count how many csa/ecsa beacon will send out |
| * @param band_width 1-40Mhz above, 3-40Mhz below, 4-80Mhz, 5-160Mhz |
| * @param ecsa MTRUE/MFALSE; |
| * |
| * @return channel center frequency center, if found; O, otherwise |
| */ |
| static int |
| woal_channel_switch(moal_private *priv, t_u8 block_tx, t_u8 oper_class, |
| t_u8 channel, t_u8 switch_count, t_u8 band_width, t_u8 ecsa) |
| { |
| IEEEtypes_ExtChanSwitchAnn_t *ext_chan_switch = NULL; |
| IEEEtypes_ChanSwitchAnn_t *chan_switch = NULL; |
| custom_ie *pcust_chansw_ie = NULL; |
| t_u8 center_freq_idx = 0; |
| IEEEtypes_Header_t *pChanSwWrap_ie = NULL; |
| IEEEtypes_WideBWChanSwitch_t *pbwchansw_ie = NULL; |
| IEEEtypes_VhtTpcEnvelope_t *pvhttpcEnv_ie = NULL; |
| mlan_ioctl_req *ioctl_req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| t_u8 bw; |
| t_u8 new_oper_class = oper_class; |
| int ret = 0; |
| |
| 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_CUSTOM_IE; |
| ioctl_req->req_id = MLAN_IOCTL_MISC_CFG; |
| ioctl_req->action = MLAN_ACT_SET; |
| misc->param.cust_ie.type = TLV_TYPE_MGMT_IE; |
| misc->param.cust_ie.len = (sizeof(custom_ie) - MAX_IE_SIZE); |
| |
| pcust_chansw_ie = (custom_ie *)&misc->param.cust_ie.ie_data_list[0]; |
| pcust_chansw_ie->ie_index = 0xffff; /*Auto index */ |
| pcust_chansw_ie->ie_length = sizeof(IEEEtypes_ChanSwitchAnn_t); |
| pcust_chansw_ie->mgmt_subtype_mask = MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP; /*Add IE for |
| BEACON/probe resp */ |
| chan_switch = (IEEEtypes_ChanSwitchAnn_t *)pcust_chansw_ie->ie_buffer; |
| chan_switch->element_id = CHANNEL_SWITCH_ANN; |
| chan_switch->len = 3; |
| chan_switch->chan_switch_mode = block_tx; |
| chan_switch->new_channel_num = channel; |
| chan_switch->chan_switch_count = switch_count; |
| DBG_HEXDUMP(MCMD_D, "CSA IE", (t_u8 *)pcust_chansw_ie->ie_buffer, |
| pcust_chansw_ie->ie_length); |
| switch (band_width) { |
| case CHANNEL_BW_40MHZ_ABOVE: |
| case CHANNEL_BW_40MHZ_BELOW: |
| bw = 40; |
| break; |
| case CHANNEL_BW_80MHZ: |
| bw = 80; |
| break; |
| case CHANNEL_BW_160MHZ: |
| bw = 160; |
| break; |
| default: |
| bw = 20; |
| break; |
| } |
| if (!new_oper_class && ecsa) |
| woal_priv_get_nonglobal_operclass_by_bw_channel(priv, bw, |
| channel, |
| &new_oper_class); |
| if (new_oper_class) { |
| pcust_chansw_ie->ie_length += |
| sizeof(IEEEtypes_ExtChanSwitchAnn_t); |
| ext_chan_switch = |
| (IEEEtypes_ExtChanSwitchAnn_t *) (pcust_chansw_ie-> |
| ie_buffer + |
| sizeof |
| (IEEEtypes_ChanSwitchAnn_t)); |
| ext_chan_switch->element_id = EXTEND_CHANNEL_SWITCH_ANN; |
| ext_chan_switch->len = 4; |
| ext_chan_switch->chan_switch_mode = block_tx; |
| ext_chan_switch->new_oper_class = new_oper_class; |
| ext_chan_switch->new_channel_num = channel; |
| ext_chan_switch->chan_switch_count = switch_count; |
| DBG_HEXDUMP(MCMD_D, "ECSA IE", |
| (t_u8 *)(pcust_chansw_ie->ie_buffer + |
| sizeof(IEEEtypes_ChanSwitchAnn_t)), |
| pcust_chansw_ie->ie_length - |
| sizeof(IEEEtypes_ChanSwitchAnn_t)); |
| } |
| /* bandwidth 40/80/160 should set channel switch wrapper ie for 11ac 5G |
| * channel*/ |
| if (band_width && channel > 14) { |
| pChanSwWrap_ie = |
| (IEEEtypes_Header_t *)(pcust_chansw_ie->ie_buffer + |
| pcust_chansw_ie->ie_length); |
| pChanSwWrap_ie->element_id = EXT_POWER_CONSTR; |
| pChanSwWrap_ie->len = sizeof(IEEEtypes_WideBWChanSwitch_t); |
| |
| pbwchansw_ie = (IEEEtypes_WideBWChanSwitch_t |
| *)((t_u8 *)pChanSwWrap_ie + |
| sizeof(IEEEtypes_Header_t)); |
| pbwchansw_ie->ieee_hdr.element_id = BW_CHANNEL_SWITCH; |
| pbwchansw_ie->ieee_hdr.len = |
| sizeof(IEEEtypes_WideBWChanSwitch_t) - |
| sizeof(IEEEtypes_Header_t); |
| |
| center_freq_idx = woal_get_center_freq_idx(priv, BAND_AAC, |
| channel, band_width); |
| if (band_width == CHANNEL_BW_40MHZ_ABOVE || |
| band_width == CHANNEL_BW_40MHZ_BELOW) { |
| pbwchansw_ie->new_channel_width = 0; |
| pbwchansw_ie->new_channel_center_freq0 = |
| center_freq_idx; |
| } else if (band_width == CHANNEL_BW_80MHZ) { |
| pbwchansw_ie->new_channel_width = 1; |
| pbwchansw_ie->new_channel_center_freq0 = |
| center_freq_idx - 4; |
| pbwchansw_ie->new_channel_center_freq1 = |
| center_freq_idx + 4; |
| } else if (band_width == CHANNEL_BW_160MHZ) { |
| pbwchansw_ie->new_channel_width = 2; |
| pbwchansw_ie->new_channel_center_freq0 = |
| center_freq_idx - 8; |
| pbwchansw_ie->new_channel_center_freq1 = |
| center_freq_idx + 8; |
| } else |
| PRINTM(MERROR, |
| "Invalid bandwidth.Support value 1/3/4/5 for 40+/40-/80/160MHZ\n"); |
| |
| /*prepare the VHT Transmit Power Envelope IE */ |
| pvhttpcEnv_ie = |
| (IEEEtypes_VhtTpcEnvelope_t |
| *)((t_u8 *)pChanSwWrap_ie + |
| sizeof(IEEEtypes_Header_t) + |
| sizeof(IEEEtypes_WideBWChanSwitch_t)); |
| pvhttpcEnv_ie->ieee_hdr.element_id = VHT_TX_POWER_ENV; |
| pvhttpcEnv_ie->ieee_hdr.len = |
| sizeof(IEEEtypes_VhtTpcEnvelope_t) - |
| sizeof(IEEEtypes_Header_t); |
| /* Local Max TX Power Count= 3, |
| * Local TX Power Unit Inter=EIP(0) */ |
| pvhttpcEnv_ie->tpc_info = 3; |
| pvhttpcEnv_ie->local_max_tp_20mhz = 0xff; |
| pvhttpcEnv_ie->local_max_tp_40mhz = 0xff; |
| pvhttpcEnv_ie->local_max_tp_80mhz = 0xff; |
| pvhttpcEnv_ie->local_max_tp_160mhz_80_80mhz = 0xff; |
| pChanSwWrap_ie->len += sizeof(IEEEtypes_VhtTpcEnvelope_t); |
| pcust_chansw_ie->ie_length += |
| pChanSwWrap_ie->len + sizeof(IEEEtypes_Header_t); |
| DBG_HEXDUMP(MCMD_D, "Channel switch wrapper IE", |
| (t_u8 *)pChanSwWrap_ie, |
| pChanSwWrap_ie->len + sizeof(IEEEtypes_Header_t)); |
| } |
| if (block_tx) { |
| if (netif_carrier_ok(priv->netdev)) |
| netif_carrier_off(priv->netdev); |
| woal_stop_queue(priv->netdev); |
| priv->uap_tx_blocked = MTRUE; |
| } |
| |
| status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| PRINTM(MERROR, "Failed to set ECSA IE\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| priv->phandle->chsw_wait_q_woken = MFALSE; |
| /* wait for channel switch to complete */ |
| wait_event_interruptible_timeout(priv->phandle->chsw_wait_q, |
| priv->phandle->chsw_wait_q_woken, |
| (u32)HZ * (switch_count + |
| 2) * 110 / 1000); |
| |
| pcust_chansw_ie->ie_index = 0xffff; /*Auto index */ |
| pcust_chansw_ie->mgmt_subtype_mask = 0; |
| status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| PRINTM(MERROR, "Failed to clear ECSA IE\n"); |
| } |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(ioctl_req); |
| |
| LEAVE(); |
| return ret; |
| |
| } |
| #endif |
| |
| /** |
| * @brief Set/Get CFP table codes |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_cfp_code(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| int user_data_len = 0, header_len = 0; |
| int data[2] = { 0 }; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *misc_cfg = NULL; |
| mlan_ds_misc_cfp_code *cfp_code = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CFP_CODE); |
| |
| /* Allocate an IOCTL request buffer */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| /* Fill request buffer */ |
| misc_cfg = (mlan_ds_misc_cfg *)req->pbuf; |
| cfp_code = &misc_cfg->param.cfp_code; |
| misc_cfg->sub_command = MLAN_OID_MISC_CFP_CODE; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| req->action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| if (user_data_len > 2) { |
| PRINTM(MERROR, "Invalid number of args!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| cfp_code->cfp_code_bg = data[0]; |
| if (user_data_len == 2) |
| cfp_code->cfp_code_a = data[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; |
| } |
| |
| if (!user_data_len) { |
| data[0] = cfp_code->cfp_code_bg; |
| data[1] = cfp_code->cfp_code_a; |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, |
| sizeof(data), respbuflen); |
| ret = sizeof(data); |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get Tx/Rx antenna |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_set_get_tx_rx_ant(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| int user_data_len = 0, header_len = 0; |
| mlan_ds_radio_cfg *radio = NULL; |
| mlan_ioctl_req *req = NULL; |
| int data[3] = { 0 }; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ANT_CFG); |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| radio = (mlan_ds_radio_cfg *)req->pbuf; |
| radio->sub_command = MLAN_OID_ANT_CFG; |
| req->req_id = MLAN_IOCTL_RADIO_CFG; |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| req->action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| if (user_data_len > 2) { |
| PRINTM(MERROR, "Invalid number of args!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (priv->phandle->feature_control & FEATURE_CTRL_STREAM_2X2) { |
| radio->param.ant_cfg.tx_antenna = data[0]; |
| radio->param.ant_cfg.rx_antenna = data[0]; |
| if (user_data_len == 2) |
| radio->param.ant_cfg.rx_antenna = data[1]; |
| #if defined(STA_CFG80211) || defined(UAP_CFG80211) |
| if (IS_CARD9098(priv->phandle->card_type) || |
| IS_CARD9097(priv->phandle->card_type)) { |
| woal_cfg80211_notify_antcfg(priv, |
| priv->phandle-> |
| wiphy, radio); |
| } |
| #endif |
| } else { |
| radio->param.ant_cfg_1x1.antenna = data[0]; |
| if (user_data_len == 2) |
| radio->param.ant_cfg_1x1.evaluate_time = |
| data[1]; |
| } |
| req->action = MLAN_ACT_SET; |
| } |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| if (!user_data_len) { |
| if (priv->phandle->feature_control & FEATURE_CTRL_STREAM_2X2) { |
| data[0] = radio->param.ant_cfg.tx_antenna; |
| data[1] = radio->param.ant_cfg.rx_antenna; |
| if (data[0] && data[1]) |
| ret = sizeof(int) * 2; |
| else |
| ret = sizeof(int) * 1; |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, |
| sizeof(data), respbuflen); |
| } else { |
| data[0] = (int)radio->param.ant_cfg_1x1.antenna; |
| data[1] = (int)radio->param.ant_cfg_1x1.evaluate_time; |
| data[2] = (int)radio->param.ant_cfg_1x1.current_antenna; |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, |
| sizeof(data), respbuflen); |
| ret = sizeof(data); |
| } |
| } |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /* |
| * @brief Set/Get CWMode |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_set_get_cwmode(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ioctl_req *ioctl_req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| mlan_ds_cw_mode_ctrl *cwmode; |
| int ret = 0; |
| int header_len = 0; |
| |
| ENTER(); |
| |
| if (!priv || !priv->phandle) { |
| PRINTM(MERROR, "priv or handle is null\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_CWMODE_CTRL; |
| ioctl_req->req_id = MLAN_IOCTL_MISC_CFG; |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CWMODE); |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| ioctl_req->action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| ioctl_req->action = MLAN_ACT_SET; |
| |
| cwmode = (mlan_ds_cw_mode_ctrl *) (respbuf + header_len + |
| sizeof(t_u8)); |
| misc->param.cwmode.mode = cwmode->mode; |
| misc->param.cwmode.txPower = cwmode->txPower; |
| misc->param.cwmode.rateInfo = cwmode->rateInfo; |
| misc->param.cwmode.channel = cwmode->channel; |
| misc->param.cwmode.chanInfo = cwmode->chanInfo; |
| misc->param.cwmode.pktLength = cwmode->pktLength; |
| } |
| |
| status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&misc->param.cwmode, |
| sizeof(misc->param.cwmode), respbuflen); |
| ret = sizeof(misc->param.cwmode); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(ioctl_req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get out band independent reset |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_ind_rst_cfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| int user_data_len = 0, header_len = 0; |
| mlan_ds_misc_cfg *misc = NULL; |
| mlan_ioctl_req *req = NULL; |
| int data[2] = { 0 }; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_IND_RST_CFG); |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| misc = (mlan_ds_misc_cfg *)req->pbuf; |
| memset(misc, 0, sizeof(mlan_ds_misc_cfg)); |
| misc->sub_command = MLAN_OID_MISC_IND_RST_CFG; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| req->action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| if (user_data_len > 2) { |
| PRINTM(MERROR, "Invalid number of args!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| if ((user_data_len == 1) || (user_data_len == 2)) { |
| req->action = MLAN_ACT_SET; |
| |
| /* ir_mode */ |
| if (data[0] < 0 || data[0] > 2) { |
| PRINTM(MERROR, "Invalid ir mode parameter!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| misc->param.ind_rst_cfg.ir_mode = data[0]; |
| |
| /* gpio_pin */ |
| if (user_data_len == 2) { |
| if ((data[1] != 0xFF) && (data[1] < 0)) { |
| PRINTM(MERROR, |
| "Invalid gpio pin no!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| misc->param.ind_rst_cfg.gpio_pin = data[1]; |
| } |
| } |
| } |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| data[0] = (int)misc->param.ind_rst_cfg.ir_mode; |
| data[1] = (int)misc->param.ind_rst_cfg.gpio_pin; |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data), |
| respbuflen); |
| ret = sizeof(data); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get/Set system clock |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_sysclock(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int data[65]; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *cfg = NULL; |
| int ret = 0, i = 0; |
| int user_data_len = 0, header_len = 0; |
| int data_length = 0, length_index = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SYSCLOCK); |
| memset(data, 0, sizeof(data)); |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| } |
| |
| if (user_data_len > MLAN_MAX_CLK_NUM) { |
| PRINTM(MERROR, "Invalid number of parameters\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| cfg = (mlan_ds_misc_cfg *)req->pbuf; |
| cfg->sub_command = MLAN_OID_MISC_SYS_CLOCK; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| |
| if (user_data_len) { |
| /* SET operation */ |
| req->action = MLAN_ACT_SET; |
| |
| /* Set configurable clocks */ |
| cfg->param.sys_clock.sys_clk_type = MLAN_CLK_CONFIGURABLE; |
| cfg->param.sys_clock.sys_clk_num = |
| MIN(MLAN_MAX_CLK_NUM, user_data_len); |
| for (i = 0; i < cfg->param.sys_clock.sys_clk_num; i++) |
| cfg->param.sys_clock.sys_clk[i] = (t_u16)data[i]; |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| } else { |
| /* GET operation */ |
| req->action = MLAN_ACT_GET; |
| |
| /* Get configurable clocks */ |
| cfg->param.sys_clock.sys_clk_type = MLAN_CLK_CONFIGURABLE; |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| /* Current system clock */ |
| data[1] = (int)cfg->param.sys_clock.cur_sys_clk; |
| data_length = 1; |
| |
| length_index = |
| MIN(cfg->param.sys_clock.sys_clk_num, MLAN_MAX_CLK_NUM); |
| |
| /* Configurable clocks */ |
| for (i = 1; i <= length_index; i++) |
| data[i + data_length] = |
| (int)cfg->param.sys_clock.sys_clk[i - 1]; |
| |
| data_length += length_index; |
| |
| /* Get supported clocks */ |
| cfg->param.sys_clock.sys_clk_type = MLAN_CLK_SUPPORTED; |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| length_index = |
| MIN(cfg->param.sys_clock.sys_clk_num, MLAN_MAX_CLK_NUM); |
| |
| /* Supported clocks */ |
| for (i = 1; i <= length_index; i++) |
| data[i + data_length] = |
| (int)cfg->param.sys_clock.sys_clk[i - 1]; |
| |
| data_length += length_index; |
| |
| /* Send length as first element */ |
| data[0] = data_length; |
| data_length++; |
| |
| moal_memcpy_ext(priv->phandle, respbuf, data, |
| sizeof(int) * data_length, respbuflen); |
| ret = data_length * sizeof(int); |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Get GTK/PTK |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_get_key(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0, copy_len = 0; |
| int header_len = 0; |
| unsigned int i; |
| t_u8 key_ascii[256]; |
| t_u8 *tmp; |
| mlan_ds_sec_cfg *sec = NULL; |
| mlan_ioctl_req *req = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_GET_KEY); |
| if ((int)strlen(respbuf) != header_len) { |
| PRINTM(MERROR, "Invalid number of parameters\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| memset(key_ascii, 0x00, sizeof(key_ascii)); |
| tmp = key_ascii; |
| |
| if (priv->media_connected == MFALSE) { |
| PRINTM(MERROR, "Can't get key in un-associated state\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| /* Get Unicast Key */ |
| req->req_id = MLAN_IOCTL_SEC_CFG; |
| req->action = MLAN_ACT_GET; |
| sec = (mlan_ds_sec_cfg *)req->pbuf; |
| sec->sub_command = MLAN_OID_SEC_QUERY_KEY; |
| sec->param.encrypt_key.key_index = 0; |
| sec->param.encrypt_key.key_flags = 0; |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| if (sec->param.encrypt_key.key_len) { |
| sprintf((char *)tmp, "\n%s", "PTK: "); |
| tmp += 5; |
| for (i = 0; i < sec->param.encrypt_key.key_len; i++) |
| tmp += sprintf((char *)tmp, "%02x", |
| sec->param.encrypt_key.key_material[i]); |
| } |
| |
| /* Get Multicase Key */ |
| req->req_id = MLAN_IOCTL_SEC_CFG; |
| req->action = MLAN_ACT_GET; |
| sec = (mlan_ds_sec_cfg *)req->pbuf; |
| sec->sub_command = MLAN_OID_SEC_QUERY_KEY; |
| sec->param.encrypt_key.key_index = 0; |
| sec->param.encrypt_key.key_flags = KEY_FLAG_GROUP_KEY; |
| memset(sec->param.encrypt_key.mac_addr, 0x0, MLAN_MAC_ADDR_LENGTH); |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| if (sec->param.encrypt_key.key_len) { |
| sprintf((char *)tmp, "\n%s", "GTK: "); |
| tmp += 5; |
| for (i = 0; i < sec->param.encrypt_key.key_len; i++) |
| tmp += sprintf((char *)tmp, "%02x", |
| sec->param.encrypt_key.key_material[i]); |
| } |
| |
| /* Get IGTK Key */ |
| req->req_id = MLAN_IOCTL_SEC_CFG; |
| req->action = MLAN_ACT_GET; |
| sec = (mlan_ds_sec_cfg *)req->pbuf; |
| sec->sub_command = MLAN_OID_SEC_QUERY_KEY; |
| sec->param.encrypt_key.key_index = 0; |
| sec->param.encrypt_key.key_flags = KEY_FLAG_AES_MCAST_IGTK; |
| memset(sec->param.encrypt_key.mac_addr, 0x0, MLAN_MAC_ADDR_LENGTH); |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| if (sec->param.encrypt_key.key_len) { |
| sprintf((char *)tmp, "\n%s", "IGTK: "); |
| tmp += 6; |
| for (i = 0; i < sec->param.encrypt_key.key_len; i++) |
| tmp += sprintf((char *)tmp, "%02x", |
| sec->param.encrypt_key.key_material[i]); |
| } |
| |
| copy_len = tmp - key_ascii; |
| moal_memcpy_ext(priv->phandle, respbuf, &key_ascii, copy_len, |
| respbuflen); |
| ret = copy_len; |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Associate to a specific indexed entry in the ScanTable |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_associate_ssid_bssid(moal_private *priv, t_u8 *respbuf, |
| t_u32 respbuflen) |
| { |
| int ret = 0, copy_len = 0; |
| int header_len = 0; |
| mlan_ssid_bssid ssid_bssid; |
| #ifdef REASSOCIATION |
| mlan_bss_info bss_info; |
| #endif |
| char buf[64]; |
| t_u8 buflen; |
| t_u8 mac_idx; |
| t_u8 i; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ASSOCIATE); |
| if ((int)strlen(respbuf) == header_len) { |
| PRINTM(MERROR, "Invalid number of parameters\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| copy_len = strlen(respbuf) - header_len; |
| mac_idx = 0; |
| buflen = MIN(copy_len, (int)(sizeof(buf) - 1)); |
| memset(buf, 0, sizeof(buf)); |
| memset(&ssid_bssid, 0, sizeof(ssid_bssid)); |
| |
| if (buflen < (3 * ETH_ALEN) + 2) { |
| PRINTM(MERROR, |
| "Associate: Insufficient length in IOCTL input\n"); |
| |
| /* buffer should be at least 3 characters per BSSID octet "00:" |
| ** plus a space separater and at least 1 char in the SSID |
| */ |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| moal_memcpy_ext(priv->phandle, buf, respbuf + header_len, buflen, |
| sizeof(buf)); |
| |
| /* Skip white space */ |
| for (i = 0; (i < buflen) && (buf[i] == ' '); i++) ; |
| |
| /* Copy/Convert the BSSID */ |
| for (; (i < buflen) && (mac_idx < ETH_ALEN) && (buf[i] != ' '); i++) { |
| if (buf[i] == ':') { |
| mac_idx++; |
| } else { |
| ssid_bssid.bssid[mac_idx] = (t_u8)woal_atox(buf + i); |
| |
| while (((i < buflen) && isxdigit(buf[i + 1]))) |
| /* Skip entire hex value */ |
| i++; |
| } |
| } |
| |
| /* Skip one space between the BSSID and start of the SSID */ |
| i++; |
| |
| /* Copy the SSID */ |
| ssid_bssid.ssid.ssid_len = buflen - i; |
| moal_memcpy_ext(priv->phandle, ssid_bssid.ssid.ssid, buf + i, |
| sizeof(ssid_bssid.ssid.ssid), |
| sizeof(ssid_bssid.ssid.ssid)); |
| |
| PRINTM(MCMND, "iwpriv assoc: AP=[" MACSTR "], ssid(%d)=[%s]\n", |
| MAC2STR(ssid_bssid.bssid), (int)ssid_bssid.ssid.ssid_len, |
| ssid_bssid.ssid.ssid); |
| |
| if (MLAN_STATUS_SUCCESS != |
| woal_bss_start(priv, MOAL_IOCTL_WAIT, &ssid_bssid)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| #ifdef REASSOCIATION |
| memset(&bss_info, 0x00, sizeof(bss_info)); |
| if (MLAN_STATUS_SUCCESS == |
| woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) { |
| moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.ssid, |
| &bss_info.ssid, sizeof(mlan_802_11_ssid), |
| sizeof(mlan_802_11_ssid)); |
| moal_memcpy_ext(priv->phandle, &priv->prev_ssid_bssid.bssid, |
| &bss_info.bssid, MLAN_MAC_ADDR_LENGTH, |
| sizeof(mlan_802_11_mac_addr)); |
| } |
| #endif /* REASSOCIATION */ |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| /* Maximum input output characters in group WOAL_SET_GET_256_CHAR */ |
| #define MAX_IN_OUT_CHAR 256 |
| /** Tx BF Global conf argument index */ |
| #define BF_ENABLE_PARAM 1 |
| #define SOUND_ENABLE_PARAM 2 |
| #define FB_TYPE_PARAM 3 |
| #define SNR_THRESHOLD_PARAM 4 |
| #define SOUND_INTVL_PARAM 5 |
| #define BF_MODE_PARAM 6 |
| #define BF_CFG_ACT_GET 0 |
| #define BF_CFG_ACT_SET 1 |
| |
| /** |
| * @brief Set/Get Transmit beamforming configuration |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_tx_bf_cfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int header_len = 0; |
| int ret = 0, copy_len = 0; |
| int bf_action = 0, interval = 0; |
| int snr = 0, i, tmp_val = 0; |
| t_u8 buf[MAX_IN_OUT_CHAR], char_count = 0; |
| t_u8 *str, *token, *pos; |
| t_u16 action = 0; |
| |
| mlan_ds_11n_tx_bf_cfg bf_cfg; |
| mlan_trigger_sound_args *bf_sound = NULL; |
| mlan_tx_bf_peer_args *tx_bf_peer = NULL; |
| mlan_snr_thr_args *bf_snr = NULL; |
| mlan_bf_periodicity_args *bf_periodicity = NULL; |
| mlan_bf_global_cfg_args *bf_global = NULL; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TX_BF_CFG); |
| if ((int)strlen(respbuf) == header_len) { |
| PRINTM(MERROR, "Invalid number of parameters\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| memset(&bf_cfg, 0, sizeof(bf_cfg)); |
| /* Pointer to corresponding buffer */ |
| bf_sound = bf_cfg.body.bf_sound; |
| tx_bf_peer = bf_cfg.body.tx_bf_peer; |
| bf_snr = bf_cfg.body.bf_snr; |
| bf_periodicity = bf_cfg.body.bf_periodicity; |
| bf_global = &bf_cfg.body.bf_global_cfg; |
| |
| /* Total characters in buffer */ |
| char_count = strlen(respbuf) - header_len; |
| copy_len = char_count; |
| memset(buf, 0, sizeof(buf)); |
| if (char_count) { |
| if (copy_len > (int)sizeof(buf)) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| moal_memcpy_ext(priv->phandle, buf, respbuf + header_len, |
| copy_len, sizeof(buf)); |
| |
| if (char_count > 1 && buf[1] != ';') { |
| PRINTM(MERROR, |
| "No action argument. Separate with ';'\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| /* Replace ';' with NULL in the string to separate args */ |
| for (i = 0; i < char_count; i++) { |
| if (buf[i] == ';') |
| buf[i] = '\0'; |
| } |
| /* The first byte represents the beamforming action */ |
| if (woal_atoi(&bf_action, &buf[0]) != MLAN_STATUS_SUCCESS) { |
| ret = -EINVAL; |
| goto done; |
| } |
| switch (bf_action) { |
| case BF_GLOBAL_CONFIGURATION: |
| if (char_count == 1) { |
| action = MLAN_ACT_GET; |
| bf_cfg.action = BF_CFG_ACT_GET; |
| } else { |
| action = MLAN_ACT_SET; |
| bf_cfg.action = BF_CFG_ACT_SET; |
| /* Eliminate action field */ |
| token = &buf[2]; |
| for (i = 1, str = &buf[2]; token != NULL; i++) { |
| token = strstr(str, " "); |
| pos = str; |
| if (token != NULL) { |
| *token = '\0'; |
| str = token + 1; |
| } |
| woal_atoi(&tmp_val, pos); |
| switch (i) { |
| case BF_ENABLE_PARAM: |
| bf_global->bf_enbl = |
| (t_u8)tmp_val; |
| break; |
| case SOUND_ENABLE_PARAM: |
| bf_global->sounding_enbl = |
| (t_u8)tmp_val; |
| break; |
| case FB_TYPE_PARAM: |
| bf_global->fb_type = |
| (t_u8)tmp_val; |
| break; |
| case SNR_THRESHOLD_PARAM: |
| bf_global->snr_threshold = |
| (t_u8)tmp_val; |
| break; |
| case SOUND_INTVL_PARAM: |
| bf_global->sounding_interval = |
| (t_u16)tmp_val; |
| break; |
| case BF_MODE_PARAM: |
| bf_global->bf_mode = |
| (t_u8)tmp_val; |
| break; |
| default: |
| PRINTM(MERROR, |
| "Invalid Argument\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| } |
| break; |
| case TRIGGER_SOUNDING_FOR_PEER: |
| /* First arg = 2 BfAction |
| * Second arg = 17 MAC "00:50:43:20:BF:64" */ |
| if (char_count != 19) { |
| PRINTM(MERROR, "Invalid argument\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| woal_mac2u8(bf_sound->peer_mac, &buf[2]); |
| action = MLAN_ACT_SET; |
| bf_cfg.action = BF_CFG_ACT_SET; |
| break; |
| case SET_GET_BF_PERIODICITY: |
| /* First arg = 2 BfAction |
| * Second arg = 18 MAC "00:50:43:20:BF:64;" |
| * Third arg = 1 (min char) TX BF interval |
| * 10 (max char) u32 maximum value |
| * 4294967295 */ |
| if (char_count < 19 || char_count > 30) { |
| PRINTM(MERROR, "Invalid argument\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| woal_mac2u8(bf_periodicity->peer_mac, &buf[2]); |
| if (char_count == 19) { |
| action = MLAN_ACT_GET; |
| bf_cfg.action = BF_CFG_ACT_GET; |
| } else { |
| action = MLAN_ACT_SET; |
| bf_cfg.action = BF_CFG_ACT_SET; |
| if (woal_atoi(&interval, &buf[20]) != |
| MLAN_STATUS_SUCCESS) { |
| ret = -EINVAL; |
| goto done; |
| } |
| bf_periodicity->interval = interval; |
| } |
| break; |
| case TX_BF_FOR_PEER_ENBL: |
| /* Handle only SET operation here |
| * First arg = 2 BfAction |
| * Second arg = 18 MAC "00:50:43:20:BF:64;" |
| * Third arg = 2 enable/disable bf |
| * Fourth arg = 2 enable/disable sounding |
| * Fifth arg = 1 FB Type */ |
| if (char_count != 25 && char_count != 1) { |
| PRINTM(MERROR, "Invalid argument\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (char_count == 1) { |
| action = MLAN_ACT_GET; |
| bf_cfg.action = BF_CFG_ACT_GET; |
| } else { |
| woal_mac2u8(tx_bf_peer->peer_mac, &buf[2]); |
| woal_atoi(&tmp_val, &buf[20]); |
| tx_bf_peer->bf_enbl = (t_u8)tmp_val; |
| woal_atoi(&tmp_val, &buf[22]); |
| tx_bf_peer->sounding_enbl = (t_u8)tmp_val; |
| woal_atoi(&tmp_val, &buf[24]); |
| tx_bf_peer->fb_type = (t_u8)tmp_val; |
| action = MLAN_ACT_SET; |
| bf_cfg.action = BF_CFG_ACT_SET; |
| } |
| break; |
| case SET_SNR_THR_PEER: |
| /* First arg = 2 BfAction |
| * Second arg = 18 MAC "00:50:43:20:BF:64;" |
| * Third arg = 1/2 SNR u8 - can be 1/2 charerters */ |
| if (char_count != 1 && |
| !(char_count == 21 || char_count == 22)) { |
| PRINTM(MERROR, "Invalid argument\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (char_count == 1) { |
| action = MLAN_ACT_GET; |
| bf_cfg.action = BF_CFG_ACT_GET; |
| } else { |
| woal_mac2u8(bf_snr->peer_mac, &buf[2]); |
| if (woal_atoi(&snr, &buf[20]) != |
| MLAN_STATUS_SUCCESS) { |
| ret = -EINVAL; |
| goto done; |
| } |
| bf_snr->snr = snr; |
| action = MLAN_ACT_SET; |
| bf_cfg.action = BF_CFG_ACT_SET; |
| } |
| break; |
| default: |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| /* Save the value */ |
| bf_cfg.bf_action = bf_action; |
| if (MLAN_STATUS_SUCCESS != |
| woal_set_get_tx_bf_cfg(priv, action, &bf_cfg)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| } else { |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| switch (bf_action) { |
| case BF_GLOBAL_CONFIGURATION: |
| moal_memcpy_ext(priv->phandle, respbuf, bf_global, |
| sizeof(mlan_bf_global_cfg_args), respbuflen); |
| ret = sizeof(mlan_bf_global_cfg_args); |
| break; |
| case TRIGGER_SOUNDING_FOR_PEER: |
| moal_memcpy_ext(priv->phandle, respbuf, bf_sound, |
| sizeof(mlan_bf_global_cfg_args), respbuflen); |
| ret = sizeof(mlan_bf_global_cfg_args); |
| break; |
| case SET_GET_BF_PERIODICITY: |
| moal_memcpy_ext(priv->phandle, respbuf, bf_periodicity, |
| sizeof(mlan_bf_periodicity_args), respbuflen); |
| ret = sizeof(mlan_bf_periodicity_args); |
| break; |
| case TX_BF_FOR_PEER_ENBL: |
| moal_memcpy_ext(priv->phandle, respbuf, tx_bf_peer, |
| sizeof(mlan_tx_bf_peer_args), respbuflen); |
| ret = sizeof(mlan_tx_bf_peer_args); |
| break; |
| case SET_SNR_THR_PEER: |
| moal_memcpy_ext(priv->phandle, respbuf, bf_snr, |
| sizeof(mlan_snr_thr_args), respbuflen); |
| ret = sizeof(mlan_snr_thr_args); |
| break; |
| default: |
| ret = 0; |
| } |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| #ifdef SDIO |
| /** |
| * @brief Cmd53 read/write register |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_cmd53rdwr(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int header_len = 0; |
| int ret = 0; |
| t_u8 *buf = NULL; |
| t_u8 *data = NULL; |
| t_u8 rw, mode; |
| t_u16 blklen = 0, blknum = 0; |
| int reg = 0; |
| t_u32 pattern_len = 0, total_len = 0; |
| t_u16 cmd_len; |
| gfp_t flag; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_SD_CMD53_RW); |
| |
| flag = (in_atomic() || irqs_disabled())? GFP_ATOMIC : GFP_KERNEL; |
| data = kzalloc(WOAL_2K_BYTES, flag); |
| if (!data) { |
| PRINTM(MERROR, "Cannot allocate buffer for command!\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| moal_memcpy_ext(priv->phandle, &cmd_len, respbuf + header_len, |
| sizeof(cmd_len), sizeof(cmd_len)); |
| buf = respbuf + header_len + sizeof(cmd_len); |
| |
| rw = buf[0]; /* read/write (0/1) */ |
| reg = buf[5]; /* address */ |
| reg = (reg << 8) | buf[4]; |
| reg = (reg << 8) | buf[3]; |
| reg = (reg << 8) | buf[2]; |
| mode = buf[6]; /* byte mode/block mode (0/1) */ |
| blklen = buf[8]; /* block size */ |
| blklen = (blklen << 8) | buf[7]; |
| blknum = buf[10]; /* block number or byte number */ |
| blknum = (blknum << 8) | buf[9]; |
| |
| if (mode == BYTE_MODE) |
| blklen = 1; |
| else |
| mode = BLOCK_MODE; |
| |
| total_len = (mode == BLOCK_MODE) ? blknum * blklen : blknum; |
| if (total_len > WOAL_2K_BYTES) { |
| PRINTM(MERROR, "Total data length is too large!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| PRINTM(MINFO, |
| "CMD53 read/write, addr = %#x, mode = %d, " |
| "block size = %d, block(byte) number = %d\n", |
| reg, mode, blklen, blknum); |
| |
| if (!rw) { |
| sdio_claim_host(((struct sdio_mmc_card *)priv->phandle->card)-> |
| func); |
| if (sdio_readsb |
| (((struct sdio_mmc_card *)priv->phandle->card)->func, |
| respbuf, reg, total_len)) { |
| PRINTM(MERROR, |
| "sdio_readsb: reading memory 0x%x failed\n", |
| reg); |
| goto done; |
| } |
| sdio_release_host(((struct sdio_mmc_card *)priv->phandle-> |
| card)->func); |
| ret = total_len; |
| } else { |
| int pos = 0; |
| pattern_len = cmd_len - 11; |
| if (pattern_len > total_len) |
| pattern_len = total_len; |
| |
| /* Copy/duplicate the pattern to data buffer */ |
| for (pos = 0; pos < (int)total_len; pos++) |
| data[pos] = buf[11 + (pos % pattern_len)]; |
| sdio_claim_host(((struct sdio_mmc_card *)priv->phandle->card)-> |
| func); |
| if (sdio_writesb |
| (((struct sdio_mmc_card *)priv->phandle->card)->func, reg, |
| data, total_len)) |
| PRINTM(MERROR, |
| "sdio_writesb: writing memory 0x%x failed\n", |
| reg); |
| sdio_release_host(((struct sdio_mmc_card *)priv->phandle-> |
| card)->func); |
| } |
| |
| done: |
| kfree(data); |
| LEAVE(); |
| return ret; |
| } |
| #endif /* SDIO */ |
| |
| /** |
| * @brief Set/Get Port Control mode |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_port_ctrl(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int header_len = 0, user_data_len = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_sec_cfg *sec = NULL; |
| int ret = 0, data = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| ENTER(); |
| |
| /* Allocate an IOCTL request buffer */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| /* Fill request buffer */ |
| sec = (mlan_ds_sec_cfg *)req->pbuf; |
| sec->sub_command = MLAN_OID_SEC_CFG_PORT_CTRL_ENABLED; |
| req->req_id = MLAN_IOCTL_SEC_CFG; |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PORT_CTRL); |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| req->action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &data, |
| sizeof(data) / sizeof(int), &user_data_len); |
| if (user_data_len == 1) { |
| sec->param.port_ctrl_enabled = data; |
| req->action = MLAN_ACT_SET; |
| } else { |
| PRINTM(MERROR, "Invalid number of parameters\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| |
| /* Send IOCTL request to MLAN */ |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| if (!user_data_len) { |
| moal_memcpy_ext(priv->phandle, respbuf, |
| &sec->param.port_ctrl_enabled, sizeof(int), |
| respbuflen); |
| ret = sizeof(int); |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Private IOCTL entry to get the By-passed TX packet from |
| * upper layer |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_bypassed_packet(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int header_len = 0; |
| int ret = 0; |
| struct sk_buff *skb = NULL; |
| struct ethhdr *eth; |
| t_u16 moreLen = 0, copyLen = 0; |
| ENTER(); |
| |
| #define MLAN_BYPASS_PKT_EXTRA_OFFSET (4) |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PB_BYPASS); |
| copyLen = strlen(respbuf) - header_len; |
| moreLen = MLAN_MIN_DATA_HEADER_LEN + MLAN_BYPASS_PKT_EXTRA_OFFSET + |
| sizeof(mlan_buffer); |
| |
| skb = alloc_skb(copyLen + moreLen, GFP_KERNEL); |
| if (skb == NULL) { |
| PRINTM(MERROR, "kmalloc no memory !!\n"); |
| LEAVE(); |
| return -ENOMEM; |
| } |
| |
| skb_reserve(skb, moreLen); |
| |
| moal_memcpy_ext(priv->phandle, skb_put(skb, copyLen), |
| respbuf + header_len, copyLen, copyLen); |
| |
| eth = (struct ethhdr *)skb->data; |
| eth->h_proto = __constant_htons(eth->h_proto); |
| skb->dev = priv->netdev; |
| |
| HEXDUMP("Bypass TX Data", skb->data, MIN(skb->len, 100)); |
| |
| woal_hard_start_xmit(skb, priv->netdev); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set Robustcoex gpiocfg |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_robustcoex(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int header_len = 0, user_data_len = 0; |
| int ret = 0, data[3] = { 0 }; |
| mlan_ds_misc_cfg *robust_coex_cfg = NULL; |
| mlan_ioctl_req *req = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| robust_coex_cfg = (mlan_ds_misc_cfg *)req->pbuf; |
| while (respbuf[0] == ' ') { |
| /** skip space */ |
| respbuf++; |
| } |
| |
| if (strncmp(respbuf, "gpiocfg", strlen("gpiocfg")) == 0) { |
| header_len = strlen("gpiocfg") + 1; |
| parse_arguments(respbuf + header_len, data, |
| sizeof(data) / sizeof(int), &user_data_len); |
| if (user_data_len > 3) { |
| PRINTM(MERROR, "Invalid parameter number\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (data[0] != ROBUSTCOEX_GPIOCFG_ENABLE && |
| data[0] != ROBUSTCOEX_GPIOCFG_DISABLE) { |
| PRINTM(MERROR, "Invalid parameter number\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (data[0] == ROBUSTCOEX_GPIOCFG_ENABLE) { |
| if (user_data_len != 3) { |
| PRINTM(MMSG, |
| "Please provide gpio num and gpio polarity for ROBUSTCOEX_GPIOCFG_ENABLE\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| robust_coex_cfg->param.robustcoexparams.method = |
| ROBUSTCOEX_GPIO_CFG; |
| robust_coex_cfg->param.robustcoexparams.enable = |
| ROBUSTCOEX_GPIOCFG_ENABLE; |
| robust_coex_cfg->param.robustcoexparams.gpio_num = |
| data[1]; |
| robust_coex_cfg->param.robustcoexparams.gpio_polarity = |
| data[2]; |
| } else { |
| robust_coex_cfg->param.robustcoexparams.method = |
| ROBUSTCOEX_GPIO_CFG; |
| robust_coex_cfg->param.robustcoexparams.enable = |
| ROBUSTCOEX_GPIOCFG_DISABLE; |
| robust_coex_cfg->param.robustcoexparams.gpio_num = 0; |
| robust_coex_cfg->param.robustcoexparams.gpio_polarity = |
| 0; |
| } |
| req->action = MLAN_ACT_SET; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| robust_coex_cfg->sub_command = MLAN_OID_MISC_ROBUSTCOEX; |
| } else { |
| PRINTM(MERROR, "Invalid parameter\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| 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 DMCS mapping policy or get DMCS status |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_dmcs(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int header_len = 0, user_data_len = 0; |
| int ret = 0, data[2] = { 0 }; |
| mlan_ds_misc_cfg *dmcs_cfg = NULL; |
| mlan_ioctl_req *req = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DMCS); |
| dmcs_cfg = (mlan_ds_misc_cfg *)req->pbuf; |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| if (user_data_len > 2) { |
| PRINTM(MERROR, "Invalid number of args! %d\n", user_data_len); |
| ret = -EINVAL; |
| goto done; |
| } |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| dmcs_cfg->sub_command = MLAN_OID_MISC_DMCS_CONFIG; |
| dmcs_cfg->param.dmcs_policy.subcmd = data[0]; |
| switch (data[0]) { |
| case 0: |
| if (user_data_len != 2) { |
| PRINTM(MERROR, "Please provide mapping policy\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| req->action = MLAN_ACT_SET; |
| dmcs_cfg->param.dmcs_policy.mapping_policy = data[1]; |
| break; |
| case 1: |
| req->action = MLAN_ACT_GET; |
| break; |
| default: |
| break; |
| } |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| if (req->action == MLAN_ACT_GET) { |
| moal_memcpy_ext(priv->phandle, respbuf, |
| &dmcs_cfg->param.dmcs_status, |
| sizeof(mlan_ds_misc_dmcs_status), respbuflen); |
| } |
| ret = sizeof(mlan_ds_misc_dmcs_status); |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set and get boot sleep configure |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_bootsleep(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = MLAN_STATUS_SUCCESS; |
| int user_data_len = 0; |
| int header_len = 0; |
| int allowed = 1; |
| int data[1] = { 0 }; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| |
| ENTER(); |
| |
| if (!priv || !priv->phandle) { |
| PRINTM(MERROR, "priv or handle is null\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| 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_BOOT_SLEEP; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_BOOTSLEEP); |
| |
| if ((int)strlen(respbuf) == header_len) { |
| req->action = MLAN_ACT_GET; |
| } else { |
| req->action = MLAN_ACT_SET; |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| if (user_data_len != allowed) { |
| PRINTM(MERROR, "Invalid number of args! %d\n", |
| user_data_len); |
| ret = -EINVAL; |
| goto done; |
| } |
| misc->param.boot_sleep = data[0] ? 1 : 0; |
| PRINTM(MIOCTL, "boot sleep cfg:%u\n", misc->param.boot_sleep); |
| } |
| |
| ret = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT_TIMEOUT); |
| if (ret != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| moal_memcpy_ext(priv->phandle, respbuf, &misc->param.boot_sleep, |
| sizeof(misc->param.boot_sleep), respbuflen); |
| ret = sizeof(misc->param.boot_sleep); |
| |
| PRINTM(MIOCTL, "boot sleep cfg: %u\n", misc->param.boot_sleep); |
| |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| #if defined(PCIE) |
| /** |
| * @brief Enable SSU support |
| * @param priv Pointer to moal_private structure |
| * @param used_len used length |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_ssu_cmd(moal_private *priv, t_u8 used_len, t_u8 *respbuf, |
| t_u32 respbuflen) |
| { |
| int ret = 0; |
| mlan_ds_misc_cfg *ssu_cfg = NULL; |
| mlan_ioctl_req *req = NULL; |
| ssu_params_cfg *ssu_params; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| ssu_cfg = (mlan_ds_misc_cfg *)req->pbuf; |
| memset(&ssu_cfg->param.ssu_params, 0, sizeof(mlan_ds_ssu_params)); |
| if (!used_len) { |
| req->action = MLAN_ACT_SET; |
| ssu_cfg->param.ssu_params.nskip = 0; |
| ssu_cfg->param.ssu_params.nsel = 1; |
| ssu_cfg->param.ssu_params.adcdownsample = 3; |
| ssu_cfg->param.ssu_params.mask_adc_pkt = 0; |
| ssu_cfg->param.ssu_params.out_16bits = 1; |
| } else { |
| ssu_params = (ssu_params_cfg *) respbuf; |
| DBG_HEXDUMP(MCMD_D, "User SSU params:", respbuf, |
| sizeof(mlan_ds_ssu_params)); |
| if (ssu_params->ssu_mode == 2) |
| req->action = MLAN_ACT_DEFAULT; |
| else { |
| req->action = MLAN_ACT_SET; |
| ssu_cfg->param.ssu_params.nskip = ssu_params->nskip; |
| ssu_cfg->param.ssu_params.nsel = ssu_params->nsel; |
| ssu_cfg->param.ssu_params.adcdownsample = |
| ssu_params->adcdownsample; |
| ssu_cfg->param.ssu_params.mask_adc_pkt = |
| ssu_params->mask_adc_pkt; |
| ssu_cfg->param.ssu_params.out_16bits = |
| ssu_params->out_16bits; |
| ssu_cfg->param.ssu_params.spec_pwr_enable = |
| ssu_params->spec_pwr_enable; |
| ssu_cfg->param.ssu_params.rate_deduction = |
| ssu_params->rate_deduction; |
| ssu_cfg->param.ssu_params.n_pkt_avg = |
| ssu_params->n_pkt_avg; |
| } |
| } |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| ssu_cfg->sub_command = MLAN_OID_MISC_SSU; |
| |
| 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; |
| } |
| #endif |
| |
| /** |
| * @brief Configure the hal/phy cfg params |
| * |
| * The command structure contains the following parameters |
| * dot11b_psd_mask: 1: enable, 0: disable |
| * Reserved : reserved 7 params for future such use |
| * |
| * @param priv Pointer to the mlan_private driver data struct |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written if successful else negative value |
| */ |
| static int |
| woal_priv_hal_phy_cfg_cmd(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *cfg = NULL; |
| int ret = 0; |
| mlan_ds_hal_phy_cfg_params *data_ptr; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| data_ptr = (mlan_ds_hal_phy_cfg_params *) respbuf; |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| cfg = (mlan_ds_misc_cfg *)req->pbuf; |
| cfg->sub_command = MLAN_OID_MISC_HAL_PHY_CFG; |
| |
| cfg->param.hal_phy_cfg_params.dot11b_psd_mask_cfg = |
| data_ptr->dot11b_psd_mask_cfg; |
| |
| 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 configure 11ax HE capability or HE operation |
| * |
| * |
| * @param priv Pointer to the mlan_private driver data struct |
| * @param respbuf A pointer to response buffer |
| * @param len length used |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written if successful else negative value |
| */ |
| static int |
| woal_priv_11axcfg_cmd(moal_private *priv, t_u8 *respbuf, t_u8 len, |
| t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_11ax_cfg *cfg = NULL; |
| int ret = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11ax_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| req->req_id = MLAN_IOCTL_11AX_CFG; |
| req->action = MLAN_ACT_SET; |
| cfg = (mlan_ds_11ax_cfg *) req->pbuf; |
| cfg->sub_command = MLAN_OID_11AX_HE_CFG; |
| if (len) |
| moal_memcpy_ext(priv->phandle, (t_u8 *)&cfg->param.he_cfg, |
| respbuf, len, sizeof(mlan_ds_11ax_he_cfg)); |
| else |
| req->action = MLAN_ACT_GET; |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&cfg->param.he_cfg, |
| sizeof(mlan_ds_11ax_he_cfg), respbuflen); |
| ret = sizeof(mlan_ds_11ax_he_cfg); |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Configure TWT Setup parameters |
| * |
| * @param priv Pointer to the mlan_private driver data struct |
| * @param respbuf A pointer to response buffer |
| * @param len Length used |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written if successful else negative |
| * value |
| */ |
| static int |
| woal_priv_twt_setup(moal_private *priv, t_u8 *respbuf, t_u8 len, |
| t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_twtcfg *cfg = NULL; |
| int ret = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_twtcfg)); |
| if (req == NULL) { |
| PRINTM(MERROR, "Failed to allocate ioctl_req!\n"); |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| req->req_id = MLAN_IOCTL_11AX_CFG; |
| req->action = MLAN_ACT_SET; |
| cfg = (mlan_ds_twtcfg *) req->pbuf; |
| cfg->sub_command = MLAN_OID_11AX_TWT_CFG; |
| cfg->sub_id = MLAN_11AX_TWT_SETUP_SUBID; |
| |
| if (len) { |
| moal_memcpy_ext(priv->phandle, (t_u8 *)&cfg->param.twt_setup, |
| respbuf, len, sizeof(mlan_ds_twt_setup)); |
| } |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| PRINTM(MERROR, "woal_request_ioctl failed!\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| ret = sizeof(mlan_ds_twt_setup); |
| done: |
| if (status != MLAN_STATUS_PENDING) { |
| kfree(req); |
| } |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Configure TWT Tear down parameters |
| * |
| * @param priv Pointer to the mlan_private driver data struct |
| * @param respbuf A pointer to response buffer |
| * @param len Length used |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written if successful else negative |
| * value |
| */ |
| static int |
| woal_priv_twt_teardown(moal_private *priv, t_u8 *respbuf, t_u8 len, |
| t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_twtcfg *cfg = NULL; |
| int ret = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_twtcfg)); |
| if (req == NULL) { |
| PRINTM(MERROR, "Failed to allocate ioctl_req!\n"); |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| req->req_id = MLAN_IOCTL_11AX_CFG; |
| req->action = MLAN_ACT_SET; |
| cfg = (mlan_ds_twtcfg *) req->pbuf; |
| cfg->sub_command = MLAN_OID_11AX_TWT_CFG; |
| cfg->sub_id = MLAN_11AX_TWT_TEARDOWN_SUBID; |
| |
| if (len) { |
| moal_memcpy_ext(priv->phandle, (t_u8 *)&cfg->param.twt_teardown, |
| respbuf, len, sizeof(mlan_ds_twt_teardown)); |
| } |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| PRINTM(MERROR, "woal_request_ioctl failed!\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| ret = sizeof(mlan_ds_twt_teardown); |
| done: |
| if (status != MLAN_STATUS_PENDING) { |
| kfree(req); |
| } |
| LEAVE(); |
| return ret; |
| } |
| |
| #ifdef WIFI_DIRECT_SUPPORT |
| #if defined(UAP_CFG80211) |
| /** |
| * @brief Set/Get P2P NoA (Notice of Absence) parameters |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_cfg_noa(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int header_len = 0, user_data_len = 0; |
| int ret = 0, data[7]; |
| mlan_ds_wifi_direct_config noa_cfg; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CFG_NOA); |
| memset(&noa_cfg, 0, sizeof(noa_cfg)); |
| |
| memset(data, 0, sizeof(data)); |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| |
| if (user_data_len > 5) { |
| PRINTM(MERROR, "invalid parameters\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| noa_cfg.flags |= WIFI_DIRECT_NOA; |
| |
| if (woal_p2p_config(priv, MLAN_ACT_GET, &noa_cfg) != |
| MLAN_STATUS_SUCCESS) { |
| PRINTM(MERROR, "Could not get P2P noa config\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| moal_memcpy_ext(priv->phandle, respbuf, &noa_cfg, |
| sizeof(noa_cfg), respbuflen); |
| ret = sizeof(noa_cfg); |
| } else { |
| switch (user_data_len) { |
| case 5: |
| noa_cfg.noa_interval = (t_u32)data[4]; |
| /* fall through */ |
| case 4: |
| noa_cfg.noa_duration = (t_u32)data[3]; |
| /* fall through */ |
| case 3: |
| if (data[2] < 1 || data[2] > 255) { |
| PRINTM(MERROR, |
| "Invalid number of absence intervals\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| noa_cfg.noa_count = (t_u8)data[2]; |
| /* fall through */ |
| case 2: |
| if (data[1] < 0 || data[1] > 255) { |
| PRINTM(MERROR, "Invalid Index\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| noa_cfg.index = (t_u16)data[1]; |
| /* fall through */ |
| case 1: |
| if (data[0] < 0 || data[0] > 1) { |
| PRINTM(MERROR, "Invalid noa enable\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| noa_cfg.noa_enable = (t_u8)data[0]; |
| noa_cfg.flags |= WIFI_DIRECT_NOA; |
| break; |
| default: |
| break; |
| } |
| woal_p2p_config(priv, MLAN_ACT_SET, &noa_cfg); |
| } |
| |
| done: |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get P2P OPP-PS parameters |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_cfg_opp_ps(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int header_len = 0, user_data_len = 0; |
| int ret = 0, data[7]; |
| mlan_ds_wifi_direct_config opp_ps_cfg; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CFG_OPP_PS); |
| memset(&opp_ps_cfg, 0, sizeof(opp_ps_cfg)); |
| |
| memset(data, 0, sizeof(data)); |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| |
| if (user_data_len > 2) { |
| PRINTM(MERROR, "invalid parameters\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| opp_ps_cfg.flags |= WIFI_DIRECT_OPP_PS; |
| |
| if (woal_p2p_config(priv, MLAN_ACT_GET, &opp_ps_cfg) != |
| MLAN_STATUS_SUCCESS) { |
| PRINTM(MERROR, "Could not get P2P opp ps config\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| moal_memcpy_ext(priv->phandle, respbuf, &opp_ps_cfg, |
| sizeof(opp_ps_cfg), respbuflen); |
| ret = sizeof(opp_ps_cfg); |
| } else { |
| switch (user_data_len) { |
| case 2: |
| opp_ps_cfg.ct_window = (t_u8)data[1]; |
| /* fall through */ |
| case 1: |
| if (data[0] < 0 || data[0] > 1) { |
| PRINTM(MERROR, "Invalid ps enable\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| opp_ps_cfg.opp_ps_enable = (t_u8)data[0]; |
| opp_ps_cfg.flags |= WIFI_DIRECT_OPP_PS; |
| /* fall through */ |
| default: |
| break; |
| } |
| woal_p2p_config(priv, MLAN_ACT_SET, &opp_ps_cfg); |
| } |
| |
| done: |
| |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| #endif |
| |
| /** |
| * @brief Set/Get GPIO TSF latch clock sync config parameters |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_cfg_clock_sync(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int header_len = 0, user_data_len = 0; |
| int ret = 0, data[5]; |
| mlan_ds_gpio_tsf_latch *clock_sync_cfg = NULL; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *misc_cfg = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CFG_CLOCK_SYNC); |
| |
| memset(data, 0, sizeof(data)); |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| |
| if (user_data_len > 5) { |
| PRINTM(MERROR, "invalid parameters\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| /* Allocate an IOCTL request buffer */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| /* Fill request buffer */ |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| misc_cfg = (mlan_ds_misc_cfg *)req->pbuf; |
| misc_cfg->sub_command = MLAN_OID_MISC_GPIO_TSF_LATCH; |
| clock_sync_cfg = &misc_cfg->param.gpio_tsf_latch_config; |
| memset(clock_sync_cfg, 0, sizeof(mlan_ds_gpio_tsf_latch)); |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| req->action = MLAN_ACT_GET; |
| user_data_len = 0; |
| } else { |
| req->action = MLAN_ACT_SET; |
| switch (user_data_len) { |
| case 5: |
| clock_sync_cfg->clock_sync_gpio_pulse_width = |
| (t_u16)data[4]; |
| /* fall through */ |
| case 4: |
| if (data[3] < 0 || data[3] > 1) { |
| PRINTM(MERROR, "Invalid Level/Trigger\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| clock_sync_cfg->clock_sync_gpio_level_toggle = |
| (t_u8)data[3]; |
| /* fall through */ |
| case 3: |
| if (data[2] < 1 || data[2] > 255) { |
| PRINTM(MERROR, |
| "Invalid number of GPIO Pin Number\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| clock_sync_cfg->clock_sync_gpio_pin_number = |
| (t_u8)data[2]; |
| /* fall through */ |
| case 2: |
| if (data[1] < 0 || data[1] > 2) { |
| PRINTM(MERROR, "Invalid Role\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| clock_sync_cfg->clock_sync_Role = (t_u8)data[1]; |
| /* fall through */ |
| case 1: |
| if (data[0] < 0 || data[0] > 2) { |
| PRINTM(MERROR, "Invalid Mode\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| clock_sync_cfg->clock_sync_mode = (t_u8)data[0]; |
| break; |
| default: |
| break; |
| } |
| } |
| /* Send IOCTL request to MLAN */ |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| if (!user_data_len) { |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)clock_sync_cfg, |
| sizeof(mlan_ds_gpio_tsf_latch), respbuflen); |
| ret = sizeof(mlan_ds_gpio_tsf_latch); |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get GPIO TSF latch get tsf info config parameters |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_cfg_get_tsf_info(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int header_len = 0, user_data_len = 0; |
| int ret = 0, data[1]; |
| mlan_ds_tsf_info *tsf_info; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *misc_cfg = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CFG_GET_TSF_INFO); |
| |
| memset(data, 0, sizeof(data)); |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| |
| if (user_data_len > 1) { |
| PRINTM(MERROR, "invalid parameters\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| /* Allocate an IOCTL request buffer */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| /* Fill request buffer */ |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| req->action = MLAN_ACT_GET; |
| misc_cfg = (mlan_ds_misc_cfg *)req->pbuf; |
| misc_cfg->sub_command = MLAN_OID_MISC_GET_TSF_INFO; |
| tsf_info = &misc_cfg->param.tsf_info; |
| memset(tsf_info, 0, sizeof(mlan_ds_tsf_info)); |
| if (user_data_len == 1) { |
| if (data[0] < 0 || data[0] > 1) { |
| PRINTM(MERROR, "Invalid tsf Format\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| tsf_info->tsf_format = data[0]; |
| } |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)tsf_info, |
| sizeof(mlan_ds_tsf_info), respbuflen); |
| ret = sizeof(mlan_ds_tsf_info); |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get transition channel |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_transition_channel(moal_private *priv, t_u8 *respbuf, |
| t_u32 respbuflen) |
| { |
| int header_len = 0, user_data_len = 0; |
| int ret = 0, data[1]; |
| |
| ENTER(); |
| if (!priv || (priv->bss_type != MLAN_BSS_TYPE_UAP)) { |
| PRINTM(MERROR, "priv is null or interface is not AP"); |
| ret = -EFAULT; |
| LEAVE(); |
| return ret; |
| } |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TRANSITION_CHANNEL); |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, data, |
| sizeof(data) / sizeof(int), &user_data_len); |
| if (user_data_len > 1) { |
| PRINTM(MERROR, "Invalid parameter number\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (user_data_len) |
| priv->trans_chan = data[0]; |
| } |
| data[0] = priv->trans_chan; |
| moal_memcpy_ext(priv->phandle, respbuf, &data, sizeof(data), |
| respbuflen); |
| ret = sizeof(int); |
| done: |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| #if defined(STA_CFG80211) || defined(UAP_CFG80211) |
| #ifdef WIFI_DIRECT_SUPPORT |
| #define DEF_NOA_INTERVAL 100 |
| /** |
| ** @brief Set/Get P2P NoA (Notice of Absence) parameters |
| ** @param priv Pointer to moal_private structure |
| ** @param respbuf Pointer to response buffer |
| ** @param resplen Response buffer length |
| ** |
| ** @return Number of bytes written, negative for failure. |
| **/ |
| static int |
| woal_p2p_ps_cfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int user_data_len = 0; |
| int ret = 0, data[2]; |
| u32 duration = priv->phandle->noa_duration; |
| u32 interval = 0; |
| |
| ENTER(); |
| if (strlen(respbuf) > strlen("P2P_PERIODIC_SLEEP")) { |
| memset((char *)data, 0, sizeof(data)); |
| parse_arguments(respbuf + strlen("P2P_PERIODIC_SLEEP") + 1, |
| data, ARRAY_SIZE(data), &user_data_len); |
| } |
| if ((user_data_len != 1) && (user_data_len != 2)) { |
| PRINTM(MERROR, |
| " Invalid parameter number for P2P_PERIODIC_SLEEP"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (data[0] < DEF_NOA_INTERVAL) |
| interval = DEF_NOA_INTERVAL; |
| else |
| interval = (data[0] + DEF_NOA_INTERVAL - 1) / DEF_NOA_INTERVAL * |
| DEF_NOA_INTERVAL; |
| |
| if (user_data_len == 2) |
| duration = data[1]; |
| if (duration >= interval) { |
| PRINTM(MERROR, |
| " Invalid noa duration/interval! duration=%d interval=%d\n", |
| duration, interval); |
| ret = -EINVAL; |
| goto done; |
| } |
| priv->phandle->noa_interval = interval; |
| priv->phandle->noa_duration = duration; |
| PRINTM(MIOCTL, "configure noa interval=%d, duration=%d\n", |
| priv->phandle->noa_interval, priv->phandle->noa_duration); |
| done: |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| #endif |
| |
| /** |
| * @brief Set/Get DFS repeater mode |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_dfs_repeater_cfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| int user_data_len = 0, header_len = 0, data[1] = { 0 }; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *misc_cfg = NULL; |
| mlan_ds_misc_dfs_repeater *dfs_repeater = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DFS_REPEATER_CFG); |
| |
| /* 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 */ |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| misc_cfg = (mlan_ds_misc_cfg *)req->pbuf; |
| misc_cfg->sub_command = MLAN_OID_MISC_DFS_REAPTER_MODE; |
| dfs_repeater = |
| (mlan_ds_misc_dfs_repeater *)&misc_cfg->param.dfs_repeater; |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| req->action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| if (user_data_len != 1) { |
| PRINTM(MERROR, "Invalid number of args! %d\n", |
| user_data_len); |
| ret = -EINVAL; |
| goto done; |
| } |
| if ((data[0] != MTRUE) && (data[0] != MFALSE)) { |
| PRINTM(MERROR, "Invalid DFS repeater mode %d\n", |
| data[0]); |
| ret = -EINVAL; |
| goto done; |
| } |
| dfs_repeater->mode = (t_u16)data[0]; |
| |
| 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; |
| } |
| |
| if (!user_data_len) { |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)dfs_repeater, |
| sizeof(mlan_ds_misc_dfs_repeater), respbuflen); |
| ret = sizeof(mlan_ds_misc_dfs_repeater); |
| } |
| |
| /* Store current value of DFS repeater mode for futher references. eg., |
| * for avoiding CAC timers |
| */ |
| priv->phandle->dfs_repeater_mode = dfs_repeater->mode; |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| #ifdef WIFI_DIRECT_SUPPORT |
| #if defined(STA_CFG80211) || defined(UAP_CFG80211) |
| /** |
| * @brief Set/Get MIRACAST configuration parameters |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_miracast_cfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| int user_data_len = 0, header_len = 0, data[3] = { 0, 0, 0 }; |
| |
| ENTER(); |
| |
| if (!priv || !priv->phandle) { |
| PRINTM(MERROR, "priv or handle is null\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_MIRACAST_CFG); |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| data[0] = priv->phandle->miracast_mode; |
| data[1] = priv->phandle->miracast_scan_time; |
| data[2] = priv->phandle->scan_chan_gap; |
| |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, |
| sizeof(data), respbuflen); |
| ret = sizeof(data); |
| } else { |
| /* SET operation */ |
| memset(data, 0, sizeof(data)); |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| |
| if (user_data_len > 3) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (data[0] < 0 || data[0] > 2 || data[1] < 0 || data[2] < 0) { |
| PRINTM(MERROR, "Invalid argument\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| |
| if (user_data_len >= 1) |
| priv->phandle->miracast_mode = (t_u8)data[0]; |
| if (user_data_len >= 2) |
| priv->phandle->miracast_scan_time = (t_u16)data[1]; |
| if (user_data_len == 3) |
| priv->phandle->scan_chan_gap = (t_u16)data[2]; |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Configuring scan gap for miracast mode |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return 0 --success, otherwise failure |
| */ |
| static int |
| woal_set_scan_chan_gap(moal_private *priv, t_u8 *respbuf, int respbuflen) |
| { |
| t_u32 data[2]; |
| int ret = 0; |
| int user_data_len = 0; |
| |
| ENTER(); |
| |
| if (strlen(respbuf) > strlen("SCAN_TIMING")) { |
| memset((char *)data, 0, sizeof(data)); |
| parse_arguments(respbuf + strlen("SCAN_TIMING") + 1, data, |
| ARRAY_SIZE(data), &user_data_len); |
| } |
| |
| if (user_data_len != 2) { |
| PRINTM(MERROR, "Invalid arguments for scan timing\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| priv->phandle->miracast_scan_time = (t_u16)data[0]; |
| priv->phandle->scan_chan_gap = (t_u16)data[1]; |
| done: |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| #endif |
| |
| /** |
| * @brief Set/Get control to coex RX window size configuration |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_coex_rx_winsize(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| int user_data_len = 0, header_len = 0, data = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_11n_cfg *cfg_11n = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (!priv || !priv->phandle) { |
| PRINTM(MERROR, "priv or handle is null\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_COEX_RX_WINSIZE); |
| |
| /* Allocate an IOCTL request buffer */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| /* Fill request buffer */ |
| req->req_id = MLAN_IOCTL_11N_CFG; |
| cfg_11n = (mlan_ds_11n_cfg *)req->pbuf; |
| cfg_11n->sub_command = MLAN_OID_11N_CFG_COEX_RX_WINSIZE; |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| req->action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &data, |
| sizeof(data) / sizeof(int), &user_data_len); |
| if (user_data_len != 1) { |
| PRINTM(MERROR, "Invalid number of args! %d\n", |
| user_data_len); |
| ret = -EINVAL; |
| goto done; |
| } |
| if ((data != MTRUE) && (data != MFALSE)) { |
| PRINTM(MERROR, |
| "Invalid coex RX window size parameter %d\n", |
| data); |
| ret = -EINVAL; |
| goto done; |
| } |
| cfg_11n->param.coex_rx_winsize = data; |
| 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; |
| } |
| |
| if (!user_data_len) { |
| moal_memcpy_ext(priv->phandle, respbuf, |
| (t_u8 *)&cfg_11n->param.coex_rx_winsize, |
| sizeof(t_u32), respbuflen); |
| ret = sizeof(t_u32); |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get control to TX AMPDU configuration on infra link |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_txaggrctrl(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| int user_data_len = 0, header_len = 0, data = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_11n_cfg *cfg_11n = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (!priv || !priv->phandle) { |
| PRINTM(MERROR, "priv or handle is null\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TX_AGGR_CTRL); |
| |
| /* Allocate an IOCTL request buffer */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| /* Fill request buffer */ |
| req->req_id = MLAN_IOCTL_11N_CFG; |
| cfg_11n = (mlan_ds_11n_cfg *)req->pbuf; |
| cfg_11n->sub_command = MLAN_OID_11N_CFG_TX_AGGR_CTRL; |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| req->action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &data, |
| sizeof(data) / sizeof(int), &user_data_len); |
| if (user_data_len != 1) { |
| PRINTM(MERROR, "Invalid number of args! %d\n", |
| user_data_len); |
| ret = -EINVAL; |
| goto done; |
| } |
| if ((data != MTRUE) && (data != MFALSE)) { |
| PRINTM(MERROR, "Invalid txaggrctrl parameter %d\n", |
| data); |
| ret = -EINVAL; |
| goto done; |
| } |
| cfg_11n->param.txaggrctrl = data; |
| 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; |
| } |
| |
| if (!user_data_len) { |
| moal_memcpy_ext(priv->phandle, respbuf, |
| (t_u8 *)&cfg_11n->param.txaggrctrl, |
| sizeof(t_u32), respbuflen); |
| ret = sizeof(t_u32); |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get control to enable/disable auto TDLS |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_auto_tdls(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| int user_data_len = 0, header_len = 0, data = 0; |
| |
| ENTER(); |
| |
| if (!priv || !priv->phandle) { |
| PRINTM(MERROR, "priv or handle is null\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_AUTO_TDLS); |
| |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| data = priv->enable_auto_tdls; |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data, |
| sizeof(data), respbuflen); |
| ret = sizeof(data); |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &data, |
| sizeof(data) / sizeof(int), &user_data_len); |
| if (user_data_len != 1) { |
| PRINTM(MERROR, "Invalid number of args! %d\n", |
| user_data_len); |
| ret = -EINVAL; |
| goto done; |
| } |
| if ((data != MTRUE) && (data != MFALSE)) { |
| PRINTM(MERROR, "Invalid autotdls parameter %d\n", data); |
| ret = -EINVAL; |
| goto done; |
| } |
| priv->enable_auto_tdls = (t_u8)data; |
| } |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| #ifdef PCIE |
| /** |
| * @brief Read/Write PCIE register |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_pcie_reg_rw(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| moal_handle *handle = priv->phandle; |
| int data[3]; |
| t_u32 reg; |
| t_u32 value; |
| int ret = MLAN_STATUS_SUCCESS; |
| int user_data_len = 0, header_len = 0; |
| |
| ENTER(); |
| |
| memset(data, 0, sizeof(data)); |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PCIE_REG_RW); |
| if ((int)strlen(respbuf) == header_len) { |
| PRINTM(MERROR, "Invalid number of parameters\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| if ((user_data_len != 1) && (user_data_len != 2)) { |
| PRINTM(MERROR, "Invalid number of parameters\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| reg = (t_u32)data[0]; |
| if (user_data_len == 1) { |
| if (moal_read_reg(handle, reg, &value)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| data[1] = value; |
| } else { |
| value = data[1]; |
| if (moal_write_reg(handle, reg, value)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| } |
| moal_memcpy_ext(handle, respbuf, (t_u8 *)data, sizeof(data), |
| respbuflen); |
| ret = sizeof(data); |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Read/Write PCIE register/memory from BAR0 |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_pcie_bar0_reg_rw(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| moal_handle *handle = priv->phandle; |
| pcie_service_card *card = (pcie_service_card *)handle->card; |
| int data[3]; |
| t_u32 reg; |
| t_u32 value; |
| int ret = MLAN_STATUS_SUCCESS; |
| int user_data_len = 0, header_len = 0; |
| |
| ENTER(); |
| |
| memset(data, 0, sizeof(data)); |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_PCIE_BAR0_REG_RW); |
| if ((int)strlen(respbuf) == header_len) { |
| PRINTM(MERROR, "Invalid number of parameters\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| if ((user_data_len != 1) && (user_data_len != 2)) { |
| PRINTM(MERROR, "Invalid number of parameters\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| reg = (t_u32)data[0]; |
| if (user_data_len == 1) { |
| value = ioread32(card->pci_mmap + reg); |
| if (value == MLAN_STATUS_FAILURE) { |
| ret = -EFAULT; |
| goto done; |
| } |
| data[1] = value; |
| } else { |
| value = data[1]; |
| iowrite32(value, card->pci_mmap + reg); |
| } |
| moal_memcpy_ext(handle, respbuf, (t_u8 *)data, sizeof(data), |
| respbuflen); |
| ret = sizeof(data); |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| |
| /** |
| * @brief Get SOC temperature |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_get_sensor_temp(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *pcfg = NULL; |
| int ret = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| pcfg = (mlan_ds_misc_cfg *)req->pbuf; |
| pcfg->sub_command = MLAN_OID_MISC_GET_SENSOR_TEMP; |
| 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 done; |
| } |
| |
| memset(respbuf, 0, respbuflen); |
| moal_memcpy_ext(priv->phandle, respbuf, |
| &pcfg->param.sensor_temp.temperature, sizeof(t_u32), |
| respbuflen); |
| |
| ret = sizeof(t_u32); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) |
| #if defined(STA_CFG80211) || defined(UAP_CFG80211) |
| /** |
| * @brief Enable/disable DFS offload |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_dfs_offload_enable(moal_private *priv, t_u8 *respbuf, |
| t_u32 respbuflen) |
| { |
| struct wiphy *wiphy = NULL; |
| int ret = 0, dfs_offload_en = 0, user_data_len = 0, header_len = 0, |
| dfs_offload; |
| |
| ENTER(); |
| |
| if (priv && priv->wdev) |
| wiphy = priv->wdev->wiphy; |
| if (!wiphy) { |
| PRINTM(MERROR, "wiphy is NULL\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| dfs_offload = moal_extflg_isset(priv->phandle, EXT_DFS_OFFLOAD); |
| if (woal_is_any_interface_active(priv->phandle)) { |
| PRINTM(MERROR, |
| "DFS offload enable/disable do not allowed after BSS started!\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DFS_OFFLOAD); |
| parse_arguments(respbuf + header_len, &dfs_offload_en, |
| sizeof(dfs_offload_en) / sizeof(int), &user_data_len); |
| if (user_data_len != 1) { |
| PRINTM(MERROR, "Invalid number of args! %d\n", user_data_len); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| if (dfs_offload_en != 0 && dfs_offload_en != 1) { |
| PRINTM(MERROR, "Invalid args!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (dfs_offload != dfs_offload_en) { |
| dfs_offload = dfs_offload_en; |
| if (dfs_offload) |
| moal_extflg_set(priv->phandle, EXT_DFS_OFFLOAD); |
| else |
| moal_extflg_clear(priv->phandle, EXT_DFS_OFFLOAD); |
| woal_update_radar_chans_dfs_state(wiphy); |
| } |
| done: |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| #endif |
| |
| /** |
| * @brief Set/Get TDLS CS off channel value |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_tdls_cs_chan(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ioctl_req *ioctl_req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| int ret = 0; |
| int user_data_len = 0, header_len = 0, data = 0; |
| |
| ENTER(); |
| |
| if (!priv || !priv->phandle) { |
| PRINTM(MERROR, "priv or handle is null\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_CS_CHANNEL; |
| ioctl_req->req_id = MLAN_IOCTL_MISC_CFG; |
| |
| header_len = strlen("TDLS_CS_CHAN"); |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| ioctl_req->action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len + 1, &data, |
| sizeof(data) / sizeof(int), &user_data_len); |
| if (user_data_len != 1) { |
| PRINTM(MERROR, "Invalid number of args! %d\n", |
| user_data_len); |
| ret = -EINVAL; |
| goto done; |
| } |
| ioctl_req->action = MLAN_ACT_SET; |
| misc->param.tdls_cs_channel = (t_u8)data; |
| } |
| |
| status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| ret = sprintf(respbuf, "off channel %d\n", |
| misc->param.tdls_cs_channel) + 1; |
| |
| PRINTM(MIOCTL, "tdls CS channel %d\n", misc->param.tdls_cs_channel); |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(ioctl_req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get TDLS idle timeout value |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_tdls_idle_time(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ioctl_req *ioctl_req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| int ret = 0; |
| int user_data_len = 0, header_len = 0, data = 0; |
| |
| ENTER(); |
| |
| if (!priv || !priv->phandle) { |
| PRINTM(MERROR, "priv or handle is null\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_IDLE_TIME; |
| ioctl_req->req_id = MLAN_IOCTL_MISC_CFG; |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TDLS_IDLE_TIME); |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| ioctl_req->action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &data, |
| sizeof(data) / sizeof(int), &user_data_len); |
| if (user_data_len != 1) { |
| PRINTM(MERROR, "Invalid number of args! %d\n", |
| user_data_len); |
| ret = -EINVAL; |
| goto done; |
| } |
| ioctl_req->action = MLAN_ACT_SET; |
| misc->param.tdls_idle_time = (t_u16)data; |
| } |
| |
| status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| moal_memcpy_ext(priv->phandle, respbuf, |
| (t_u8 *)&misc->param.tdls_idle_time, sizeof(t_u16), |
| respbuflen); |
| ret = sizeof(t_u16); |
| |
| PRINTM(MIOCTL, "tdls idle time %d\n", misc->param.tdls_idle_time); |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(ioctl_req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get dynamic bandwidth |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_config_dyn_bw(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ioctl_req *ioctl_req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| int ret = 0; |
| int user_data_len = 0, header_len = 0, data = 0; |
| |
| ENTER(); |
| |
| if (!priv || !priv->phandle) { |
| PRINTM(MERROR, "priv or handle is null\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_DYN_BW; |
| ioctl_req->req_id = MLAN_IOCTL_MISC_CFG; |
| |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DYN_BW); |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| ioctl_req->action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &data, |
| sizeof(data) / sizeof(int), &user_data_len); |
| if (user_data_len != 1) { |
| PRINTM(MERROR, "Invalid number of args! %d\n", |
| user_data_len); |
| ret = -EINVAL; |
| goto done; |
| } |
| ioctl_req->action = MLAN_ACT_SET; |
| misc->param.dyn_bw = (t_u16)data; |
| } |
| |
| status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&misc->param.dyn_bw, |
| sizeof(t_u16), respbuflen); |
| ret = sizeof(t_u16); |
| |
| PRINTM(MIOCTL, "Dynamic bandwidth %d\n", misc->param.dyn_bw); |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(ioctl_req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| #if defined(UAP_SUPPORT) |
| /** |
| * @brief Check validation of channel and oper class |
| * |
| * @param priv Pointer to moal_private structure |
| * @param channel channel |
| * @param oper_class oper_class |
| |
| * @return SUCCESS/FAIL |
| */ |
| static int |
| woal_check_valid_channel_operclass(moal_private *priv, int channel, |
| int 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_CHECK; |
| ioctl_req->req_id = MLAN_IOCTL_MISC_CFG; |
| ioctl_req->action = MLAN_ACT_GET; |
| misc->param.bw_chan_oper.oper_class = (t_u8)oper_class; |
| misc->param.bw_chan_oper.channel = (t_u8)channel; |
| |
| status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(ioctl_req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief send CSA/ECSA action frame |
| * |
| ** @param priv Pointer to moal_private structure |
| * @param block_tx 0-no need block traffic 1- need block traffic |
| * @param oper_class oper_class |
| * @param channel channel |
| * @param switch count how many csa/ecsa beacon will send out |
| * @param wait_option |
| * |
| * @return channel center frequency center, if found; O, otherwise |
| */ |
| static int |
| woal_action_channel_switch(moal_private *priv, t_u8 block_tx, t_u8 oper_class, |
| t_u8 channel, t_u8 switch_count, t_u8 wait_option) |
| { |
| mlan_status ret = MLAN_STATUS_SUCCESS; |
| mlan_ds_bss *bss = NULL; |
| mlan_ioctl_req *req = NULL; |
| |
| ENTER(); |
| |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss)); |
| if (req == NULL) { |
| ret = MLAN_STATUS_FAILURE; |
| goto done; |
| } |
| |
| bss = (mlan_ds_bss *)req->pbuf; |
| bss->sub_command = MLAN_OID_ACTION_CHAN_SWITCH; |
| req->req_id = MLAN_IOCTL_BSS; |
| req->action = MLAN_ACT_SET; |
| bss->param.chanswitch.chan_switch_mode = block_tx; |
| bss->param.chanswitch.new_channel_num = channel; |
| bss->param.chanswitch.chan_switch_count = switch_count; |
| bss->param.chanswitch.new_oper_class = oper_class; |
| 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 Set extended channel switch ie |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_extend_channel_switch(moal_private *priv, t_u8 *respbuf, |
| t_u32 respbuflen) |
| { |
| int ret = 0; |
| int user_data_len = 0; |
| int data[5] = { 0 }; |
| ENTER(); |
| |
| if (!priv || !priv->phandle || |
| (priv->bss_role != MLAN_BSS_ROLE_UAP) || |
| (priv->bss_started != MTRUE)) { |
| PRINTM(MERROR, |
| "priv or handle is null or interface is not AP/GO" |
| "or AP is not started\n"); |
| ret = -EFAULT; |
| LEAVE(); |
| return ret; |
| } |
| |
| parse_arguments(respbuf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_EXTEND_CHAN_SWITCH), |
| data, ARRAY_SIZE(data), &user_data_len); |
| |
| if (sizeof(int) * user_data_len > sizeof(data)) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| LEAVE(); |
| return ret; |
| } |
| if (user_data_len < 4) { |
| PRINTM(MERROR, "Too few arguments\n"); |
| ret = -EINVAL; |
| LEAVE(); |
| return ret; |
| } |
| if (data[1]) { |
| if (woal_check_valid_channel_operclass(priv, data[2], data[1])) { |
| PRINTM(MERROR, "Wrong channel switch parameters!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| if (data[3]) |
| woal_channel_switch(priv, data[0], data[1], data[2], data[3], |
| data[4], MFALSE); |
| else |
| woal_action_channel_switch(priv, data[0], data[1], data[2], |
| data[3], MOAL_IOCTL_WAIT); |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief P2P extended channel switch |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_p2p_ecsa(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| int user_data_len = 0, header_len = 0; |
| int data[2] = { 0 }; |
| t_u8 bw = 0, oper_class = 0, channel = 0; |
| IEEEtypes_ExtChanSwitchAnn_t *ext_chan_switch = NULL; |
| custom_ie *pcust_chansw_ie = NULL; |
| mlan_ioctl_req *ioctl_req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (!priv || !priv->phandle) { |
| PRINTM(MERROR, "priv or handle is null\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| if (priv->bss_role != MLAN_BSS_ROLE_UAP) { |
| PRINTM(MERROR, |
| "Extended Channel Switch is only allowed for AP/GO mode\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| if (priv->bss_started != MTRUE) { |
| PRINTM(MERROR, "AP is not started!\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; |
| ioctl_req->action = MLAN_ACT_SET; |
| misc->param.cust_ie.type = TLV_TYPE_MGMT_IE; |
| misc->param.cust_ie.len = (sizeof(custom_ie) - MAX_IE_SIZE); |
| |
| pcust_chansw_ie = (custom_ie *)&misc->param.cust_ie.ie_data_list[0]; |
| pcust_chansw_ie->ie_index = 0xffff; /*Auto index */ |
| pcust_chansw_ie->ie_length = sizeof(IEEEtypes_ExtChanSwitchAnn_t); |
| pcust_chansw_ie->mgmt_subtype_mask = MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP; /*Add IE for |
| BEACON/probe resp */ |
| ext_chan_switch = |
| (IEEEtypes_ExtChanSwitchAnn_t *) pcust_chansw_ie->ie_buffer; |
| |
| header_len = strlen("P2P_ECSA"); |
| parse_arguments(respbuf + header_len + 1, data, ARRAY_SIZE(data), |
| &user_data_len); |
| |
| if (user_data_len != 2) { |
| PRINTM(MERROR, "Invalid parameters\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| channel = data[0]; |
| /* bandwidth 20:20M 40:40M 80:80M */ |
| bw = data[1]; |
| if (bw != 20 && bw != 40 && bw != 80) { |
| PRINTM(MERROR, "Unsupported bandwidth\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (channel >= 52 && channel <= 144) { |
| PRINTM(MERROR, "Switch to DFS channel is not allowed!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| woal_priv_get_nonglobal_operclass_by_bw_channel(priv, bw, channel, |
| &oper_class); |
| if (oper_class == 0) { |
| PRINTM(MERROR, "Wrong parameters!\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| ext_chan_switch->element_id = EXTEND_CHANNEL_SWITCH_ANN; |
| ext_chan_switch->len = 4; |
| ext_chan_switch->chan_switch_mode = 1; |
| ext_chan_switch->new_oper_class = oper_class; |
| ext_chan_switch->new_channel_num = channel; |
| ext_chan_switch->chan_switch_count = DEF_CHAN_SWITCH_COUNT; |
| |
| if (ext_chan_switch->chan_switch_mode) { |
| if (netif_carrier_ok(priv->netdev)) |
| netif_carrier_off(priv->netdev); |
| woal_stop_queue(priv->netdev); |
| priv->uap_tx_blocked = MTRUE; |
| } |
| |
| DBG_HEXDUMP(MCMD_D, "ECSA IE", (t_u8 *)pcust_chansw_ie->ie_buffer, |
| pcust_chansw_ie->ie_length); |
| |
| status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| priv->phandle->chsw_wait_q_woken = MFALSE; |
| /* wait for channel switch to complete */ |
| wait_event_interruptible_timeout(priv->phandle->chsw_wait_q, |
| priv->phandle->chsw_wait_q_woken, |
| (u32)HZ * |
| (ext_chan_switch->chan_switch_count + |
| 2) * 110 / 1000); |
| |
| pcust_chansw_ie->ie_index = 0xffff; /*Auto index */ |
| pcust_chansw_ie->mgmt_subtype_mask = 0; |
| status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| PRINTM(MERROR, "Failed to clear ECSA IE\n"); |
| } |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(ioctl_req); |
| |
| LEAVE(); |
| return ret; |
| } |
| #endif |
| |
| /** |
| * @brief Set random mac configure value (ON/OFF) |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_config_random_mac(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| int header_len = 0, space_len = 0, i; |
| t_u8 rand_data[3]; |
| const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = { 0, 0, 0, 0, 0, 0 }; |
| |
| ENTER(); |
| |
| if (!priv || !priv->phandle) { |
| PRINTM(MERROR, "priv or handle is null\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| header_len = strlen("FAKEMAC"); |
| if ((int)strlen(respbuf) >= header_len) { |
| for (i = 0; i < (int)(strlen(respbuf) - header_len - 1); i++) { |
| if (respbuf[header_len + 1 + i] != ' ') |
| break; |
| } |
| space_len = i; |
| |
| if (strncmp(respbuf + header_len + 1 + space_len, "On", |
| strlen("On")) == 0) { |
| if (memcmp(priv->random_mac, zero_mac, |
| MLAN_MAC_ADDR_LENGTH)) { |
| ret = sprintf(respbuf, |
| "FAKEMAC has been On\n") + 1; |
| goto done; |
| } |
| moal_memcpy_ext(priv->phandle, priv->random_mac, |
| priv->current_addr, ETH_ALEN, |
| MLAN_MAC_ADDR_LENGTH); |
| get_random_bytes(rand_data, 3); |
| moal_memcpy_ext(priv->phandle, priv->random_mac + 3, |
| rand_data, 3, 3); |
| PRINTM(MMSG, "FAKEMAC parameter is On\n"); |
| } else if (strncmp(respbuf + header_len + 1 + space_len, "Off", |
| strlen("Off")) == 0) { |
| memset(priv->random_mac, 0, ETH_ALEN); |
| PRINTM(MMSG, "FAKEMAC parameter is Off\n"); |
| } else { |
| PRINTM(MERROR, "Invalid parameter!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } else { |
| PRINTM(MERROR, "Invalid parameter!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Download start keep alive parameters |
| * |
| * @param priv Pointer to moal_private structure |
| * @param mkeep_alive_id keep alive ID number |
| * @param ip_pke IP packet from host |
| * @param ip_pke_len IP packet length from host |
| * @param src_mac Source MAC address |
| * @param dst_mac Destination MAC address |
| * @param period_msec Send keep alive packet interval |
| |
| * @return 0: success fail otherwise |
| */ |
| int |
| woal_start_mkeep_alive(moal_private *priv, t_u8 mkeep_alive_id, |
| t_u8 *ip_pkt, t_u16 ip_pkt_len, t_u8 *src_mac, |
| t_u8 *dst_mac, t_u32 period_msec, |
| t_u32 retry_interval, t_u8 retry_cnt) |
| { |
| mlan_ioctl_req *ioctl_req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| int ret = 0; |
| |
| ENTER(); |
| |
| if (!priv || !priv->phandle) { |
| PRINTM(MERROR, "priv or handle is null\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_CLOUD_KEEP_ALIVE; |
| ioctl_req->req_id = MLAN_IOCTL_MISC_CFG; |
| |
| if (mkeep_alive_id >= MAX_KEEP_ALIVE_ID) { |
| PRINTM(MERROR, "Invalid parameters\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| /* SET operation */ |
| ioctl_req->action = MLAN_ACT_SET; |
| misc->param.keep_alive.mkeep_alive_id = mkeep_alive_id; |
| misc->param.keep_alive.enable = true; |
| misc->param.keep_alive.send_interval = period_msec; |
| misc->param.keep_alive.retry_interval = retry_interval; |
| misc->param.keep_alive.retry_count = retry_cnt; |
| moal_memcpy_ext(priv->phandle, misc->param.keep_alive.dst_mac, dst_mac, |
| MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH); |
| moal_memcpy_ext(priv->phandle, misc->param.keep_alive.src_mac, src_mac, |
| MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH); |
| misc->param.keep_alive.pkt_len = |
| MIN(ip_pkt_len, MKEEP_ALIVE_IP_PKT_MAX); |
| moal_memcpy_ext(priv->phandle, misc->param.keep_alive.packet, ip_pkt, |
| ip_pkt_len, MKEEP_ALIVE_IP_PKT_MAX); |
| |
| status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(ioctl_req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Download stop keep alive parameters |
| * |
| * @param priv Pointer to moal_private structure |
| * @param mkeep_alive_id keep alive ID number |
| * @param ip_pkt Last packet |
| * @param ip_pkt_len Last packet length |
| |
| * @return 0: success fail otherwise |
| */ |
| int |
| woal_stop_mkeep_alive(moal_private *priv, t_u8 mkeep_alive_id, t_u8 reset, |
| t_u8 *ip_pkt, t_u8 *pkt_len) |
| { |
| mlan_ioctl_req *ioctl_req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| mlan_ds_misc_keep_alive *misc_keep_alive = NULL; |
| int ret = 0; |
| |
| ENTER(); |
| |
| if (!priv || !priv->phandle) { |
| PRINTM(MERROR, "priv or handle is null\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_CLOUD_KEEP_ALIVE; |
| ioctl_req->req_id = MLAN_IOCTL_MISC_CFG; |
| misc_keep_alive = &misc->param.keep_alive; |
| |
| if (mkeep_alive_id >= MAX_KEEP_ALIVE_ID) { |
| PRINTM(MERROR, "Invalid parameters\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| /* GET operation */ |
| ioctl_req->action = MLAN_ACT_GET; |
| misc_keep_alive->mkeep_alive_id = mkeep_alive_id; |
| misc_keep_alive->enable = false; |
| |
| status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| if (!misc_keep_alive->enable) { |
| PRINTM(MERROR, "ID %d is already stop\n", mkeep_alive_id); |
| goto done; |
| } |
| |
| if (reset) |
| ioctl_req->action = MLAN_ACT_RESET; |
| else |
| /* SET operation */ |
| ioctl_req->action = MLAN_ACT_SET; |
| misc_keep_alive->mkeep_alive_id = mkeep_alive_id; |
| misc_keep_alive->enable = false; |
| |
| status = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| #ifdef STA_CFG80211 |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) |
| if (IS_STA_CFG80211(priv->phandle->params.cfg80211_wext)) { |
| ret = woal_mkeep_alive_vendor_event(priv, |
| &misc->param.keep_alive); |
| if (ret) |
| PRINTM(MERROR, |
| "Keep alive vendor event upload failed\n"); |
| } |
| #endif |
| #endif |
| if (pkt_len) { |
| *pkt_len = MIN(misc_keep_alive->pkt_len, |
| (MKEEP_ALIVE_IP_PKT_MAX - 1)); |
| PRINTM(MINFO, "keep alive stop pkt_len is %d\n", *pkt_len); |
| } |
| if (*pkt_len && ip_pkt) |
| moal_memcpy_ext(priv->phandle, ip_pkt, misc_keep_alive->packet, |
| *pkt_len, *pkt_len); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(ioctl_req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Save cloud keep alive params in driver handle |
| * |
| * @param priv Pointer to moal_private structure |
| * @params Other params for keep alive |
| |
| * @return Number of bytes written, negative for failure. |
| */ |
| int |
| woal_priv_save_cloud_keep_alive_params(moal_private *priv, |
| t_u8 mkeep_alive_id, t_u8 enable, |
| t_u16 ether_type, t_u8 *ip_pkt, |
| t_u16 ip_pkt_len, t_u8 *src_mac, |
| t_u8 *dst_mac, t_u32 period_msec, |
| t_u32 retry_interval, t_u8 retry_cnt) |
| { |
| mlan_ioctl_req *ioctl_req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| int ret = 0; |
| mlan_ds_misc_keep_alive *keep_alive = NULL; |
| moal_handle *phandle = NULL; |
| |
| ENTER(); |
| |
| if (!priv || !priv->phandle) { |
| PRINTM(MERROR, "priv or handle is null\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| phandle = priv->phandle; |
| |
| 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_CLOUD_KEEP_ALIVE; |
| ioctl_req->req_id = MLAN_IOCTL_MISC_CFG; |
| |
| if (mkeep_alive_id >= MAX_KEEP_ALIVE_ID) { |
| PRINTM(MERROR, "Invalid parameters\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| /* GET operation */ |
| ioctl_req->action = MLAN_ACT_GET; |
| misc->param.keep_alive.mkeep_alive_id = mkeep_alive_id; |
| misc->param.keep_alive.enable = true; |
| |
| ret = woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT); |
| if (ret != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| if (misc->param.keep_alive.enable) { |
| PRINTM(MERROR, "ID %d is in use\n", mkeep_alive_id); |
| ret = -EINVAL; |
| goto done; |
| } |
| |
| keep_alive = &phandle->keep_alive[mkeep_alive_id]; |
| keep_alive->mkeep_alive_id = mkeep_alive_id; |
| keep_alive->enable = enable; |
| if (enable) { |
| keep_alive->cached = true; |
| keep_alive->send_interval = period_msec; |
| keep_alive->retry_interval = retry_interval; |
| keep_alive->retry_count = retry_cnt; |
| moal_memcpy_ext(phandle, keep_alive->dst_mac, dst_mac, |
| MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH); |
| moal_memcpy_ext(phandle, keep_alive->src_mac, src_mac, |
| MLAN_MAC_ADDR_LENGTH, MLAN_MAC_ADDR_LENGTH); |
| keep_alive->pkt_len = MIN(ip_pkt_len, MKEEP_ALIVE_IP_PKT_MAX); |
| moal_memcpy_ext(phandle, keep_alive->packet, ip_pkt, ip_pkt_len, |
| MKEEP_ALIVE_IP_PKT_MAX); |
| if (ether_type) |
| keep_alive->ether_type = ether_type; |
| else |
| keep_alive->ether_type = 0; |
| } |
| |
| done: |
| if (ret != MLAN_STATUS_PENDING) |
| kfree(ioctl_req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Cloud keep alive feature |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_cloud_keep_alive(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| cloud_keep_alive *keep_alive = NULL; |
| int header_len = 0; |
| |
| ENTER(); |
| |
| header_len = strlen(PRIV_CMD_CLOUD_KEEP_ALIVE); |
| |
| keep_alive = (cloud_keep_alive *) (respbuf + header_len); |
| |
| if (keep_alive->enable) { |
| ret = woal_priv_save_cloud_keep_alive_params(priv, |
| keep_alive-> |
| mkeep_alive_id, |
| keep_alive->enable, |
| 0, keep_alive->pkt, |
| keep_alive-> |
| pkt_len, |
| keep_alive-> |
| src_mac, |
| keep_alive-> |
| dst_mac, |
| keep_alive-> |
| sendInterval, |
| keep_alive-> |
| retryInterval, |
| keep_alive-> |
| retryCount); |
| } else { |
| if (0 != woal_stop_mkeep_alive(priv, keep_alive->mkeep_alive_id, |
| keep_alive->reset, |
| keep_alive->pkt, |
| &keep_alive->pkt_len)) { |
| ret = -EFAULT; |
| return ret; |
| } |
| ret = respbuflen; |
| } |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get static rx abort config |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_rx_abort_cfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| int ret = 0; |
| int data[2] = { 0 }; |
| int header_len = 0, user_data_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (!respbuf) { |
| PRINTM(MERROR, "response buffer is not available!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RX_ABORT_CFG); |
| user_data_len = strlen(respbuf) - header_len; |
| |
| /* Allocate an IOCTL request buffer */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| /* Fill request buffer */ |
| misc = (mlan_ds_misc_cfg *)req->pbuf; |
| misc->sub_command = MLAN_OID_MISC_RX_ABORT_CFG; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| req->action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| if (user_data_len > 2 || |
| (data[0] == MTRUE && user_data_len != 2)) { |
| PRINTM(MERROR, "Invalid number of args!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (data[0] == MTRUE && data[1] > 0x7f) { |
| PRINTM(MERROR, "Invalid threshold value\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| misc->param.rx_abort_cfg.enable = (t_u8)data[0]; |
| if (user_data_len == 2) |
| misc->param.rx_abort_cfg.rssi_threshold = (t_s8)data[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; |
| } |
| |
| data[0] = misc->param.rx_abort_cfg.enable; |
| data[1] = misc->param.rx_abort_cfg.rssi_threshold; |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data), |
| respbuflen); |
| ret = sizeof(data); |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get dynamic rx abort config |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_rx_abort_cfg_ext(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| int ret = 0; |
| int data[3] = { 0 }; |
| int header_len = 0, user_data_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (!respbuf) { |
| PRINTM(MERROR, "response buffer is not available!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RX_ABORT_CFG_EXT); |
| user_data_len = strlen(respbuf) - header_len; |
| |
| /* Allocate an IOCTL request buffer */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| /* Fill request buffer */ |
| misc = (mlan_ds_misc_cfg *)req->pbuf; |
| misc->sub_command = MLAN_OID_MISC_RX_ABORT_CFG_EXT; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| req->action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| if (user_data_len > 3 || |
| (data[0] == MTRUE && user_data_len != 3)) { |
| PRINTM(MERROR, "Invalid number of args!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (data[0] == MTRUE) { |
| if (data[1] > 0x7f) { |
| PRINTM(MERROR, "Invalid margin value\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (data[2] > 0x7f) { |
| PRINTM(MERROR, |
| "Invalid ceil threshold value\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| misc->param.rx_abort_cfg_ext.enable = (t_u8)data[0]; |
| if (user_data_len > 1) { |
| misc->param.rx_abort_cfg_ext.rssi_margin = |
| (t_s8)data[1]; |
| misc->param.rx_abort_cfg_ext.ceil_rssi_threshold = |
| (t_s8)data[2]; |
| } |
| 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; |
| } |
| |
| data[0] = misc->param.rx_abort_cfg_ext.enable; |
| data[1] = misc->param.rx_abort_cfg_ext.rssi_margin; |
| data[2] = misc->param.rx_abort_cfg_ext.ceil_rssi_threshold; |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data), |
| respbuflen); |
| ret = sizeof(data); |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Enable/Disable Un-associated Dot11mc FTM Frame exchanges |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_dot11mc_unassoc_ftm_cfg(moal_private *priv, t_u8 *respbuf, |
| t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| int ret = 0; |
| int data[1] = { 0 }; |
| int header_len = 0, user_data_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (!respbuf) { |
| PRINTM(MERROR, "response buffer is not available!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_DOT11MC_UNASSOC_FTM_CFG); |
| user_data_len = strlen(respbuf) - header_len; |
| |
| /* Allocate an IOCTL request buffer */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| /* Fill request buffer */ |
| misc = (mlan_ds_misc_cfg *)req->pbuf; |
| misc->sub_command = MLAN_OID_MISC_DOT11MC_UNASSOC_FTM_CFG; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| req->action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| if (user_data_len > 1) { |
| PRINTM(MERROR, "Invalid number of args!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if ((data[0] != MTRUE) && (data[0] != MFALSE)) { |
| PRINTM(MERROR, "Invalid state for unassoc ftm\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| misc->param.dot11mc_unassoc_ftm_cfg.state = (t_u16)data[0]; |
| 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; |
| } |
| |
| data[0] = misc->param.dot11mc_unassoc_ftm_cfg.state; |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data), |
| respbuflen); |
| ret = sizeof(data); |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get Tx AMPDU protection mode |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_tx_ampdu_prot_mode(moal_private *priv, t_u8 *respbuf, |
| t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| int ret = 0; |
| int data[1] = { 0 }; |
| int header_len = 0, user_data_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (!respbuf) { |
| PRINTM(MERROR, "response buffer is not available!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TX_AMPDU_PROT_MODE); |
| user_data_len = strlen(respbuf) - header_len; |
| |
| /* Allocate an IOCTL request buffer */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| /* Fill request buffer */ |
| misc = (mlan_ds_misc_cfg *)req->pbuf; |
| misc->sub_command = MLAN_OID_MISC_TX_AMPDU_PROT_MODE; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| req->action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| if (user_data_len > 1) { |
| PRINTM(MERROR, "Invalid number of args!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (data[0] > TX_AMPDU_DYNAMIC_RTS_CTS) { |
| PRINTM(MERROR, "Invalid protection mode\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| misc->param.tx_ampdu_prot_mode.mode = (t_u16)data[0]; |
| 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; |
| } |
| |
| data[0] = misc->param.tx_ampdu_prot_mode.mode; |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data), |
| respbuflen); |
| ret = sizeof(data); |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get Tx rate adapt config |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_rate_adapt_cfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| int ret = 0; |
| int data[4] = { 0 }; |
| int header_len = 0, user_data_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (!respbuf) { |
| PRINTM(MERROR, "response buffer is not available!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_RATE_ADAPT_CFG); |
| user_data_len = strlen(respbuf) - header_len; |
| |
| /* Allocate an IOCTL request buffer */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| /* Fill request buffer */ |
| misc = (mlan_ds_misc_cfg *)req->pbuf; |
| misc->sub_command = MLAN_OID_MISC_RATE_ADAPT_CFG; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| req->action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| if (user_data_len < 1) { |
| PRINTM(MERROR, "Invalid number of args!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (data[0] > RATEADAPT_ALGO_SR) { |
| PRINTM(MERROR, "Invalid Rateadapt Algorithm\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (data[0] == RATEADAPT_ALGO_SR && user_data_len > 1) { |
| if ((data[1] & data[2]) == 0xff) { |
| /* dynamic CCA noise based rate adapation enable |
| * request nothing to do here |
| */ |
| } else if (data[1] > 100 || data[2] > 100) { |
| PRINTM(MERROR, |
| "Invalid success rate threshold value\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (data[3] < 10 || data[3] > 0xffff) { |
| PRINTM(MERROR, "Invalid interval value\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| misc->param.rate_adapt_cfg.sr_rateadapt = (t_u8)data[0]; |
| if (data[0] == RATEADAPT_ALGO_SR && user_data_len > 1) { |
| misc->param.rate_adapt_cfg.ra_low_thresh = |
| (t_u8)data[1]; |
| misc->param.rate_adapt_cfg.ra_high_thresh = |
| (t_u8)data[2]; |
| misc->param.rate_adapt_cfg.ra_interval = (t_u16)data[3]; |
| } |
| 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; |
| } |
| data[0] = misc->param.rate_adapt_cfg.sr_rateadapt; |
| data[1] = misc->param.rate_adapt_cfg.ra_low_thresh; |
| data[2] = misc->param.rate_adapt_cfg.ra_high_thresh; |
| data[3] = misc->param.rate_adapt_cfg.ra_interval; |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data), |
| respbuflen); |
| ret = sizeof(data); |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get global cck desense config |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_cck_desense_cfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| int ret = 0; |
| int data[5] = { 0 }; |
| int header_len = 0, user_data_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (!respbuf) { |
| PRINTM(MERROR, "response buffer is not available!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_CCK_DESENSE_CFG); |
| user_data_len = strlen(respbuf) - header_len; |
| |
| /* Allocate an IOCTL request buffer */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| /* Fill request buffer */ |
| misc = (mlan_ds_misc_cfg *)req->pbuf; |
| misc->sub_command = MLAN_OID_MISC_CCK_DESENSE_CFG; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| req->action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| if (user_data_len > 5) { |
| PRINTM(MERROR, "Invalid number of args!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (data[0] > CCK_DESENSE_MODE_DYN_ENH) { |
| PRINTM(MERROR, "Invalid cck desense mode\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if ((data[0] == CCK_DESENSE_MODE_DISABLED && |
| user_data_len > 1) || |
| (data[0] == CCK_DESENSE_MODE_DYNAMIC && |
| user_data_len != 3) || |
| (data[0] == CCK_DESENSE_MODE_DYN_ENH && |
| (user_data_len < 3 || user_data_len == 4))) { |
| PRINTM(MERROR, |
| "Invalid number of args for requested mode\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (user_data_len > 1) { |
| if (data[1] > 0x7f) { |
| PRINTM(MERROR, "Invalid margin value\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (data[2] > 0x7f) { |
| PRINTM(MERROR, |
| "Invalid ceil threshold value\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| if (user_data_len > 3) { |
| if (data[3] > 0xff || data[4] > 0xff) { |
| PRINTM(MERROR, |
| "Invalid ON/OFF intervals value\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| } |
| misc->param.cck_desense_cfg.mode = (t_u8)data[0]; |
| if (user_data_len > 1) { |
| misc->param.cck_desense_cfg.margin = (t_s8)data[1]; |
| misc->param.cck_desense_cfg.ceil_thresh = (t_s8)data[2]; |
| } |
| if (data[0] == CCK_DESENSE_MODE_DYN_ENH) { |
| if (user_data_len > 3) { |
| misc->param.cck_desense_cfg.num_on_intervals = |
| (t_u8)data[3]; |
| misc->param.cck_desense_cfg.num_off_intervals = |
| (t_u8)data[4]; |
| } else { |
| /* set these to 0xff. This will indicate the FW |
| * to use previously set values. |
| */ |
| misc->param.cck_desense_cfg.num_on_intervals = |
| 0xff; |
| misc->param.cck_desense_cfg.num_off_intervals = |
| 0xff; |
| } |
| } |
| 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; |
| } |
| |
| data[0] = misc->param.cck_desense_cfg.mode; |
| data[1] = misc->param.cck_desense_cfg.margin; |
| data[2] = misc->param.cck_desense_cfg.ceil_thresh; |
| data[3] = misc->param.cck_desense_cfg.num_on_intervals; |
| data[4] = misc->param.cck_desense_cfg.num_off_intervals; |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)data, sizeof(data), |
| respbuflen); |
| ret = sizeof(data); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief set/get low power mode |
| * |
| * @param priv Pointer to moal_private structure |
| * @param respbuf Pointer to response buffer |
| * @param resplen Response buffer length |
| |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_set_get_lpm(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| int ret = 0; |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_power_cfg *cfg = NULL; |
| int data = 0; |
| int user_data_len = 0, header_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (IS_CARD9098(priv->phandle->card_type) || |
| IS_CARD9097(priv->phandle->card_type)) { |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_LPM); |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, &data, 1, |
| &user_data_len); |
| } |
| if (user_data_len >= 2) { |
| PRINTM(MERROR, "Too many arguments\n"); |
| ret = -EINVAL; |
| goto done; |
| } else { |
| req = woal_alloc_mlan_ioctl_req(sizeof |
| (mlan_ds_power_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| |
| cfg = (mlan_ds_power_cfg *)req->pbuf; |
| if (user_data_len == 0) { |
| req->action = MLAN_ACT_GET; |
| } else { |
| cfg->param.lpm = data; |
| req->action = MLAN_ACT_SET; |
| } |
| } |
| cfg->sub_command = MLAN_OID_POWER_LOW_POWER_MODE; |
| req->req_id = MLAN_IOCTL_POWER_CFG; |
| |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_SUCCESS) { |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| data = cfg->param.lpm; |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u8 *)&data, |
| sizeof(data), respbuflen); |
| ret = sizeof(data); |
| } else |
| PRINTM(MERROR, "Low power mode command is not supported!\n"); |
| |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set/Get HW ARB config |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_arbcfg(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| int ret = 0; |
| int data[1]; |
| int header_len = 0, user_data_len = 0; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| |
| ENTER(); |
| |
| if (!respbuf) { |
| PRINTM(MERROR, "response buffer is not available!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_ARB_CFG); |
| user_data_len = strlen(respbuf) - header_len; |
| |
| /* Allocate an IOCTL request buffer */ |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) { |
| ret = -ENOMEM; |
| goto done; |
| } |
| /* Fill request buffer */ |
| misc = (mlan_ds_misc_cfg *)req->pbuf; |
| misc->sub_command = MLAN_OID_MISC_ARB_CONFIG; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| if ((int)strlen(respbuf) == header_len) { |
| /* GET operation */ |
| user_data_len = 0; |
| req->action = MLAN_ACT_GET; |
| } else { |
| /* SET operation */ |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| if (user_data_len != 1) { |
| PRINTM(MERROR, "Invalid Parameter\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| if (data[0] < 0 || data[0] > 4) { |
| PRINTM(MERROR, "Invalid Parameter: arb mode 0-4\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| misc->param.arb_cfg.arb_mode = (t_u32)data[0]; |
| 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; |
| } |
| |
| data[0] = misc->param.arb_cfg.arb_mode; |
| moal_memcpy_ext(priv->phandle, respbuf, (t_u32 *)data, sizeof(data), |
| respbuflen); |
| ret = sizeof(data); |
| done: |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Timer function for TP state command. |
| * |
| * @param data pointer to a buffer |
| * |
| * @return N/A |
| */ |
| void |
| woal_tp_acnt_timer_func(void *context) |
| { |
| moal_handle *phandle = (moal_handle *)context; |
| int i = 0; |
| |
| if (phandle == NULL) |
| return; |
| PRINTM(MDATA, "####### CPU%d: tp acnt timer\n", smp_processor_id()); |
| /* Tx TP accounting */ |
| for (i = 0; i < MAX_TP_ACCOUNT_DROP_POINT_NUM; i++) { |
| phandle->tp_acnt.tx_bytes_rate[i] = |
| phandle->tp_acnt.tx_bytes[i] - |
| phandle->tp_acnt.tx_bytes_last[i]; |
| phandle->tp_acnt.tx_bytes_last[i] = |
| phandle->tp_acnt.tx_bytes[i]; |
| phandle->tp_acnt.tx_packets_rate[i] = |
| phandle->tp_acnt.tx_packets[i] - |
| phandle->tp_acnt.tx_packets_last[i]; |
| phandle->tp_acnt.tx_packets_last[i] = |
| phandle->tp_acnt.tx_packets[i]; |
| } |
| phandle->tp_acnt.tx_pending = atomic_read(&phandle->tx_pending); |
| /* Tx Interrupt accounting */ |
| phandle->tp_acnt.tx_intr_rate = |
| phandle->tp_acnt.tx_intr_cnt - phandle->tp_acnt.tx_intr_last; |
| phandle->tp_acnt.tx_intr_last = phandle->tp_acnt.tx_intr_cnt; |
| |
| /* Rx TP accounting */ |
| for (i = 0; i < MAX_TP_ACCOUNT_DROP_POINT_NUM; i++) { |
| phandle->tp_acnt.rx_bytes_rate[i] = |
| phandle->tp_acnt.rx_bytes[i] - |
| phandle->tp_acnt.rx_bytes_last[i]; |
| phandle->tp_acnt.rx_bytes_last[i] = |
| phandle->tp_acnt.rx_bytes[i]; |
| phandle->tp_acnt.rx_packets_rate[i] = |
| phandle->tp_acnt.rx_packets[i] - |
| phandle->tp_acnt.rx_packets_last[i]; |
| phandle->tp_acnt.rx_packets_last[i] = |
| phandle->tp_acnt.rx_packets[i]; |
| } |
| phandle->tp_acnt.rx_pending = atomic_read(&phandle->rx_pending); |
| // Interrupt accounting, RX |
| phandle->tp_acnt.rx_intr_rate = |
| phandle->tp_acnt.rx_intr_cnt - phandle->tp_acnt.rx_intr_last; |
| phandle->tp_acnt.rx_intr_last = phandle->tp_acnt.rx_intr_cnt; |
| phandle->tp_acnt.rx_amsdu_cnt_rate = |
| phandle->tp_acnt.rx_amsdu_cnt - |
| phandle->tp_acnt.rx_amsdu_cnt_last; |
| phandle->tp_acnt.rx_amsdu_cnt_last = phandle->tp_acnt.rx_amsdu_cnt; |
| |
| phandle->tp_acnt.rx_amsdu_pkt_cnt_rate = |
| phandle->tp_acnt.rx_amsdu_pkt_cnt - |
| phandle->tp_acnt.rx_amsdu_pkt_cnt_last; |
| phandle->tp_acnt.rx_amsdu_pkt_cnt_last = |
| phandle->tp_acnt.rx_amsdu_pkt_cnt; |
| |
| phandle->tp_acnt.tx_amsdu_cnt_rate = |
| phandle->tp_acnt.tx_amsdu_cnt - |
| phandle->tp_acnt.tx_amsdu_cnt_last; |
| phandle->tp_acnt.tx_amsdu_cnt_last = phandle->tp_acnt.tx_amsdu_cnt; |
| |
| phandle->tp_acnt.tx_amsdu_pkt_cnt_rate = |
| phandle->tp_acnt.tx_amsdu_pkt_cnt - |
| phandle->tp_acnt.tx_amsdu_pkt_cnt_last; |
| phandle->tp_acnt.tx_amsdu_pkt_cnt_last = |
| phandle->tp_acnt.tx_amsdu_pkt_cnt; |
| |
| /* re-arm timer */ |
| woal_mod_timer(&phandle->tp_acnt.timer, 1000); |
| } |
| |
| /** |
| * @brief set tp state to mlan |
| * |
| * @param priv pointer to moal_private |
| * |
| * @return N/A |
| */ |
| void |
| woal_set_tp_state(moal_private *priv) |
| { |
| mlan_ioctl_req *req = NULL; |
| mlan_ds_misc_cfg *misc = NULL; |
| moal_handle *handle = priv->phandle; |
| mlan_status status = MLAN_STATUS_SUCCESS; |
| req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg)); |
| if (req == NULL) |
| return; |
| /* Fill request buffer */ |
| misc = (mlan_ds_misc_cfg *)req->pbuf; |
| misc->sub_command = MLAN_OID_MISC_TP_STATE; |
| req->req_id = MLAN_IOCTL_MISC_CFG; |
| misc->param.tp_state.on = handle->tp_acnt.on; |
| misc->param.tp_state.drop_point = handle->tp_acnt.drop_point; |
| req->action = MLAN_ACT_SET; |
| /* Send IOCTL request to MLAN */ |
| status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT); |
| if (status != MLAN_STATUS_PENDING) |
| kfree(req); |
| return; |
| } |
| |
| /** |
| * @brief Set/Get TP statistics. |
| * |
| * @param priv A pointer to moal_private structure |
| * @param respbuf A pointer to response buffer |
| * @param respbuflen Available length of response buffer |
| * |
| * @return Number of bytes written, negative for failure. |
| */ |
| static int |
| woal_priv_set_tp_state(moal_private *priv, t_u8 *respbuf, t_u32 respbuflen) |
| { |
| moal_handle *handle = priv->phandle; |
| int ret = 0; |
| int data[2]; |
| int header_len = 0, user_data_len = 0; |
| |
| ENTER(); |
| |
| if (!respbuf) { |
| PRINTM(MERROR, "response buffer is not available!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| header_len = strlen(CMD_NXP) + strlen(PRIV_CMD_TP_STATE); |
| user_data_len = strlen(respbuf) - header_len; |
| parse_arguments(respbuf + header_len, data, ARRAY_SIZE(data), |
| &user_data_len); |
| if (user_data_len > 2) { |
| PRINTM(MERROR, "Invalid number of args!\n"); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (user_data_len) { |
| handle->tp_acnt.on = data[0]; |
| /* Enable TP statistics collection */ |
| if (data[0] == 1) { |
| handle->tp_acnt.drop_point = data[1]; |
| if (handle->is_tp_acnt_timer_set == MFALSE) { |
| woal_initialize_timer(&handle->tp_acnt.timer, |
| woal_tp_acnt_timer_func, |
| handle); |
| handle->is_tp_acnt_timer_set = MTRUE; |
| woal_mod_timer(&handle->tp_acnt.timer, 1000); |
| } |
| } else { |
| if (handle->is_tp_acnt_timer_set) { |
| woal_cancel_timer(&handle->tp_acnt.timer); |
| handle->is_tp_acnt_timer_set = MFALSE; |
| } |
| memset((void *)&handle->tp_acnt, 0, |
| sizeof(moal_tp_acnt_t)); |
| } |
| woal_set_tp_state(priv); |
| } |
| /* Get command results */ |
| if (user_data_len == 0) { |
| moal_memcpy_ext(handle, respbuf, (t_u8 *)(&handle->tp_acnt), |
| sizeof(handle->tp_acnt), respbuflen); |
| ret = sizeof(handle->tp_acnt); |
| } |
| |
| done: |
| LEAVE(); |
| return ret; |
| } |
| |
| /** |
| * @brief Set priv command for Android |
| * @param dev A pointer to net_device structure |
| * @param req A pointer to ifreq structure |
| * |
| * @return 0 --success, otherwise fail |
| */ |
| int |
| woal_android_priv_cmd(struct net_device *dev, struct ifreq *req) |
| { |
| int ret = 0; |
| android_wifi_priv_cmd priv_cmd; |
| moal_private *priv = (moal_private *)netdev_priv(dev); |
| char *buf = NULL; |
| char *pdata; |
| #ifdef STA_SUPPORT |
| int power_mode = 0; |
| int band = 0; |
| char *pband = NULL; |
| mlan_bss_info bss_info; |
| mlan_ds_get_signal signal; |
| mlan_rate_cfg_t rate; |
| t_u8 country_code[COUNTRY_CODE_LEN]; |
| int copy_len = 0; |
| #endif |
| int len = 0; |
| gfp_t flag; |
| char *cmd_buf = NULL; |
| #if defined(STA_CFG80211) && defined(UAP_CFG80211) |
| int cfg80211_wext; |
| #endif |
| |
| ENTER(); |
| if (!priv || !priv->phandle) { |
| PRINTM(MERROR, "priv or handle is NULL\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| #if defined(STA_CFG80211) && defined(UAP_CFG80211) |
| cfg80211_wext = priv->phandle->params.cfg80211_wext; |
| #endif |
| if (copy_from_user(&priv_cmd, req->ifr_data, |
| sizeof(android_wifi_priv_cmd))) { |
| ret = -EFAULT; |
| goto done; |
| } |
| #define CMD_BUF_LEN 4096 |
| if (priv_cmd.used_len < 0 || priv_cmd.total_len <= 0 || |
| priv_cmd.used_len > priv_cmd.total_len) { |
| PRINTM(MERROR, |
| "Invalid Android priv cmd len. used_len: %d, total_len: %d\n", |
| priv_cmd.used_len, priv_cmd.total_len); |
| ret = -EINVAL; |
| goto done; |
| } |
| if (priv_cmd.total_len + 1 > CMD_BUF_LEN) |
| priv_cmd.total_len = CMD_BUF_LEN - 1; |
| |
| flag = (in_atomic() || irqs_disabled())? GFP_ATOMIC : GFP_KERNEL; |
| buf = kzalloc(CMD_BUF_LEN, flag); |
| if (!buf) { |
| PRINTM(MERROR, "%s: failed to allocate memory\n", __FUNCTION__); |
| ret = -ENOMEM; |
| goto done; |
| } |
| #ifdef USERSPACE_32BIT_OVER_KERNEL_64BIT |
| moal_memcpy_ext(priv->phandle, &cmd_buf, &priv_cmd.buf, sizeof(cmd_buf), |
| sizeof(cmd_buf)); |
| #else |
| cmd_buf = priv_cmd.buf; |
| #endif |
| if (copy_from_user(buf, (const void __user *)cmd_buf, |
| priv_cmd.total_len)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| buf[CMD_BUF_LEN - 1] = '\0'; |
| |
| PRINTM(MIOCTL, "Android priv cmd: [%s] on [%s]\n", buf, req->ifr_name); |
| |
| if (strncmp(buf, CMD_NXP, strlen(CMD_NXP)) && |
| woal_check_driver_status(priv->phandle)) { |
| PRINTM(MERROR, "%s fail when driver hang\n", buf); |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| if (strncmp(buf, CMD_NXP, strlen(CMD_NXP)) == 0) { |
| /* This command has come from mlanutl app */ |
| |
| /* Check command */ |
| if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_VERSION, |
| strlen(PRIV_CMD_VERSION)) == 0) { |
| /* Get version */ |
| len = woal_get_priv_driver_version(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_BANDCFG, |
| strlen(PRIV_CMD_BANDCFG)) == 0) { |
| /* Set/Get band configuration */ |
| len = woal_setget_priv_bandcfg(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HOSTCMD, |
| strlen(PRIV_CMD_HOSTCMD)) == 0) { |
| /* hostcmd configuration */ |
| len = woal_priv_hostcmd(priv, buf, priv_cmd.total_len, |
| MOAL_IOCTL_WAIT); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_11AXCMDCFG, |
| strlen(PRIV_CMD_11AXCMDCFG)) == 0) { |
| /* 11ax command */ |
| pdata = buf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_11AXCMDCFG); |
| len = priv_cmd.total_len - strlen(CMD_NXP) + |
| strlen(PRIV_CMD_11AXCMDCFG); |
| len = woal_setget_priv_11axcmdcfg(priv, pdata, len, |
| MOAL_IOCTL_WAIT); |
| len += strlen(CMD_NXP) + strlen(PRIV_CMD_11AXCMDCFG); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_RANGE_EXT, |
| strlen(PRIV_CMD_RANGE_EXT)) == 0) { |
| len = woal_setget_priv_range_ext(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HTTXCFG, |
| strlen(PRIV_CMD_HTTXCFG)) == 0) { |
| /* Set/Get HT Tx configuration */ |
| len = woal_setget_priv_httxcfg(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HTCAPINFO, |
| strlen(PRIV_CMD_HTCAPINFO)) == 0) { |
| /* Set/Get HT Capability information */ |
| len = woal_setget_priv_htcapinfo(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ADDBAPARA, |
| strlen(PRIV_CMD_ADDBAPARA)) == 0) { |
| /* Set/Get Add BA parameters */ |
| len = woal_setget_priv_addbapara(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AGGRPRIOTBL, |
| strlen(PRIV_CMD_AGGRPRIOTBL)) == 0) { |
| /* Set/Get Aggregation priority table parameters */ |
| len = woal_setget_priv_aggrpriotbl(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ADDBAREJECT, |
| strlen(PRIV_CMD_ADDBAREJECT)) == 0) { |
| /* Set/Get Add BA reject parameters */ |
| len = woal_setget_priv_addbareject(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DELBA, |
| strlen(PRIV_CMD_DELBA)) == 0) { |
| /* Delete selective BA based on parameters */ |
| len = woal_priv_delba(priv, buf, priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_REJECTADDBAREQ, |
| strlen(PRIV_CMD_REJECTADDBAREQ)) == 0) { |
| /* Set/Get the reject addba requst conditions */ |
| len = woal_priv_rejectaddbareq(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_VHTCFG, |
| strlen(PRIV_CMD_VHTCFG)) == 0) { |
| /* Set/Get 11AC configuration */ |
| len = woal_setget_priv_vhtcfg(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_OPERMODECFG, |
| strlen(PRIV_CMD_OPERMODECFG)) == 0) { |
| /* Set/Get 11AC configuration */ |
| len = woal_setget_priv_opermodecfg(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DATARATE, |
| strlen(PRIV_CMD_DATARATE)) == 0) { |
| /* Get data rate */ |
| len = woal_get_priv_datarate(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TXRATECFG, |
| strlen(PRIV_CMD_TXRATECFG)) == 0) { |
| /* Set/Get tx rate cfg */ |
| len = woal_setget_priv_txratecfg(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #if defined(STA_SUPPORT) || defined(UAP_SUPPORT) |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GETLOG, |
| strlen(PRIV_CMD_GETLOG)) == 0) { |
| /* Get wireless stats information */ |
| len = woal_get_priv_getlog(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #endif |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CUSTOMIE, |
| strlen(PRIV_CMD_CUSTOMIE)) == 0) { |
| /* Custom IE configuration */ |
| len = woal_priv_customie(priv, buf, priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ESUPPMODE, |
| strlen(PRIV_CMD_ESUPPMODE)) == 0) { |
| /* Esupplicant mode configuration */ |
| len = woal_setget_priv_esuppmode(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PASSPHRASE, |
| strlen(PRIV_CMD_PASSPHRASE)) == 0) { |
| /* Esupplicant passphrase configuration */ |
| len = woal_setget_priv_passphrase(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DEAUTH, |
| strlen(PRIV_CMD_DEAUTH)) == 0) { |
| /* Deauth */ |
| len = woal_priv_deauth(priv, buf, priv_cmd.total_len); |
| goto handled; |
| #ifdef UAP_SUPPORT |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AP_DEAUTH, |
| strlen(PRIV_CMD_AP_DEAUTH)) == 0) { |
| /* AP Deauth */ |
| len = woal_priv_ap_deauth(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_GET_STA_LIST, |
| strlen(PRIV_CMD_GET_STA_LIST)) == 0) { |
| /* Get STA list */ |
| len = woal_priv_get_sta_list(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_BSS_CONFIG, |
| strlen(PRIV_CMD_BSS_CONFIG)) == 0) { |
| /* BSS config */ |
| len = woal_priv_bss_config(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #endif |
| #ifdef WIFI_DIRECT_SUPPORT |
| #if defined(STA_SUPPORT) && defined(UAP_SUPPORT) |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_BSSROLE, |
| strlen(PRIV_CMD_BSSROLE)) == 0) { |
| /* BSS Role */ |
| len = woal_priv_bssrole(priv, buf, |
| (t_u32)priv_cmd.total_len); |
| goto handled; |
| #endif |
| #endif |
| #ifdef STA_SUPPORT |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SETUSERSCAN, |
| strlen(PRIV_CMD_SETUSERSCAN)) == 0) { |
| /* Set user scan */ |
| len = woal_priv_setuserscan(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_GETSCANTABLE, |
| strlen(PRIV_CMD_GETSCANTABLE)) == 0) { |
| /* Get scan table */ |
| len = woal_priv_getscantable(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_GETCHANSTATS, |
| strlen(PRIV_CMD_GETCHANSTATS)) == 0) { |
| /* Get channel statistics */ |
| len = woal_priv_get_chanstats(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_EXTCAPCFG, |
| strlen(PRIV_CMD_EXTCAPCFG)) == 0) { |
| /* Extended capabilities configure */ |
| len = woal_priv_extcapcfg(priv, buf, |
| (t_u32)priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CANCELSCAN, |
| strlen(PRIV_CMD_CANCELSCAN)) == 0) { |
| /* Cancel scan */ |
| len = woal_cancel_scan(priv, MOAL_IOCTL_WAIT); |
| goto handled; |
| #endif |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DEEPSLEEP, |
| strlen(PRIV_CMD_DEEPSLEEP)) == 0) { |
| /* Deep sleep */ |
| len = woal_priv_setgetdeepsleep(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_IPADDR, |
| strlen(PRIV_CMD_IPADDR)) == 0) { |
| /* IP address */ |
| len = woal_priv_setgetipaddr(priv, buf, |
| (t_u32)priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_WPSSESSION, |
| strlen(PRIV_CMD_WPSSESSION)) == 0) { |
| /* WPS Session */ |
| len = woal_priv_setwpssession(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_OTPUSERDATA, |
| strlen(PRIV_CMD_OTPUSERDATA)) == 0) { |
| /* OTP user data */ |
| len = woal_priv_otpuserdata(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_COUNTRYCODE, |
| strlen(PRIV_CMD_COUNTRYCODE)) == 0) { |
| /* Country code */ |
| len = woal_priv_set_get_countrycode(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CFPINFO, |
| strlen(PRIV_CMD_CFPINFO)) == 0) { |
| /* CFP info */ |
| len = woal_priv_get_cfpinfo(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TCPACKENH, |
| strlen(PRIV_CMD_TCPACKENH)) == 0) { |
| /* TCP ack enhancement */ |
| len = woal_priv_setgettcpackenh(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #ifdef REASSOCIATION |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ASSOCBSSID, |
| strlen(PRIV_CMD_ASSOCBSSID)) == 0) { |
| /* Associate to essid */ |
| len = woal_priv_assocessid(priv, buf, |
| priv_cmd.total_len, 1); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ASSOCESSID, |
| strlen(PRIV_CMD_ASSOCESSID)) == 0) { |
| /* Associate to essid */ |
| len = woal_priv_assocessid(priv, buf, |
| priv_cmd.total_len, 0); |
| goto handled; |
| #endif |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_WAKEUPREASON, |
| strlen(PRIV_CMD_WAKEUPREASON)) == 0) { |
| /* wakeup reason */ |
| len = woal_priv_getwakeupreason(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #ifdef STA_SUPPORT |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_LISTENINTERVAL, |
| strlen(PRIV_CMD_LISTENINTERVAL)) == 0) { |
| /* Listen Interval */ |
| len = woal_priv_set_get_listeninterval(priv, buf, |
| priv_cmd. |
| total_len); |
| goto handled; |
| #endif |
| #ifdef DEBUG_LEVEL1 |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DRVDBG, |
| strlen(PRIV_CMD_DRVDBG)) == 0) { |
| /* Driver debug bit mask */ |
| len = woal_priv_set_get_drvdbg(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #endif |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HSCFG, |
| strlen(PRIV_CMD_HSCFG)) == 0) { |
| /* HS configuration */ |
| len = woal_priv_hscfg(priv, buf, priv_cmd.total_len, |
| MTRUE); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HSSETPARA, |
| strlen(PRIV_CMD_HSSETPARA)) == 0) { |
| /* Set HS parameter */ |
| len = woal_priv_hssetpara(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MGMT_FILTER, |
| strlen(PRIV_CMD_MGMT_FILTER)) == 0) { |
| /* Management frame filter wakeup */ |
| len = woal_priv_mgmt_filter(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SCANCFG, |
| strlen(PRIV_CMD_SCANCFG)) == 0) { |
| /* Scan configuration */ |
| len = woal_priv_set_get_scancfg(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GETNLNUM, |
| strlen(PRIV_CMD_GETNLNUM)) == 0) { |
| /* Scan configuration */ |
| len = woal_priv_getnlnum(priv, buf, priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AGGRCTRL, |
| strlen(PRIV_CMD_AGGRCTRL)) == 0) { |
| /* aggregation control */ |
| len = woal_priv_set_get_aggrctrl(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #ifdef USB |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_USBAGGRCTRL, |
| strlen(PRIV_CMD_USBAGGRCTRL)) == 0) { |
| /* USB aggregation control */ |
| len = woal_priv_set_get_usbaggrctrl(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #endif |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_SET_BSS_MODE, |
| strlen(PRIV_CMD_SET_BSS_MODE)) == 0) { |
| /* Set bss mode */ |
| len = woal_priv_set_bss_mode(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #ifdef STA_SUPPORT |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SET_AP, |
| strlen(PRIV_CMD_SET_AP)) == 0) { |
| /* Set AP */ |
| len = woal_priv_set_ap(priv, buf, priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SET_POWER, |
| strlen(PRIV_CMD_SET_POWER)) == 0) { |
| /* Set power management parameters */ |
| len = woal_priv_set_power(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SET_ESSID, |
| strlen(PRIV_CMD_SET_ESSID)) == 0) { |
| /* Set essid */ |
| len = woal_priv_set_essid(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SET_AUTH, |
| strlen(PRIV_CMD_SET_AUTH)) == 0) { |
| /* Set authentication mode parameters */ |
| len = woal_priv_set_auth(priv, buf, priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GET_AP, |
| strlen(PRIV_CMD_GET_AP)) == 0) { |
| /* Get AP */ |
| len = woal_priv_get_ap(priv, buf, priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GET_POWER, |
| strlen(PRIV_CMD_GET_POWER)) == 0) { |
| /* Get power management parameters */ |
| len = woal_priv_get_power(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PSMODE, |
| strlen(PRIV_CMD_PSMODE)) == 0) { |
| /* Set/Get PS mode */ |
| len = woal_priv_set_get_psmode(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #endif |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_WARMRESET, |
| strlen(PRIV_CMD_WARMRESET)) == 0) { |
| /* Performs warm reset */ |
| len = woal_priv_warmreset(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TXPOWERCFG, |
| strlen(PRIV_CMD_TXPOWERCFG)) == 0) { |
| /* TX power configurations */ |
| len = woal_priv_txpowercfg(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_RX_ABORT_CFG_EXT, |
| strlen(PRIV_CMD_RX_ABORT_CFG_EXT)) == 0) { |
| /* dynamic Rx Abort config */ |
| len = woal_priv_rx_abort_cfg_ext(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_RX_ABORT_CFG, |
| strlen(PRIV_CMD_RX_ABORT_CFG)) == 0) { |
| /* static Rx Abort config */ |
| len = woal_priv_rx_abort_cfg(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_TX_AMPDU_PROT_MODE, |
| strlen(PRIV_CMD_TX_AMPDU_PROT_MODE)) == 0) { |
| /* tx ampdu protection mode setting */ |
| len = woal_priv_tx_ampdu_prot_mode(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_DOT11MC_UNASSOC_FTM_CFG, |
| strlen(PRIV_CMD_DOT11MC_UNASSOC_FTM_CFG)) == |
| 0) { |
| /* setting for dot11mc un-associated case FTM frame exchange */ |
| len = woal_priv_dot11mc_unassoc_ftm_cfg(priv, buf, |
| priv_cmd. |
| total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_RATE_ADAPT_CFG, |
| strlen(PRIV_CMD_RATE_ADAPT_CFG)) == 0) { |
| /* rate adapt config */ |
| len = woal_priv_rate_adapt_cfg(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_CCK_DESENSE_CFG, |
| strlen(PRIV_CMD_CCK_DESENSE_CFG)) == 0) { |
| /* cck desense config */ |
| len = woal_priv_cck_desense_cfg(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PSCFG, |
| strlen(PRIV_CMD_PSCFG)) == 0) { |
| /* PS configurations */ |
| len = woal_priv_pscfg(priv, buf, priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_BCNTIMEOUTCFG, |
| strlen(PRIV_CMD_BCNTIMEOUTCFG)) == 0) { |
| /* Beacon timeout configurations */ |
| len = woal_priv_bcntimeoutcfg(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SLEEPPD, |
| strlen(PRIV_CMD_SLEEPPD)) == 0) { |
| /* Sleep period */ |
| len = woal_priv_sleeppd(priv, buf, priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TXCONTROL, |
| strlen(PRIV_CMD_TXCONTROL)) == 0) { |
| /* Tx control */ |
| len = woal_priv_txcontrol(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_REGRDWR, |
| strlen(PRIV_CMD_REGRDWR)) == 0) { |
| /* Register Read/Write */ |
| len = woal_priv_regrdwr(priv, buf, priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_RDEEPROM, |
| strlen(PRIV_CMD_RDEEPROM)) == 0) { |
| /* Read the EEPROM contents of the card */ |
| len = woal_priv_rdeeprom(priv, buf, priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MEMRDWR, |
| strlen(PRIV_CMD_MEMRDWR)) == 0) { |
| /* Memory Read/Write */ |
| len = woal_priv_memrdwr(priv, buf, priv_cmd.total_len); |
| goto handled; |
| #ifdef SDIO |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SDCMD52RW, |
| strlen(PRIV_CMD_SDCMD52RW)) == 0) { |
| /* Cmd52 read/write register */ |
| len = woal_priv_sdcmd52rw(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SDIO_CLOCK, |
| strlen(PRIV_CMD_SDIO_CLOCK)) == 0) { |
| /* Turn on/off the sdio clock */ |
| len = woal_priv_sdio_clock_ioctl(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MPA_CTRL, |
| strlen(PRIV_CMD_MPA_CTRL)) == 0) { |
| /* Set SDIO Multi-point aggregation |
| * control parameters */ |
| len = woal_priv_sdio_mpa_ctrl(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SD_CMD53_RW, |
| strlen(PRIV_CMD_SD_CMD53_RW)) == 0) { |
| /* Cmd53 read/write register */ |
| len = woal_priv_cmd53rdwr(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #endif |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ROBUSTCOEX, |
| strlen(PRIV_CMD_ROBUSTCOEX)) == 0) { |
| /* Set Robustcoex GPIOcfg */ |
| pdata = buf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_ROBUSTCOEX); |
| len = priv_cmd.total_len - strlen(PRIV_CMD_ROBUSTCOEX) - |
| strlen(CMD_NXP); |
| len = woal_priv_robustcoex(priv, pdata, len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DMCS, |
| strlen(PRIV_CMD_DMCS)) == 0) { |
| /* Set/Get DMCS config */ |
| len = woal_priv_dmcs(priv, buf, priv_cmd.total_len); |
| goto handled; |
| #if defined(PCIE) |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SSU, |
| strlen(PRIV_CMD_SSU)) == 0) { |
| /* Set SSU config */ |
| pdata = buf + strlen(CMD_NXP) + strlen(PRIV_CMD_SSU); |
| len = priv_cmd.used_len - strlen(PRIV_CMD_SSU) - |
| strlen(CMD_NXP); |
| len = woal_priv_ssu_cmd(priv, len, pdata, |
| priv_cmd.total_len); |
| goto handled; |
| #endif |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HAL_PHY_CFG, |
| strlen(PRIV_CMD_HAL_PHY_CFG)) == 0) { |
| /* Set hal_phy config */ |
| pdata = buf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_HAL_PHY_CFG); |
| len = priv_cmd.total_len - |
| strlen(PRIV_CMD_HAL_PHY_CFG) - strlen(CMD_NXP); |
| len = woal_priv_hal_phy_cfg_cmd(priv, pdata, len); |
| goto handled; |
| #ifdef STA_SUPPORT |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ARPFILTER, |
| strlen(PRIV_CMD_ARPFILTER)) == 0) { |
| /* ARPFilter Configuration */ |
| len = woal_priv_arpfilter(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #endif |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AUTO_ARP, |
| strlen(PRIV_CMD_AUTO_ARP)) == 0) { |
| /* Auto ARP enable/disable */ |
| len = woal_priv_set_get_auto_arp(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_HOTSPOTCFG, |
| strlen(PRIV_CMD_HOTSPOTCFG)) == 0) { |
| /* Hotspot CFG */ |
| len = woal_priv_hotspotcfg(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #ifdef RX_PACKET_COALESCE |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_RX_COAL_CFG, |
| strlen(PRIV_CMD_RX_COAL_CFG)) == 0) { |
| /* RX packet coalescing Configuration */ |
| len = woal_priv_rx_pkt_coalesce_cfg(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #endif |
| |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_MGMT_FRAME_CTRL, |
| strlen(PRIV_CMD_MGMT_FRAME_CTRL)) == 0) { |
| /* Mgmt Frame Passthrough Ctrl */ |
| len = woal_priv_mgmt_frame_passthru_ctrl(priv, buf, |
| priv_cmd. |
| total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_QCONFIG, |
| strlen(PRIV_CMD_QCONFIG)) == 0) { |
| /* Queue config */ |
| len = woal_priv_qconfig(priv, buf, priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ADDTS, |
| strlen(PRIV_CMD_ADDTS)) == 0) { |
| /* Send an ADDTS TSPEC */ |
| len = woal_priv_wmm_addts_req_ioctl(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DELTS, |
| strlen(PRIV_CMD_DELTS)) == 0) { |
| /* Send a DELTS TSPE */ |
| len = woal_priv_wmm_delts_req_ioctl(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_QSTATUS, |
| strlen(PRIV_CMD_QSTATUS)) == 0) { |
| /* Get the status of the WMM queues */ |
| len = woal_priv_wmm_queue_status_ioctl(priv, buf, |
| priv_cmd. |
| total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TS_STATUS, |
| strlen(PRIV_CMD_TS_STATUS)) == 0) { |
| /* Get the status of the WMM Traffic Streams */ |
| len = woal_priv_wmm_ts_status_ioctl(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #ifdef STA_SUPPORT |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_QOS_CFG, |
| strlen(PRIV_CMD_QOS_CFG)) == 0) { |
| t_u32 action = MLAN_ACT_GET; |
| if (strlen(buf) == |
| strlen(CMD_NXP) + strlen(PRIV_CMD_QOS_CFG)) { |
| pdata = buf; /* GET operation */ |
| } else { |
| pdata = buf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_QOS_CFG); |
| action = MLAN_ACT_SET; /* SET operation */ |
| } |
| if (MLAN_STATUS_SUCCESS != |
| woal_priv_qos_cfg(priv, action, pdata)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| if (action == MLAN_ACT_GET) |
| len = sizeof(t_u8); |
| goto handled; |
| #endif |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MAC_CTRL, |
| strlen(PRIV_CMD_MAC_CTRL)) == 0) { |
| /* MAC CTRL */ |
| len = woal_priv_macctrl(priv, buf, priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GETWAP, |
| strlen(PRIV_CMD_GETWAP)) == 0) { |
| /* Get WAP */ |
| len = woal_priv_getwap(priv, buf, priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_REGION_CODE, |
| strlen(PRIV_CMD_REGION_CODE)) == 0) { |
| /* Region Code */ |
| len = woal_priv_region_code(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_FWMACADDR, |
| strlen(PRIV_CMD_FWMACADDR)) == 0) { |
| /* Set FW MAC address */ |
| len = woal_priv_fwmacaddr(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #if defined(STA_CFG80211) || defined(UAP_CFG80211) |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(2, 6, 39) |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_OFFCHANNEL, |
| strlen(PRIV_CMD_OFFCHANNEL)) == 0) { |
| if (IS_STA_CFG80211(cfg80211_wext)) { |
| /* Set offchannel */ |
| len = woal_priv_offchannel(priv, buf, |
| priv_cmd.total_len); |
| } else |
| len = sprintf(buf, |
| "CFG80211 is not enabled\n") + 1; |
| goto handled; |
| #endif |
| #endif |
| |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DSCP_MAP, |
| strlen(PRIV_CMD_DSCP_MAP)) == 0) { |
| /* Set/Get DSCP Map */ |
| len = woal_priv_set_get_dscp_map(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_VEREXT, |
| strlen(PRIV_CMD_VEREXT)) == 0) { |
| /* Get Extended version */ |
| len = woal_priv_get_driver_verext(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #ifdef USB |
| #ifdef CONFIG_USB_SUSPEND |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_USB_SUSPEND, |
| strlen(PRIV_CMD_USB_SUSPEND)) == 0) { |
| /* Makes USB device to suspend */ |
| len = woal_priv_enter_usb_suspend(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_USB_RESUME, |
| strlen(PRIV_CMD_USB_RESUME)) == 0) { |
| /* Makes USB device to resume */ |
| len = woal_priv_exit_usb_suspend(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #endif /* CONFIG_USB_SUSPEND */ |
| #endif |
| #if defined(STA_SUPPORT) && defined(STA_WEXT) |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_RADIO_CTRL, |
| strlen(PRIV_CMD_RADIO_CTRL)) == 0) { |
| /* Set/Get radio */ |
| len = woal_priv_radio_ctrl(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #endif |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_WMM_CFG, |
| strlen(PRIV_CMD_WMM_CFG)) == 0) { |
| /* Implement WMM enable command */ |
| len = woal_priv_wmm_cfg(priv, buf, priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_MIN_BA_THRESH_CFG, |
| strlen(PRIV_CMD_MIN_BA_THRESH_CFG)) == 0) { |
| /* Implement Minimum BA threshold configuration command |
| */ |
| len = woal_priv_min_ba_threshold_cfg(priv, buf, |
| priv_cmd. |
| total_len); |
| goto handled; |
| #if defined(STA_SUPPORT) |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_11D_CFG, |
| strlen(PRIV_CMD_11D_CFG)) == 0) { |
| /* Implement 802.11D enable command */ |
| len = woal_priv_11d_cfg(priv, buf, priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_11D_CLR_TBL, |
| strlen(PRIV_CMD_11D_CLR_TBL)) == 0) { |
| /* Implement 802.11D clear chan table command */ |
| len = woal_priv_11d_clr_chan_tbl(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #endif |
| #ifndef OPCHAN |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_WWS_CFG, |
| strlen(PRIV_CMD_WWS_CFG)) == 0) { |
| /* Set/Get WWS configuration */ |
| len = woal_priv_wws_cfg(priv, buf, priv_cmd.total_len); |
| goto handled; |
| #endif |
| #if defined(REASSOCIATION) |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_REASSOCTRL, |
| strlen(PRIV_CMD_REASSOCTRL)) == 0) { |
| /* Set/Get reassociation settings */ |
| len = woal_priv_set_get_reassoc(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #endif |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TXBUF_CFG, |
| strlen(PRIV_CMD_TXBUF_CFG)) == 0) { |
| /* Get Transmit buffer size */ |
| len = woal_priv_txbuf_cfg(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #ifdef STA_SUPPORT |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AUTH_TYPE, |
| strlen(PRIV_CMD_AUTH_TYPE)) == 0) { |
| /* Set/Get auth type */ |
| len = woal_priv_auth_type(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #endif |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_POWER_CONS, |
| strlen(PRIV_CMD_POWER_CONS)) == 0) { |
| /* Set/get user provisioned local power constraint */ |
| len = woal_priv_11h_local_pwr_constraint(priv, buf, |
| priv_cmd. |
| total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_HT_STREAM_CFG, |
| strlen(PRIV_CMD_HT_STREAM_CFG)) == 0) { |
| /* Set/get HT stream configurations */ |
| len = woal_priv_ht_stream_cfg(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_MIMO_SWITCH, |
| strlen(PRIV_CMD_MIMO_SWITCH)) == 0) { |
| /* Set mimo switch configurations */ |
| len = woal_priv_mimo_switch(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_THERMAL, |
| strlen(PRIV_CMD_THERMAL)) == 0) { |
| /* Get thermal reading */ |
| len = woal_priv_thermal(priv, buf, priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_BCN_INTERVAL, |
| strlen(PRIV_CMD_BCN_INTERVAL)) == 0) { |
| /* Set/Get beacon interval */ |
| len = woal_priv_beacon_interval(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #ifdef STA_SUPPORT |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_SIGNALEXT_CFG, |
| strlen(PRIV_CMD_SIGNALEXT_CFG)) == 0) { |
| /* Set signalext flag */ |
| len = woal_priv_signalext_cfg(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_GET_SIGNAL_EXT_V2, |
| strlen(PRIV_CMD_GET_SIGNAL_EXT_V2)) == 0) { |
| /* Get signal info */ |
| len = woal_priv_get_signal_ext_v2(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_GET_SIGNAL_EXT, |
| strlen(PRIV_CMD_GET_SIGNAL_EXT)) == 0) { |
| /* Get signal info */ |
| len = woal_priv_get_signal_ext(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GET_SIGNAL, |
| strlen(PRIV_CMD_GET_SIGNAL)) == 0) { |
| /* Get signal */ |
| len = woal_priv_get_signal(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #endif |
| #if defined(STA_SUPPORT) |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PMFCFG, |
| strlen(PRIV_CMD_PMFCFG)) == 0) { |
| /* Configure PMF */ |
| len = woal_priv_set_get_pmfcfg(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #endif |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_INACTIVITYTO, |
| strlen(PRIV_CMD_INACTIVITYTO)) == 0) { |
| /* Get/Set inactivity timeout extend */ |
| len = woal_priv_inactivity_timeout_ext(priv, buf, |
| priv_cmd. |
| total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_AMSDU_AGGR_CTRL, |
| strlen(PRIV_CMD_AMSDU_AGGR_CTRL)) == 0) { |
| /* Enable/Disable amsdu_aggr_ctrl */ |
| len = woal_priv_11n_amsdu_aggr_ctrl(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TX_BF_CAP, |
| strlen(PRIV_CMD_TX_BF_CAP)) == 0) { |
| /* Set/Get Transmit beamforming capabilities */ |
| len = woal_priv_tx_bf_cap_ioctl(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_SLEEP_PARAMS, |
| strlen(PRIV_CMD_SLEEP_PARAMS)) == 0) { |
| /* Configure sleep parameters */ |
| len = woal_priv_sleep_params_ioctl(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DFS_TESTING, |
| strlen(PRIV_CMD_DFS_TESTING)) == 0) { |
| /* Set/Get DFS Testing settings */ |
| len = woal_priv_dfs_testing(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DFS53_CFG, |
| strlen(PRIV_CMD_DFS53_CFG)) == 0) { |
| /* Set/Get DFS W53 settings */ |
| len = woal_priv_dfs53cfg(priv, buf, priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ARB_CFG, |
| strlen(PRIV_CMD_ARB_CFG)) == 0) { |
| /* Set/Get CFP table codes */ |
| len = woal_priv_arbcfg(priv, buf, priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CFP_CODE, |
| strlen(PRIV_CMD_CFP_CODE)) == 0) { |
| /* Set/Get CFP table codes */ |
| len = woal_priv_cfp_code(priv, buf, priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CWMODE, |
| strlen(PRIV_CMD_CWMODE)) == 0) { |
| /* Set/Get Tx CWMode */ |
| len = woal_priv_set_get_cwmode(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ANT_CFG, |
| strlen(PRIV_CMD_ANT_CFG)) == 0) { |
| /* Set/Get Tx/Rx antenna */ |
| len = woal_priv_set_get_tx_rx_ant(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_SYSCLOCK, |
| strlen(PRIV_CMD_SYSCLOCK)) == 0) { |
| /* Get/Set system clock */ |
| len = woal_priv_sysclock(priv, buf, priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_GET_KEY, |
| strlen(PRIV_CMD_GET_KEY)) == 0) { |
| /* Get GTK/PTK */ |
| len = woal_priv_get_key(priv, buf, priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_ASSOCIATE, |
| strlen(PRIV_CMD_ASSOCIATE)) == 0) { |
| /* Associate to a specific indexed entry in the |
| * ScanTable */ |
| len = woal_priv_associate_ssid_bssid(priv, buf, |
| priv_cmd. |
| total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TX_BF_CFG, |
| strlen(PRIV_CMD_TX_BF_CFG)) == 0) { |
| /* Set/Get Transmit beamforming configuration */ |
| len = woal_priv_tx_bf_cfg(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_BOOTSLEEP, |
| strlen(PRIV_CMD_BOOTSLEEP)) == 0) { |
| len = woal_priv_bootsleep(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PORT_CTRL, |
| strlen(PRIV_CMD_PORT_CTRL)) == 0) { |
| /* Set/Get Port Control mode */ |
| len = woal_priv_port_ctrl(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PB_BYPASS, |
| strlen(PRIV_CMD_PB_BYPASS)) == 0) { |
| /* Private IOCTL entry to get the By-passed TX packet |
| * from upper layer */ |
| len = woal_priv_bypassed_packet(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #ifdef WIFI_DIRECT_SUPPORT |
| #if defined(UAP_CFG80211) |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CFG_NOA, |
| strlen(PRIV_CMD_CFG_NOA)) == 0) { |
| /* Set/Get P2P NoA (Notice of Absence) parameters */ |
| len = woal_priv_cfg_noa(priv, buf, priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_CFG_OPP_PS, |
| strlen(PRIV_CMD_CFG_OPP_PS)) == 0) { |
| /* Set/Get P2P OPP-PS parameters */ |
| len = woal_priv_cfg_opp_ps(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #endif |
| #endif |
| } else if (strnicmp |
| (buf + strlen(CMD_NXP), PRIV_CMD_CFG_CLOCK_SYNC, |
| strlen(PRIV_CMD_CFG_CLOCK_SYNC)) == 0) { |
| /* Set/Get P2P NoA (Notice of Absence) parameters */ |
| len = woal_priv_cfg_clock_sync(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp |
| (buf + strlen(CMD_NXP), PRIV_CMD_CFG_GET_TSF_INFO, |
| strlen(PRIV_CMD_CFG_GET_TSF_INFO)) == 0) { |
| /* Get TSF info */ |
| len = woal_priv_cfg_get_tsf_info(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp |
| (buf + strlen(CMD_NXP), PRIV_CMD_TRANSITION_CHANNEL, |
| strlen(PRIV_CMD_TRANSITION_CHANNEL)) == 0) { |
| /* Get/Set Transition channel */ |
| len = woal_priv_transition_channel(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_DFS_REPEATER_CFG, |
| strlen(PRIV_CMD_DFS_REPEATER_CFG)) == 0) { |
| /* Set/Get DFS_REPEATER mode */ |
| len = woal_priv_dfs_repeater_cfg(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #ifdef WIFI_DIRECT_SUPPORT |
| #if defined(STA_CFG80211) || defined(UAP_CFG80211) |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_MIRACAST_CFG, |
| strlen(PRIV_CMD_MIRACAST_CFG)) == 0) { |
| /* Set/Get MIRACAST configuration parameters */ |
| len = woal_priv_miracast_cfg(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #endif |
| #endif |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_COEX_RX_WINSIZE, |
| strlen(PRIV_CMD_COEX_RX_WINSIZE)) == 0) { |
| /* Set/Get control to coex RX window size */ |
| len = woal_priv_coex_rx_winsize(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_TX_AGGR_CTRL, |
| strlen(PRIV_CMD_TX_AGGR_CTRL)) == 0) { |
| /* Set/Get control to TX AMPDU on infra link */ |
| len = woal_priv_txaggrctrl(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_AUTO_TDLS, |
| strlen(PRIV_CMD_AUTO_TDLS)) == 0) { |
| /* Set/Get control to enable/disable auto TDLS */ |
| len = woal_priv_auto_tdls(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #ifdef PCIE |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PCIE_REG_RW, |
| strlen(PRIV_CMD_PCIE_REG_RW)) == 0) { |
| /* Read/Write PCIE register */ |
| len = woal_priv_pcie_reg_rw(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_PCIE_BAR0_REG_RW, |
| strlen(PRIV_CMD_PCIE_BAR0_REG_RW)) == 0) { |
| /* Read/Write PCIE register/memory from BAR0 */ |
| len = woal_priv_pcie_bar0_reg_rw(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #endif |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_TDLS_IDLE_TIME, |
| strlen(PRIV_CMD_TDLS_IDLE_TIME)) == 0) { |
| /* Set/Get TDLS idle timeout value */ |
| len = woal_priv_tdls_idle_time(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_GET_SENSOR_TEMP, |
| strlen(PRIV_CMD_GET_SENSOR_TEMP)) == 0) { |
| /* Get SOC temperature */ |
| len = woal_priv_get_sensor_temp(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) |
| #if defined(STA_CFG80211) || defined(UAP_CFG80211) |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DFS_OFFLOAD, |
| strlen(PRIV_CMD_DFS_OFFLOAD)) == 0) { |
| /* Enable/disable DFS offload */ |
| if (IS_STA_OR_UAP_CFG80211(cfg80211_wext)) |
| len = woal_priv_dfs_offload_enable(priv, buf, |
| priv_cmd. |
| total_len); |
| else |
| len = sprintf(buf, |
| "CFG80211 is not enabled\n") + 1; |
| goto handled; |
| #endif |
| #endif |
| #if defined(UAP_SUPPORT) |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_EXTEND_CHAN_SWITCH, |
| strlen(PRIV_CMD_EXTEND_CHAN_SWITCH)) == 0) { |
| /* Extended channel switch */ |
| len = woal_priv_extend_channel_switch(priv, buf, |
| priv_cmd. |
| total_len); |
| goto handled; |
| #endif |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DYN_BW, |
| strlen(PRIV_CMD_DYN_BW)) == 0) { |
| /* Set/Get dynamic bandwidth */ |
| len = woal_priv_config_dyn_bw(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_IND_RST_CFG, |
| strlen(PRIV_CMD_IND_RST_CFG)) == 0) { |
| /* Set/Get out band independent reset */ |
| len = woal_priv_ind_rst_cfg(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_PER_PKT_CFG, |
| strlen(PRIV_CMD_PER_PKT_CFG)) == 0) { |
| /* Get/Set per packet Txctl and Rxinfo configuration */ |
| len = woal_priv_per_pkt_cfg(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_DEAUTH_CTRL, |
| strlen(PRIV_CMD_DEAUTH_CTRL)) == 0) { |
| len = woal_priv_deauth_ctrl(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_11AXCFG, |
| strlen(PRIV_CMD_11AXCFG)) == 0) { |
| pdata = buf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_11AXCFG); |
| len = priv_cmd.used_len - strlen(PRIV_CMD_11AXCFG) - |
| strlen(CMD_NXP); |
| len = woal_priv_11axcfg_cmd(priv, pdata, len, |
| priv_cmd.total_len); |
| len += strlen(PRIV_CMD_11AXCFG) + strlen(CMD_NXP); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TWT_SETUP, |
| strlen(PRIV_CMD_TWT_SETUP)) == 0) { |
| pdata = buf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_TWT_SETUP); |
| len = priv_cmd.used_len - strlen(PRIV_CMD_TWT_SETUP) - |
| strlen(CMD_NXP); |
| len = woal_priv_twt_setup(priv, pdata, len, |
| priv_cmd.total_len); |
| len += strlen(PRIV_CMD_TWT_SETUP) + strlen(CMD_NXP); |
| goto handled; |
| |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_TWT_TEARDOWN, |
| strlen(PRIV_CMD_TWT_TEARDOWN)) == 0) { |
| pdata = buf + strlen(CMD_NXP) + |
| strlen(PRIV_CMD_TWT_TEARDOWN); |
| len = priv_cmd.used_len - |
| strlen(PRIV_CMD_TWT_TEARDOWN) - strlen(CMD_NXP); |
| len = woal_priv_twt_teardown(priv, pdata, len, |
| priv_cmd.total_len); |
| len += strlen(PRIV_CMD_TWT_TEARDOWN) + strlen(CMD_NXP); |
| goto handled; |
| #if defined(STA_CFG80211) || defined(UAP_CFG80211) |
| } else if (strnicmp(buf + strlen(CMD_NXP), |
| PRIV_CMD_GET_CFG_CHAN_LIST, |
| strlen(PRIV_CMD_GET_CFG_CHAN_LIST)) == 0) { |
| /* Get txpwrlimit */ |
| if (IS_STA_OR_UAP_CFG80211(cfg80211_wext)) |
| len = woal_priv_getcfgchanlist(priv, buf, |
| priv_cmd. |
| total_len); |
| else |
| len = sprintf(buf, |
| "CFG80211 is not enabled\n") + 1; |
| goto handled; |
| #endif |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_LPM, |
| strlen(PRIV_CMD_LPM)) == 0) { |
| /* Set/Get low power mode */ |
| len = woal_priv_set_get_lpm(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf + strlen(CMD_NXP), PRIV_CMD_TP_STATE, |
| strlen(PRIV_CMD_TP_STATE)) == 0) { |
| /* Set/Get TP accounting state */ |
| len = woal_priv_set_tp_state(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else { |
| PRINTM(MERROR, |
| "Unknown NXP PRIVATE command %s, ignored\n", |
| buf); |
| ret = -EFAULT; |
| goto done; |
| } |
| } |
| #ifdef STA_SUPPORT |
| if (strncmp(buf, "RSSILOW-THRESHOLD", strlen("RSSILOW-THRESHOLD")) == 0) { |
| pdata = buf + strlen("RSSILOW-THRESHOLD") + 1; |
| if (MLAN_STATUS_SUCCESS != |
| woal_set_rssi_low_threshold(priv, pdata, MOAL_IOCTL_WAIT)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strncmp(buf, "SCAN-CFG", strlen("SCAN-CFG")) == 0) { |
| PRINTM(MIOCTL, "Set SCAN CFG\n"); |
| if (MLAN_STATUS_SUCCESS != |
| woal_set_scan_cfg(priv, buf, priv_cmd.total_len)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strncmp(buf, "RSSI", strlen("RSSI")) == 0) { |
| if (MLAN_STATUS_SUCCESS != |
| woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| if (bss_info.media_connected) { |
| if (MLAN_STATUS_SUCCESS != |
| woal_get_signal_info(priv, MOAL_IOCTL_WAIT, |
| &signal)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| len = sprintf(buf, "%.32s rssi %d\n", |
| bss_info.ssid.ssid, signal.bcn_rssi_avg) + |
| 1; |
| } else { |
| len = sprintf(buf, "OK\n") + 1; |
| } |
| } else if (strncmp(buf, "LINKSPEED", strlen("LINKSPEED")) == 0) { |
| if (MLAN_STATUS_SUCCESS != |
| woal_set_get_data_rate(priv, MLAN_ACT_GET, &rate)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| PRINTM(MIOCTL, "tx rate=%d\n", (int)rate.rate); |
| len = sprintf(buf, "LinkSpeed %d\n", |
| (int)(rate.rate * 500000 / 1000000)) + 1; |
| } else |
| #endif |
| if (strncmp(buf, "MACADDR", strlen("MACADDR")) == 0) { |
| len = sprintf(buf, "Macaddr = %02X:%02X:%02X:%02X:%02X:%02X\n", |
| priv->current_addr[0], priv->current_addr[1], |
| priv->current_addr[2], priv->current_addr[3], |
| priv->current_addr[4], priv->current_addr[5]) + 1; |
| } |
| #ifdef STA_SUPPORT |
| else if (strncmp(buf, "GETPOWER", strlen("GETPOWER")) == 0) { |
| if (MLAN_STATUS_SUCCESS != |
| woal_get_powermode(priv, &power_mode)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| len = sprintf(buf, "powermode = %d\n", power_mode) + 1; |
| } else if (strncmp(buf, "SCAN-ACTIVE", strlen("SCAN-ACTIVE")) == 0) { |
| if (MLAN_STATUS_SUCCESS != |
| woal_set_scan_type(priv, MLAN_SCAN_TYPE_ACTIVE)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| priv->scan_type = MLAN_SCAN_TYPE_ACTIVE; |
| PRINTM(MIOCTL, "Set Active Scan\n"); |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strncmp(buf, "SCAN-PASSIVE", strlen("SCAN-PASSIVE")) == 0) { |
| if (MLAN_STATUS_SUCCESS != |
| woal_set_scan_type(priv, MLAN_SCAN_TYPE_PASSIVE)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| priv->scan_type = MLAN_SCAN_TYPE_PASSIVE; |
| PRINTM(MIOCTL, "Set Passive Scan\n"); |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strncmp(buf, "POWERMODE", strlen("POWERMODE")) == 0) { |
| pdata = buf + strlen("POWERMODE") + 1; |
| if (!moal_extflg_isset(priv->phandle, EXT_HW_TEST)) { |
| if (MLAN_STATUS_SUCCESS != |
| woal_set_powermode(priv, pdata)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| } |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strncmp(buf, "SETROAMING", strlen("SETROAMING")) == 0) { |
| pdata = buf + strlen("SETROAMING") + 1; |
| #ifdef STA_CFG80211 |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) |
| if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME)) |
| goto done; |
| #endif |
| #endif |
| #ifdef STA_CFG80211 |
| if (*pdata == '1') { |
| priv->roaming_enabled = MTRUE; |
| PRINTM(MIOCTL, "Roaming enabled\n"); |
| } else if (*pdata == '0') { |
| priv->roaming_enabled = MFALSE; |
| PRINTM(MIOCTL, "Roaming disabled\n"); |
| } |
| #endif |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strncmp(buf, "ROAM", strlen("ROAM")) == 0) { |
| pdata = buf + strlen("ROAM") + 1; |
| #ifdef STA_CFG80211 |
| #if CFG80211_VERSION_CODE >= KERNEL_VERSION(3, 8, 0) |
| if (moal_extflg_isset(priv->phandle, EXT_HOST_MLME)) |
| goto done; |
| #endif |
| #endif |
| #ifdef STA_CFG80211 |
| if (*pdata == '1') { |
| priv->roaming_enabled = MTRUE; |
| PRINTM(MIOCTL, "Roaming enabled\n"); |
| } else if (*pdata == '0') { |
| priv->roaming_enabled = MFALSE; |
| PRINTM(MIOCTL, "Roaming disabled\n"); |
| } |
| #endif |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strncmp(buf, "COUNTRY", strlen("COUNTRY")) == 0) { |
| copy_len = strlen(buf) - strlen("COUNTRY") - 1; |
| if (copy_len > COUNTRY_CODE_LEN || copy_len <= 0) { |
| PRINTM(MERROR, "Invalid country length\n"); |
| ret = -EFAULT; |
| goto done; |
| } |
| memset(country_code, 0, sizeof(country_code)); |
| moal_memcpy_ext(priv->phandle, country_code, |
| buf + strlen("COUNTRY") + 1, copy_len, |
| COUNTRY_CODE_LEN); |
| PRINTM(MIOCTL, "Set COUNTRY %s\n", country_code); |
| if (priv->phandle->params.cntry_txpwr) { |
| if (MLAN_STATUS_SUCCESS != |
| woal_request_country_power_table(priv, |
| country_code)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| } |
| #ifdef STA_CFG80211 |
| if (IS_STA_CFG80211(cfg80211_wext)) { |
| PRINTM(MIOCTL, "Notify country code=%s\n", |
| country_code); |
| if (!moal_extflg_isset(priv->phandle, |
| EXT_DISABLE_REGD_BY_DRIVER)) |
| regulatory_hint(priv->wdev->wiphy, |
| country_code); |
| len = sprintf(buf, "OK\n") + 1; |
| goto done; |
| } |
| #endif |
| if (MLAN_STATUS_SUCCESS != |
| woal_set_region_code(priv, country_code)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (memcmp(buf, WEXT_CSCAN_HEADER, WEXT_CSCAN_HEADER_SIZE) == 0) { |
| PRINTM(MIOCTL, "Set Combo Scan\n"); |
| if (MLAN_STATUS_SUCCESS != |
| woal_set_combo_scan(priv, buf, priv_cmd.total_len)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strncmp(buf, "GETBAND", strlen("GETBAND")) == 0) { |
| if (MLAN_STATUS_SUCCESS != woal_get_band(priv, &band)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| len = sprintf(buf, "Band %d\n", band) + 1; |
| } else if (strncmp(buf, "SETBAND", strlen("SETBAND")) == 0) { |
| pband = buf + strlen("SETBAND") + 1; |
| if (MLAN_STATUS_SUCCESS != woal_set_band(priv, pband)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| len = sprintf(buf, "OK\n") + 1; |
| } |
| #endif |
| else if (strncmp(buf, "START", strlen("START")) == 0) { |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strncmp(buf, "STOP", strlen("STOP")) == 0) { |
| len = sprintf(buf, "OK\n") + 1; |
| } |
| #ifdef UAP_SUPPORT |
| else if (strncmp(buf, "AP_BSS_START", strlen("AP_BSS_START")) == 0) { |
| ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START); |
| if (ret) |
| goto done; |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strncmp(buf, "AP_BSS_STOP", strlen("AP_BSS_STOP")) == 0) { |
| ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP); |
| if (ret) |
| goto done; |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strncmp(buf, "AP_SET_CFG", strlen("AP_SET_CFG")) == 0) { |
| if (priv_cmd.total_len <= (int)strlen("AP_SET_CFG") + 1) |
| goto done; |
| pdata = buf + strlen("AP_SET_CFG") + 1; |
| ret = woal_uap_set_ap_cfg(priv, pdata, |
| priv_cmd.total_len - |
| strlen("AP_SET_CFG") - 1); |
| if (ret) |
| goto done; |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strncmp(buf, "WL_FW_RELOAD", strlen("WL_FW_RELOAD")) == 0) { |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strncmp(buf, "AP_GET_STA_LIST", strlen("AP_GET_STA_LIST")) == |
| 0) { |
| /* TODO Add STA list support */ |
| len = sprintf(buf, "OK\n") + 1; |
| } |
| #endif |
| else if (strncmp(buf, "SETSUSPENDOPT", strlen("SETSUSPENDOPT")) == 0) { |
| /* it will be done by GUI */ |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strncmp(buf, "SETSUSPENDMODE", strlen("SETSUSPENDMODE")) == |
| 0) { |
| /* it will be done by GUI */ |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strncmp(buf, "BTCOEXMODE", strlen("BTCOEXMODE")) == 0) { |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strncmp(buf, "BTCOEXSCAN-START", |
| strlen("BTCOEXSCAN-START")) == 0) { |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strncmp(buf, "BTCOEXSCAN-STOP", strlen("BTCOEXSCAN-STOP")) == |
| 0) { |
| len = sprintf(buf, "OK\n") + 1; |
| } |
| #ifdef STA_SUPPORT |
| else if (strncmp(buf, "BGSCAN-START", strlen("BGSCAN-START")) == 0) { |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strncmp(buf, "BGSCAN-CONFIG", strlen("BGSCAN-CONFIG")) == 0) { |
| if (MLAN_STATUS_SUCCESS != |
| woal_set_bg_scan(priv, buf, priv_cmd.total_len)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| priv->bg_scan_start = MTRUE; |
| priv->bg_scan_reported = MFALSE; |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strncmp(buf, "BGSCAN-STOP", strlen("BGSCAN-STOP")) == 0) { |
| if (priv->bg_scan_start && !priv->scan_cfg.rssi_threshold) { |
| if (MLAN_STATUS_SUCCESS != |
| woal_stop_bg_scan(priv, MOAL_NO_WAIT)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| priv->bg_scan_start = MFALSE; |
| priv->bg_scan_reported = MFALSE; |
| } |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strncmp(buf, "RXFILTER-START", strlen("RXFILTER-START")) == |
| 0) { |
| #ifdef MEF_CFG_RX_FILTER |
| ret = woal_set_rxfilter(priv, MTRUE); |
| if (ret) |
| goto done; |
| #endif |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strncmp(buf, "RXFILTER-STOP", strlen("RXFILTER-STOP")) == 0) { |
| #ifdef MEF_CFG_RX_FILTER |
| ret = woal_set_rxfilter(priv, MFALSE); |
| if (ret) |
| goto done; |
| #endif |
| len = sprintf(buf, "OK\n") + 1; |
| } |
| #ifdef STA_CFG80211 |
| else if (strncmp(buf, "GET_EVENT", strlen("GET_EVENT")) == 0) { |
| if (IS_STA_CFG80211(cfg80211_wext)) { |
| if (priv->last_event & EVENT_BG_SCAN_REPORT) |
| woal_inform_bss_from_scan_result(priv, NULL, |
| MOAL_IOCTL_WAIT); |
| } |
| len = sprintf(buf, "EVENT=%d\n", priv->last_event) + 1; |
| priv->last_event = 0; |
| } else if (strncmp(buf, "GET_802_11W", strlen("GET_802_11W")) == 0) { |
| len = sprintf(buf, "802_11W=ENABLED\n") + 1; |
| } |
| #endif /* STA_CFG80211 */ |
| else if (strncmp(buf, "RXFILTER-ADD", strlen("RXFILTER-ADD")) == 0) { |
| pdata = buf + strlen("RXFILTER-ADD") + 1; |
| if (MLAN_STATUS_SUCCESS != woal_add_rxfilter(priv, pdata)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strncmp(buf, "RXFILTER-REMOVE", strlen("RXFILTER-REMOVE")) == |
| 0) { |
| pdata = buf + strlen("RXFILTER-REMOVE") + 1; |
| if (MLAN_STATUS_SUCCESS != woal_remove_rxfilter(priv, pdata)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strncmp(buf, "QOSINFO", strlen("QOSINFO")) == 0) { |
| pdata = buf + strlen("QOSINFO") + 1; |
| #ifdef STA_SUPPORT |
| if (MLAN_STATUS_SUCCESS != |
| woal_priv_qos_cfg(priv, MLAN_ACT_SET, pdata)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| #endif |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strncmp(buf, "SLEEPPD", strlen("SLEEPPD")) == 0) { |
| pdata = buf + strlen("SLEEPPD") + 1; |
| if (MLAN_STATUS_SUCCESS != woal_set_sleeppd(priv, pdata)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strncmp(buf, "SET_AP_WPS_P2P_IE", |
| strlen("SET_AP_WPS_P2P_IE")) == 0) { |
| pdata = buf + strlen("SET_AP_WPS_P2P_IE") + 1; |
| /* Android cmd format: |
| * "SET_AP_WPS_P2P_IE 1" -- beacon IE |
| * "SET_AP_WPS_P2P_IE 2" -- proberesp IE |
| * "SET_AP_WPS_P2P_IE 4" -- assocresp IE |
| */ |
| #if defined(STA_CFG80211) && defined(UAP_CFG80211) |
| #if CFG80211_VERSION_CODE < KERNEL_VERSION(3, 2, 0) |
| if (MLAN_STATUS_SUCCESS != |
| woal_set_ap_wps_p2p_ie(priv, (t_u8 *)pdata, |
| priv_cmd.used_len - |
| strlen("SET_AP_WPS_P2P_IE") - 1)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| #endif |
| #endif |
| len = sprintf(buf, "OK\n") + 1; |
| } |
| #endif |
| else if (strncmp(buf, "P2P_DEV_ADDR", strlen("P2P_DEV_ADDR")) == 0) { |
| memset(buf, 0x0, (size_t) priv_cmd.total_len); |
| moal_memcpy_ext(priv->phandle, buf, priv->current_addr, |
| ETH_ALEN, (t_u32)priv_cmd.total_len); |
| len = ETH_ALEN; |
| } else if (strncmp(buf, ("P2P_GET_NOA"), strlen("P2P_GET_NOA")) == 0) { |
| /* TODO |
| * Just return '\0' |
| */ |
| memset(buf, 0x0, (size_t) priv_cmd.total_len); |
| *buf = 0; |
| len = 1; |
| } else if (strnicmp(buf, "MIRACAST", strlen("MIRACAST")) == 0) { |
| pdata = buf + strlen("MIRACAST"); |
| /* Android cmd format: |
| * "MIRACAST 0" -- disabled |
| * "MIRACAST 1" -- operating as source |
| * "MIRACAST 2" -- operating as sink |
| */ |
| #ifdef WIFI_DIRECT_SUPPORT |
| #if defined(STA_CFG80211) || defined(UAP_CFG80211) |
| if (MLAN_STATUS_SUCCESS != |
| woal_set_miracast_mode(priv, (t_u8 *)pdata, |
| priv_cmd.used_len - |
| strlen("MIRACAST"))) { |
| ret = -EFAULT; |
| goto done; |
| } |
| #endif |
| #endif |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strnicmp(buf, "SCAN_TIMING", strlen("SCAN_TIMING")) == 0) { |
| #ifdef WIFI_DIRECT_SUPPORT |
| #if defined(STA_CFG80211) || defined(UAP_CFG80211) |
| if (MLAN_STATUS_SUCCESS != |
| woal_set_scan_chan_gap(priv, buf, priv_cmd.total_len)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| #endif |
| #endif |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strnicmp(buf, "BA_WSIZE_RX", strlen("BA_WSIZE_RX")) == 0) { |
| pdata = buf + strlen("BA_WSIZE_RX") + 1; |
| len = priv_cmd.total_len - strlen("BA_WSIZE_RX") - 1; |
| if (MLAN_STATUS_SUCCESS != |
| woal_set_rx_ba_winsize(priv, pdata, len)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strnicmp(buf, "BA_WSIZE_TX", strlen("BA_WSIZE_TX")) == 0) { |
| pdata = buf + strlen("BA_WSIZE_TX") + 1; |
| len = priv_cmd.total_len - strlen("BA_WSIZE_TX") - 1; |
| if (MLAN_STATUS_SUCCESS != |
| woal_set_tx_ba_winsize(priv, pdata, len)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strncmp(buf, "FAKE_SCAN_COMPLETE", |
| strlen("FAKE_SCAN_COMPLETE")) == 0) { |
| pdata = buf + strlen("FAKE_SCAN_COMPLETE") + 1; |
| #ifdef STA_CFG80211 |
| if (*pdata == '1') { |
| priv->fake_scan_complete = MTRUE; |
| PRINTM(MIOCTL, "fake scan complete enabled\n"); |
| } else if (*pdata == '0') { |
| priv->fake_scan_complete = MFALSE; |
| PRINTM(MIOCTL, "fake scan complete disabled\n"); |
| } |
| #endif |
| len = sprintf(buf, "OK\n") + 1; |
| } |
| #if defined(STA_CFG80211) || defined(UAP_CFG80211) |
| #ifdef WIFI_DIRECT_SUPPORT |
| else if (strncmp(buf, "P2P_PERIODIC_SLEEP", |
| strlen("P2P_PERIODIC_SLEEP")) == 0) { |
| if (MLAN_STATUS_SUCCESS != |
| woal_p2p_ps_cfg(priv, buf, priv_cmd.total_len)) { |
| ret = -EFAULT; |
| goto done; |
| } |
| len = sprintf(buf, "OK\n") + 1; |
| } |
| #endif |
| #endif |
| else if (strncmp(buf, "WLS_BATCHING", strlen("WLS_BATCHING")) == 0) { |
| /* TODO */ |
| len = sprintf(buf, "OK\n") + 1; |
| } else if (strncmp(buf, "TDLS_CS_CHAN", strlen("TDLS_CS_CHAN")) == 0) { |
| len = woal_priv_tdls_cs_chan(priv, buf, priv_cmd.total_len); |
| } |
| #if defined(UAP_SUPPORT) |
| else if (strncmp(buf, "P2P_ECSA", strlen("P2P_ECSA")) == 0) { |
| len = woal_priv_p2p_ecsa(priv, buf, priv_cmd.total_len); |
| } |
| #endif |
| else if (strncmp(buf, "FAKEMAC", strlen("FAKEMAC")) == 0) { |
| len = woal_priv_config_random_mac(priv, buf, |
| priv_cmd.total_len); |
| } else if (strncmp(buf, PRIV_CMD_CLOUD_KEEP_ALIVE, |
| strlen(PRIV_CMD_CLOUD_KEEP_ALIVE)) == 0) { |
| len = woal_priv_cloud_keep_alive(priv, buf, priv_cmd.total_len); |
| } else if (strnicmp(buf, PRIV_CMD_TX_RX_HISTOGRAM, |
| strlen(PRIV_CMD_TX_RX_HISTOGRAM)) == 0) { |
| /* Get TX/RX histogram statistic */ |
| len = woal_priv_get_rx_tx_histogram(priv, buf, |
| priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf, PRIV_CMD_GET_CHNRGPWR, |
| strlen(PRIV_CMD_GET_CHNRGPWR)) == 0) { |
| /* Get chnrgpwr */ |
| len = woal_priv_get_chnrgpwr(priv, buf, priv_cmd.total_len); |
| goto handled; |
| } else if (strnicmp(buf, PRIV_CMD_GET_TXPWR_LIMIT, |
| strlen(PRIV_CMD_GET_TXPWR_LIMIT)) == 0) { |
| /* Get txpwrlimit */ |
| len = woal_priv_get_txpwrlimit(priv, buf, priv_cmd.total_len); |
| goto handled; |
| } else { |
| PRINTM(MIOCTL, "Unknown PRIVATE command: %s, ignored\n", buf); |
| ret = -EFAULT; |
| goto done; |
| } |
| |
| handled: |
| PRINTM(MIOCTL, "PRIV Command return: %s, length=%d\n", buf, len); |
| |
| if (len > 0) { |
| priv_cmd.used_len = len; |
| if (priv_cmd.used_len <= priv_cmd.total_len) { |
| memset(buf + priv_cmd.used_len, 0, |
| (size_t) (CMD_BUF_LEN - priv_cmd.used_len)); |
| if (copy_to_user((void __user *)cmd_buf, buf, |
| priv_cmd.total_len)) { |
| PRINTM(MERROR, |
| "%s: failed to copy data to user buffer\n", |
| __FUNCTION__); |
| ret = -EFAULT; |
| goto done; |
| } |
| if (copy_to_user(req->ifr_data, &priv_cmd, |
| sizeof(android_wifi_priv_cmd))) { |
| PRINTM(MERROR, |
| "%s: failed to copy command header to user buffer\n", |
| __FUNCTION__); |
| ret = -EFAULT; |
| } |
| } else { |
| PRINTM(MERROR, |
| "%s: the buffer supplied by appl is too small (supplied: %d, used: %d)\n", |
| __FUNCTION__, priv_cmd.total_len, |
| priv_cmd.used_len); |
| ret = -EFAULT; |
| } |
| } else { |
| ret = len; |
| } |
| |
| done: |
| kfree(buf); |
| LEAVE(); |
| return ret; |
| } |
| |
| /******************************************************** |
| Global Functions |
| ********************************************************/ |
| /** |
| * @brief Create a brief scan resp to relay basic BSS info to the app layer |
| * |
| * When the beacon/probe response has not been buffered, use the saved BSS |
| * information available to provide a minimum response for the application |
| * ioctl retrieval routines. Include: |
| * - Timestamp |
| * - Beacon Period |
| * - Capabilities (including WMM Element if available) |
| * - SSID |
| * |
| * @param ppbuffer Output parameter: Buffer used to create basic scan rsp |
| * @param pbss_desc Pointer to a BSS entry in the scan table to create |
| * scan response from for delivery to the application layer |
| * |
| * @return N/A |
| */ |
| void |
| wlan_scan_create_brief_table_entry(t_u8 **ppbuffer, BSSDescriptor_t *pbss_desc) |
| { |
| t_u8 *ptmp_buf = *ppbuffer; |
| t_u8 tmp_ssid_hdr[2]; |
| t_u8 ie_len = 0; |
| |
| ENTER(); |
| |
| moal_memcpy_ext(NULL, ptmp_buf, pbss_desc->time_stamp, |
| sizeof(pbss_desc->time_stamp), |
| sizeof(pbss_desc->time_stamp)); |
| ptmp_buf += sizeof(pbss_desc->time_stamp); |
| |
| moal_memcpy_ext(NULL, ptmp_buf, &pbss_desc->beacon_period, |
| sizeof(pbss_desc->beacon_period), |
| sizeof(pbss_desc->beacon_period)); |
| ptmp_buf += sizeof(pbss_desc->beacon_period); |
| |
| moal_memcpy_ext(NULL, ptmp_buf, &pbss_desc->cap_info, |
| sizeof(pbss_desc->cap_info), |
| sizeof(pbss_desc->cap_info)); |
| ptmp_buf += sizeof(pbss_desc->cap_info); |
| |
| tmp_ssid_hdr[0] = 0; /* Element ID for SSID is zero */ |
| tmp_ssid_hdr[1] = pbss_desc->ssid.ssid_len; |
| moal_memcpy_ext(NULL, ptmp_buf, tmp_ssid_hdr, sizeof(tmp_ssid_hdr), |
| sizeof(tmp_ssid_hdr)); |
| ptmp_buf += sizeof(tmp_ssid_hdr); |
| |
| moal_memcpy_ext(NULL, ptmp_buf, pbss_desc->ssid.ssid, |
| pbss_desc->ssid.ssid_len, pbss_desc->ssid.ssid_len); |
| ptmp_buf += pbss_desc->ssid.ssid_len; |
| |
| if (pbss_desc->wmm_ie.vend_hdr.element_id == WMM_IE) { |
| ie_len = sizeof(IEEEtypes_Header_t) + |
| pbss_desc->wmm_ie.vend_hdr.len; |
| moal_memcpy_ext(NULL, ptmp_buf, &pbss_desc->wmm_ie, ie_len, |
| ie_len); |
| ptmp_buf += ie_len; |
| } |
| |
| if (pbss_desc->pwpa_ie) { |
| if ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == WPA_IE) { |
| ie_len = sizeof(IEEEtypes_Header_t) + |
| (*(pbss_desc->pwpa_ie)).vend_hdr.len; |
| moal_memcpy_ext(NULL, ptmp_buf, pbss_desc->pwpa_ie, |
| ie_len, ie_len); |
| } |
| |
| ptmp_buf += ie_len; |
| } |
| if (pbss_desc->prsn_ie) { |
| if ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == RSN_IE) { |
| ie_len = sizeof(IEEEtypes_Header_t) + |
| (*(pbss_desc->prsn_ie)).ieee_hdr.len; |
| moal_memcpy_ext(NULL, ptmp_buf, pbss_desc->prsn_ie, |
| ie_len, ie_len); |
| } |
| |
| ptmp_buf += ie_len; |
| } |
| *ppbuffer = ptmp_buf; |
| LEAVE(); |
| } |
| |
| /** |
| * @brief Create a wlan_ioctl_get_scan_table_entry for a given BSS |
| * Descriptor for inclusion in the ioctl response to the user space |
| * application. |
| * |
| * |
| * @param pbss_desc Pointer to a BSS entry in the scan table to form |
| * scan response from for delivery to the application layer |
| * @param ppbuffer Output parameter: Buffer used to output scan return |
| * struct |
| * @param pspace_left Output parameter: Number of bytes available in the |
| * response buffer. |
| * |
| * @return MLAN_STATUS_SUCCESS, or < 0 with IOCTL error code |
| */ |
| int |
| wlan_get_scan_table_ret_entry(BSSDescriptor_t *pbss_desc, t_u8 **ppbuffer, |
| int *pspace_left) |
| { |
| wlan_ioctl_get_scan_table_entry *prsp_entry; |
| wlan_ioctl_get_scan_table_entry tmp_rsp_entry; |
| int space_needed; |
| t_u8 *pcurrent; |
| int variable_size; |
| |
| const int fixed_size = sizeof(wlan_ioctl_get_scan_table_entry); |
| |
| ENTER(); |
| |
| pcurrent = *ppbuffer; |
| |
| /* The variable size returned is the stored beacon size */ |
| variable_size = pbss_desc->beacon_buf_size; |
| |
| /* If we stored a beacon and its size was zero, set the variable |
| * size return value to the size of the brief scan response |
| * wlan_scan_create_brief_table_entry creates. Also used if |
| * we are not configured to store beacons in the first place |
| */ |
| if (!variable_size) { |
| variable_size = pbss_desc->ssid.ssid_len + 2; |
| variable_size += (sizeof(pbss_desc->beacon_period) + |
| sizeof(pbss_desc->time_stamp) + |
| sizeof(pbss_desc->cap_info)); |
| if (pbss_desc->wmm_ie.vend_hdr.element_id == WMM_IE) { |
| variable_size += (sizeof(IEEEtypes_Header_t) + |
| pbss_desc->wmm_ie.vend_hdr.len); |
| } |
| |
| if (pbss_desc->pwpa_ie) { |
| if ((*(pbss_desc->pwpa_ie)).vend_hdr.element_id == |
| WPA_IE) { |
| variable_size += |
| (sizeof(IEEEtypes_Header_t) + |
| (*(pbss_desc->pwpa_ie)).vend_hdr.len); |
| } |
| } |
| |
| if (pbss_desc->prsn_ie) { |
| if ((*(pbss_desc->prsn_ie)).ieee_hdr.element_id == |
| RSN_IE) { |
| variable_size += |
| (sizeof(IEEEtypes_Header_t) + |
| (*(pbss_desc->prsn_ie)).ieee_hdr.len); |
| } |
| } |
| } |
| |
| space_needed = fixed_size + variable_size; |
| |
| PRINTM(MINFO, "GetScanTable: need(%d), left(%d)\n", space_needed, |
| *pspace_left); |
| |
| if (space_needed >= *pspace_left) { |
| *pspace_left = 0; |
| LEAVE(); |
| return -E2BIG; |
| } |
| |
| *pspace_left -= space_needed; |
| |
| tmp_rsp_entry.fixed_field_length = |
| (sizeof(tmp_rsp_entry) - |
| sizeof(tmp_rsp_entry.fixed_field_length) - |
| sizeof(tmp_rsp_entry.bss_info_length)); |
| |
| moal_memcpy_ext(NULL, tmp_rsp_entry.fixed_fields.bssid, |
| pbss_desc->mac_address, |
| sizeof(prsp_entry->fixed_fields.bssid), |
| sizeof(prsp_entry->fixed_fields.bssid)); |
| |
| tmp_rsp_entry.fixed_fields.rssi = pbss_desc->rssi; |
| tmp_rsp_entry.fixed_fields.channel = pbss_desc->channel; |
| tmp_rsp_entry.fixed_fields.chan_load = pbss_desc->chan_load; |
| tmp_rsp_entry.fixed_fields.network_tsf = pbss_desc->network_tsf; |
| tmp_rsp_entry.bss_info_length = variable_size; |
| |
| /* |
| * Copy fixed fields to user space |
| */ |
| moal_memcpy_ext(NULL, pcurrent, &tmp_rsp_entry, fixed_size, fixed_size); |
| pcurrent += fixed_size; |
| |
| if (pbss_desc->pbeacon_buf) { |
| /* |
| * Copy variable length elements to user space |
| */ |
| moal_memcpy_ext(NULL, pcurrent, pbss_desc->pbeacon_buf, |
| pbss_desc->beacon_buf_size, |
| pbss_desc->beacon_buf_size); |
| |
| pcurrent += pbss_desc->beacon_buf_size; |
| } else { |
| wlan_scan_create_brief_table_entry(&pcurrent, pbss_desc); |
| } |
| |
| *ppbuffer = pcurrent; |
| |
| LEAVE(); |
| |
| return MLAN_STATUS_SUCCESS; |
| } |
| |
| /** |
| * @brief ioctl function - entry point |
| * |
| * @param dev A pointer to net_device structure |
| * @param req A pointer to ifreq structure |
| * @param cmd Command |
| * |
| * @return 0 --success, otherwise fail |
| */ |
| #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) |
| int |
| woal_do_ioctl(struct net_device *dev, struct ifreq *req, void __user * data, |
| int cmd) |
| #else |
| int |
| woal_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd) |
| #endif |
| { |
| int ret = 0; |
| |
| ENTER(); |
| |
| #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) |
| if (in_compat_syscall()) /* not implemented yet */ |
| return -EOPNOTSUPP; |
| #endif |
| |
| PRINTM(MINFO, "woal_do_ioctl: ioctl cmd = 0x%x\n", cmd); |
| switch (cmd) { |
| case WOAL_ANDROID_DEF_CMD: |
| /** android default ioctl ID is SIOCDEVPRIVATE + 1 */ |
| ret = woal_android_priv_cmd(dev, req); |
| break; |
| case WOAL_CUSTOM_IE_CFG: |
| ret = woal_custom_ie_ioctl(dev, req); |
| break; |
| case WOAL_MGMT_FRAME_TX: |
| ret = woal_send_host_packet(dev, req); |
| break; |
| case WOAL_TDLS_CONFIG: |
| ret = woal_tdls_config_ioctl(dev, req); |
| break; |
| case WOAL_ANDROID_PRIV_CMD: |
| ret = woal_android_priv_cmd(dev, req); |
| break; |
| case WOAL_GET_BSS_TYPE: |
| ret = woal_get_bss_type(dev, req); |
| break; |
| default: |
| #if defined(STA_WEXT) |
| #ifdef STA_SUPPORT |
| ret = woal_wext_do_ioctl(dev, req, cmd); |
| #else |
| ret = -EINVAL; |
| #endif |
| #else |
| ret = -EINVAL; |
| #endif |
| break; |
| } |
| |
| LEAVE(); |
| return ret; |
| } |