summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/sd8797/mlinux/moal_uap.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/sd8797/mlinux/moal_uap.c')
-rw-r--r--drivers/net/wireless/sd8797/mlinux/moal_uap.c2692
1 files changed, 2692 insertions, 0 deletions
diff --git a/drivers/net/wireless/sd8797/mlinux/moal_uap.c b/drivers/net/wireless/sd8797/mlinux/moal_uap.c
new file mode 100644
index 000000000000..7dac877abe00
--- /dev/null
+++ b/drivers/net/wireless/sd8797/mlinux/moal_uap.c
@@ -0,0 +1,2692 @@
+/** @file moal_uap.c
+ *
+ * @brief This file contains the major functions in UAP
+ * driver.
+ *
+ * Copyright (C) 2008-2012, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License"). You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED. The License provides additional details about
+ * this warranty disclaimer.
+ *
+ */
+
+/********************************************************
+Change log:
+ 10/21/2008: initial version
+********************************************************/
+
+#include "moal_main.h"
+#include "moal_uap.h"
+#include "moal_sdio.h"
+#include "moal_eth_ioctl.h"
+#if defined(STA_CFG80211) && defined(UAP_CFG80211)
+#include "moal_cfg80211.h"
+#endif
+
+/********************************************************
+ Local Variables
+********************************************************/
+
+/********************************************************
+ Global Variables
+********************************************************/
+
+/********************************************************
+ Local Functions
+********************************************************/
+/**
+ * @brief uap addba parameter handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_addba_param(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ addba_param param;
+ int ret = 0;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_addba_param() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ PRINTM(MIOCTL,
+ "addba param: action=%d, timeout=%d, txwinsize=%d, rxwinsize=%d txamsdu=%d rxamsdu=%d\n",
+ (int) param.action, (int) param.timeout, (int) param.txwinsize,
+ (int) param.rxwinsize, (int) param.txamsdu, (int) param.rxamsdu);
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *) ioctl_req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_PARAM;
+ ioctl_req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (!param.action) {
+ /* Get addba param from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set addba param in MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ cfg_11n->param.addba_param.timeout = param.timeout;
+ cfg_11n->param.addba_param.txwinsize = param.txwinsize;
+ cfg_11n->param.addba_param.rxwinsize = param.rxwinsize;
+ cfg_11n->param.addba_param.txamsdu = param.txamsdu;
+ cfg_11n->param.addba_param.rxamsdu = param.rxamsdu;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ param.timeout = cfg_11n->param.addba_param.timeout;
+ param.txwinsize = cfg_11n->param.addba_param.txwinsize;
+ param.rxwinsize = cfg_11n->param.addba_param.rxwinsize;
+ param.txamsdu = cfg_11n->param.addba_param.txamsdu;
+ param.rxamsdu = cfg_11n->param.addba_param.rxamsdu;
+
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap aggr priority tbl
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_aggr_priotbl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ aggr_prio_tbl param;
+ int ret = 0;
+ int i = 0;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_aggr_priotbl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "aggr_prio_tbl", (t_u8 *) & param, sizeof(param));
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *) ioctl_req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_AGGR_PRIO_TBL;
+ ioctl_req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (!param.action) {
+ /* Get aggr_prio_tbl from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set aggr_prio_tbl in MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ cfg_11n->param.aggr_prio_tbl.ampdu[i] = param.ampdu[i];
+ cfg_11n->param.aggr_prio_tbl.amsdu[i] = param.amsdu[i];
+ }
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ param.ampdu[i] = cfg_11n->param.aggr_prio_tbl.ampdu[i];
+ param.amsdu[i] = cfg_11n->param.aggr_prio_tbl.amsdu[i];
+ }
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap addba reject tbl
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_addba_reject(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_11n_cfg *cfg_11n = NULL;
+ addba_reject_para param;
+ int ret = 0;
+ int i = 0;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_addba_reject() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "addba_reject tbl", (t_u8 *) & param, sizeof(param));
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11n_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg_11n = (mlan_ds_11n_cfg *) ioctl_req->pbuf;
+ cfg_11n->sub_command = MLAN_OID_11N_CFG_ADDBA_REJECT;
+ ioctl_req->req_id = MLAN_IOCTL_11N_CFG;
+
+ if (!param.action) {
+ /* Get addba_reject tbl from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set addba_reject tbl in MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ cfg_11n->param.addba_reject[i] = param.addba_reject[i];
+ }
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ for (i = 0; i < MAX_NUM_TID; i++) {
+ param.addba_reject[i] = cfg_11n->param.addba_reject[i];
+ }
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap get_fw_info handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_get_fw_info(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ fw_info fw;
+ mlan_fw_info fw_info;
+ int ret = 0;
+
+ ENTER();
+ memset(&fw, 0, sizeof(fw));
+ memset(&fw_info, 0, sizeof(fw_info));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_get_fw_info() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&fw, req->ifr_data, sizeof(fw))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_get_fw_info(priv, MOAL_IOCTL_WAIT, &fw_info)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ fw.fw_release_number = fw_info.fw_ver;
+ fw.hw_dev_mcs_support = fw_info.hw_dev_mcs_support;
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &fw, sizeof(fw))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief configure deep sleep
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_deep_sleep(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_pm_cfg *pm = NULL;
+ deep_sleep_para param;
+ int ret = 0;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_deep_sleep() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "deep_sleep_para", (t_u8 *) & param, sizeof(param));
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ pm = (mlan_ds_pm_cfg *) ioctl_req->pbuf;
+ pm->sub_command = MLAN_OID_PM_CFG_DEEP_SLEEP;
+ ioctl_req->req_id = MLAN_IOCTL_PM_CFG;
+
+ if (!param.action) {
+ /* Get deep_sleep status from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set deep_sleep in MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ if (param.deep_sleep == MTRUE) {
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_ON;
+ pm->param.auto_deep_sleep.idletime = param.idle_time;
+ } else {
+ pm->param.auto_deep_sleep.auto_ds = DEEP_SLEEP_OFF;
+ }
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (pm->param.auto_deep_sleep.auto_ds == DEEP_SLEEP_ON)
+ param.deep_sleep = MTRUE;
+ else
+ param.deep_sleep = MFALSE;
+ param.idle_time = pm->param.auto_deep_sleep.idletime;
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief configure tx_pause settings
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_txdatapause(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_misc_cfg *misc = NULL;
+ tx_data_pause_para param;
+ int ret = 0;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_txdatapause corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "tx_data_pause_para", (t_u8 *) & param, sizeof(param));
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ misc = (mlan_ds_misc_cfg *) ioctl_req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_TX_DATAPAUSE;
+ ioctl_req->req_id = MLAN_IOCTL_MISC_CFG;
+
+ if (!param.action) {
+ /* Get Tx data pause status from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set Tx data pause in MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ misc->param.tx_datapause.tx_pause = param.txpause;
+ misc->param.tx_datapause.tx_buf_cnt = param.txbufcnt;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ param.txpause = misc->param.tx_datapause.tx_pause;
+ param.txbufcnt = misc->param.tx_datapause.tx_buf_cnt;
+
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap sdcmd52rw ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_sdcmd52_rw(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ sdcmd52_para param;
+ t_u8 func, data = 0;
+ int ret = 0, reg;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_sdcmd52_rw() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ func = (t_u8) param.cmd52_params[0];
+ reg = (t_u32) param.cmd52_params[1];
+
+ if (!param.action) {
+ PRINTM(MINFO, "Cmd52 read, func=%d, reg=0x%08X\n", func, reg);
+ sdio_claim_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (func)
+ data =
+ sdio_readb(((struct sdio_mmc_card *) priv->phandle->card)->func,
+ reg, &ret);
+ else
+ data =
+ sdio_f0_readb(((struct sdio_mmc_card *) priv->phandle->card)->
+ func, reg, &ret);
+ sdio_release_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (ret) {
+ PRINTM(MERROR, "sdio_readb: reading register 0x%X failed\n", reg);
+ goto done;
+ }
+ param.cmd52_params[2] = data;
+ } else {
+ data = (t_u8) param.cmd52_params[2];
+ PRINTM(MINFO, "Cmd52 write, func=%d, reg=0x%08X, data=0x%02X\n", func,
+ reg, data);
+ sdio_claim_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (func)
+ sdio_writeb(((struct sdio_mmc_card *) priv->phandle->card)->func,
+ data, reg, &ret);
+ else
+ sdio_f0_writeb(((struct sdio_mmc_card *) priv->phandle->card)->func,
+ data, reg, &ret);
+ sdio_release_host(((struct sdio_mmc_card *) priv->phandle->card)->func);
+ if (ret) {
+ PRINTM(MERROR, "sdio_writeb: writing register 0x%X failed\n", reg);
+ goto done;
+ }
+ }
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief configure snmp mib
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_snmp_mib(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_snmp_mib *snmp = NULL;
+ snmp_mib_para param;
+ t_u8 value[MAX_SNMP_VALUE_SIZE];
+ int ret = 0;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+ memset(value, 0, MAX_SNMP_VALUE_SIZE);
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_snmp_mib() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy from user */
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "snmp_mib_para", (t_u8 *) & param, sizeof(param));
+ if (param.action) {
+ if (copy_from_user(value, req->ifr_data + sizeof(param),
+ MIN(param.oid_val_len, MAX_SNMP_VALUE_SIZE))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "snmp_mib_para value", value,
+ MIN(param.oid_val_len, sizeof(t_u32)));
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_snmp_mib));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ snmp = (mlan_ds_snmp_mib *) ioctl_req->pbuf;
+ ioctl_req->req_id = MLAN_IOCTL_SNMP_MIB;
+ switch (param.oid) {
+ case OID_80211D_ENABLE:
+ snmp->sub_command = MLAN_OID_SNMP_MIB_DOT11D;
+ break;
+ case OID_80211H_ENABLE:
+ snmp->sub_command = MLAN_OID_SNMP_MIB_DOT11H;
+ break;
+ default:
+ PRINTM(MERROR, "%s: Unsupported SNMP_MIB OID (%d).\n", __FUNCTION__,
+ param.oid);
+ goto done;
+ }
+
+ if (!param.action) {
+ /* Get mib value from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set mib value to MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ snmp->param.oid_value = *(t_u32 *) value;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!param.action) { /* GET */
+ if (copy_to_user(req->ifr_data + sizeof(param), &snmp->param.oid_value,
+ MIN(param.oid_val_len, sizeof(t_u32)))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief configure domain info
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_domain_info(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_11d_cfg *cfg11d = NULL;
+ domain_info_para param;
+ t_u8 tlv[MAX_DOMAIN_TLV_LEN];
+ t_u16 tlv_data_len = 0;
+ int ret = 0;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+ memset(tlv, 0, MAX_DOMAIN_TLV_LEN);
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_domain_info() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy from user */
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "domain_info_para", (t_u8 *) & param, sizeof(param));
+ if (param.action) {
+ /* get tlv header */
+ if (copy_from_user(tlv, req->ifr_data + sizeof(param), TLV_HEADER_LEN)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ tlv_data_len = ((t_u16 *) (tlv))[1];
+ if ((TLV_HEADER_LEN + tlv_data_len) > sizeof(tlv)) {
+ PRINTM(MERROR, "TLV buffer is overflowed");
+ ret = -EINVAL;
+ goto done;
+ }
+ /* get full tlv */
+ if (copy_from_user(tlv, req->ifr_data + sizeof(param),
+ TLV_HEADER_LEN + tlv_data_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "domain_info_para tlv", tlv,
+ TLV_HEADER_LEN + tlv_data_len);
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11d_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg11d = (mlan_ds_11d_cfg *) ioctl_req->pbuf;
+ ioctl_req->req_id = MLAN_IOCTL_11D_CFG;
+ cfg11d->sub_command = MLAN_OID_11D_DOMAIN_INFO;
+
+ if (!param.action) {
+ /* Get mib value from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set mib value to MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ memcpy(cfg11d->param.domain_tlv, tlv,
+ MIN(MAX_IE_SIZE, (TLV_HEADER_LEN + tlv_data_len)));
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!param.action) { /* GET */
+ tlv_data_len = ((t_u16 *) (cfg11d->param.domain_tlv))[1];
+ if (copy_to_user
+ (req->ifr_data + sizeof(param), &cfg11d->param.domain_tlv,
+ TLV_HEADER_LEN + tlv_data_len)) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+#if defined(DFS_TESTING_SUPPORT)
+/**
+ * @brief configure dfs testing settings
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_dfs_testing(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_11h_cfg *cfg11h = NULL;
+ dfs_testing_para param;
+ int ret = 0;
+
+ ENTER();
+ memset(&param, 0, sizeof(param));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_dfs_testing() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy from user */
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "dfs_testing_para", (t_u8 *) & param, sizeof(param));
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_11h_cfg));
+ if (ioctl_req == NULL) {
+ LEAVE();
+ return -ENOMEM;
+ }
+ cfg11h = (mlan_ds_11h_cfg *) ioctl_req->pbuf;
+ ioctl_req->req_id = MLAN_IOCTL_11H_CFG;
+ cfg11h->sub_command = MLAN_OID_11H_DFS_TESTING;
+
+ if (!param.action) {
+ /* Get mib value from MLAN */
+ ioctl_req->action = MLAN_ACT_GET;
+ } else {
+ /* Set mib value to MLAN */
+ ioctl_req->action = MLAN_ACT_SET;
+ cfg11h->param.dfs_testing.usr_cac_period_msec = param.usr_cac_period;
+ cfg11h->param.dfs_testing.usr_nop_period_sec = param.usr_nop_period;
+ cfg11h->param.dfs_testing.usr_no_chan_change = param.no_chan_change;
+ cfg11h->param.dfs_testing.usr_fixed_new_chan = param.fixed_new_chan;
+ priv->phandle->cac_period_jiffies = param.usr_cac_period * HZ / 1000;
+ }
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (!param.action) { /* GET */
+ param.usr_cac_period = cfg11h->param.dfs_testing.usr_cac_period_msec;
+ param.usr_nop_period = cfg11h->param.dfs_testing.usr_nop_period_sec;
+ param.no_chan_change = cfg11h->param.dfs_testing.usr_no_chan_change;
+ param.fixed_new_chan = cfg11h->param.dfs_testing.usr_fixed_new_chan;
+ }
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+#endif
+
+/**
+ * @brief Configure TX beamforming support
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_tx_bf_cfg(struct net_device *dev, struct ifreq *req)
+{
+ int ret = 0;
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_11n_tx_bf_cfg bf_cfg;
+ tx_bf_cfg_para_hdr param;
+ t_u16 action = 0;
+
+ ENTER();
+
+ memset(&param, 0, sizeof(param));
+ memset(&bf_cfg, 0, sizeof(bf_cfg));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "woal_uap_tx_bf_cfg corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!param.action) {
+ /* Get BF configurations */
+ action = MLAN_ACT_GET;
+ } else {
+ /* Set BF configurations */
+ action = MLAN_ACT_SET;
+ }
+ if (copy_from_user(&bf_cfg, req->ifr_data + sizeof(tx_bf_cfg_para_hdr),
+ sizeof(bf_cfg))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ DBG_HEXDUMP(MCMD_D, "bf_cfg", (t_u8 *) & bf_cfg, sizeof(bf_cfg));
+
+ if (MLAN_STATUS_SUCCESS != woal_set_get_tx_bf_cfg(priv, action, &bf_cfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data + sizeof(tx_bf_cfg_para_hdr),
+ &bf_cfg, sizeof(bf_cfg))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap hs_cfg ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_hs_cfg(struct net_device *dev, struct ifreq *req,
+ BOOLEAN invoke_hostcmd)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ds_hs_cfg hscfg;
+ ds_hs_cfg hs_cfg;
+ mlan_bss_info bss_info;
+ t_u16 action;
+ int ret = 0;
+
+ ENTER();
+
+ memset(&hscfg, 0, sizeof(mlan_ds_hs_cfg));
+ memset(&hs_cfg, 0, sizeof(ds_hs_cfg));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_hs_cfg() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&hs_cfg, req->ifr_data, sizeof(ds_hs_cfg))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ PRINTM(MIOCTL, "ioctl hscfg: flags=0x%x condition=0x%x gpio=%d gap=0x%x\n",
+ hs_cfg.flags, hs_cfg.conditions, (int) hs_cfg.gpio, hs_cfg.gap);
+
+ /* HS config is blocked if HS is already activated */
+ if ((hs_cfg.flags & HS_CFG_FLAG_CONDITION) &&
+ (hs_cfg.conditions != HOST_SLEEP_CFG_CANCEL ||
+ invoke_hostcmd == MFALSE)) {
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+ if (bss_info.is_hs_configured) {
+ PRINTM(MERROR, "HS already configured\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ if (hs_cfg.flags & HS_CFG_FLAG_SET) {
+ action = MLAN_ACT_SET;
+ if (hs_cfg.flags != HS_CFG_FLAG_ALL) {
+ woal_set_get_hs_params(priv, MLAN_ACT_GET, MOAL_IOCTL_WAIT, &hscfg);
+ }
+ if (hs_cfg.flags & HS_CFG_FLAG_CONDITION)
+ hscfg.conditions = hs_cfg.conditions;
+ if (hs_cfg.flags & HS_CFG_FLAG_GPIO)
+ hscfg.gpio = hs_cfg.gpio;
+ if (hs_cfg.flags & HS_CFG_FLAG_GAP)
+ hscfg.gap = hs_cfg.gap;
+
+ if (invoke_hostcmd == MTRUE) {
+ /* Issue IOCTL to set up parameters */
+ hscfg.is_invoke_hostcmd = MFALSE;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_hs_params(priv, action, MOAL_IOCTL_WAIT, &hscfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ } else {
+ action = MLAN_ACT_GET;
+ }
+
+ /* Issue IOCTL to invoke hostcmd */
+ hscfg.is_invoke_hostcmd = invoke_hostcmd;
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_hs_params(priv, action, MOAL_IOCTL_WAIT, &hscfg)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (!(hs_cfg.flags & HS_CFG_FLAG_SET)) {
+ hs_cfg.flags =
+ HS_CFG_FLAG_CONDITION | HS_CFG_FLAG_GPIO | HS_CFG_FLAG_GAP;
+ hs_cfg.conditions = hscfg.conditions;
+ hs_cfg.gpio = hscfg.gpio;
+ hs_cfg.gap = hscfg.gap;
+ /* Copy to user */
+ if (copy_to_user(req->ifr_data, &hs_cfg, sizeof(ds_hs_cfg))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set Host Sleep parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wrq A pointer to iwreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_hs_set_para(struct net_device *dev, struct ifreq *req)
+{
+ int ret = 0;
+
+ ENTER();
+
+ if (req->ifr_data != NULL) {
+ ret = woal_uap_hs_cfg(dev, req, MFALSE);
+ goto done;
+ } else {
+ PRINTM(MERROR, "Invalid data\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap mgmt_frame_control ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_mgmt_frame_control(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0;
+ t_u16 action = 0;
+ mgmt_frame_ctrl param;
+ mlan_uap_bss_param sys_config;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_mgmt_frame_ctrl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Get user data */
+ if (copy_from_user(&param, req->ifr_data, sizeof(param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (param.action) {
+ action = MLAN_ACT_SET;
+ } else {
+ action = MLAN_ACT_GET;
+ }
+ if (action == MLAN_ACT_SET) {
+ /* Initialize the invalid values so that the correct values below are
+ downloaded to firmware */
+ woal_set_sys_config_invalid_data(&sys_config);
+ sys_config.mgmt_ie_passthru_mask = param.mask;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_sys_config(priv, action, MOAL_IOCTL_WAIT, &sys_config)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (action == MLAN_ACT_GET) {
+ param.mask = sys_config.mgmt_ie_passthru_mask;
+ if (copy_to_user(req->ifr_data, &param, sizeof(param))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get tx rate
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_tx_rate_cfg(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0, i = 0;
+ mlan_ds_rate *rate = NULL;
+ mlan_ioctl_req *mreq = NULL;
+ tx_rate_cfg_t tx_rate_config;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_tx_rate_cfg() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&tx_rate_config, 0, sizeof(tx_rate_cfg_t));
+ /* Get user data */
+ if (copy_from_user(&tx_rate_config, req->ifr_data, sizeof(tx_rate_cfg_t))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ mreq = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_rate));
+ if (mreq == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ rate = (mlan_ds_rate *) mreq->pbuf;
+ rate->param.rate_cfg.rate_type = MLAN_RATE_INDEX;
+ rate->sub_command = MLAN_OID_RATE_CFG;
+ mreq->req_id = MLAN_IOCTL_RATE;
+ if (!(tx_rate_config.action))
+ mreq->action = MLAN_ACT_GET;
+ else {
+ mreq->action = MLAN_ACT_SET;
+ if (tx_rate_config.rate == AUTO_RATE)
+ rate->param.rate_cfg.is_rate_auto = 1;
+ else {
+ if ((tx_rate_config.rate != MLAN_RATE_INDEX_MCS32) &&
+ ((tx_rate_config.rate < 0) ||
+ (tx_rate_config.rate > MLAN_RATE_INDEX_MCS15))) {
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+ rate->param.rate_cfg.rate = tx_rate_config.rate;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, mreq, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (tx_rate_config.action) {
+ priv->rate_index = tx_rate_config.action;
+ } else {
+ if (rate->param.rate_cfg.is_rate_auto)
+ tx_rate_config.rate = AUTO_RATE;
+ else
+ tx_rate_config.rate = rate->param.rate_cfg.rate;
+ for (i = 0; i < MAX_BITMAP_RATES_SIZE; i++) {
+ tx_rate_config.bitmap_rates[i] =
+ rate->param.rate_cfg.bitmap_rates[i];
+ }
+
+ if (copy_to_user(req->ifr_data, &tx_rate_config, sizeof(tx_rate_cfg_t))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+ done:
+ if (mreq)
+ kfree(mreq);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get RF antenna mode
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_antenna_cfg(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0;
+ mlan_ds_radio_cfg *radio = NULL;
+ mlan_ioctl_req *mreq = NULL;
+ ant_cfg_t antenna_config;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_antenna_cfg() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&antenna_config, 0, sizeof(ant_cfg_t));
+ /* Get user data */
+ if (copy_from_user(&antenna_config, req->ifr_data, sizeof(ant_cfg_t))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ mreq = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (mreq == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ radio = (mlan_ds_radio_cfg *) mreq->pbuf;
+ radio->sub_command = MLAN_OID_ANT_CFG;
+ mreq->req_id = MLAN_IOCTL_RADIO_CFG;
+ if (!(antenna_config.action))
+ mreq->action = MLAN_ACT_GET;
+ else {
+ mreq->action = MLAN_ACT_SET;
+ radio->param.ant_cfg.tx_antenna = antenna_config.tx_mode;
+ radio->param.ant_cfg.rx_antenna = antenna_config.rx_mode;
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, mreq, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ if (mreq->action == MLAN_ACT_GET) {
+ antenna_config.tx_mode = radio->param.ant_cfg.tx_antenna;
+ antenna_config.rx_mode = radio->param.ant_cfg.rx_antenna;
+ if (copy_to_user(req->ifr_data, &antenna_config, sizeof(ant_cfg_t))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+ done:
+ if (mreq)
+ kfree(mreq);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ int ret = 0;
+ t_u32 subcmd = 0;
+ ENTER();
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&subcmd, req->ifr_data, sizeof(subcmd))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ PRINTM(MIOCTL, "ioctl subcmd=%d\n", (int) subcmd);
+ switch (subcmd) {
+ case UAP_ADDBA_PARA:
+ ret = woal_uap_addba_param(dev, req);
+ break;
+ case UAP_AGGR_PRIOTBL:
+ ret = woal_uap_aggr_priotbl(dev, req);
+ break;
+ case UAP_ADDBA_REJECT:
+ ret = woal_uap_addba_reject(dev, req);
+ break;
+ case UAP_FW_INFO:
+ ret = woal_uap_get_fw_info(dev, req);
+ break;
+ case UAP_DEEP_SLEEP:
+ ret = woal_uap_deep_sleep(dev, req);
+ break;
+ case UAP_TX_DATA_PAUSE:
+ ret = woal_uap_txdatapause(dev, req);
+ break;
+ case UAP_SDCMD52_RW:
+ ret = woal_uap_sdcmd52_rw(dev, req);
+ break;
+ case UAP_SNMP_MIB:
+ ret = woal_uap_snmp_mib(dev, req);
+ break;
+ case UAP_DOMAIN_INFO:
+ ret = woal_uap_domain_info(dev, req);
+ break;
+#ifdef DFS_TESTING_SUPPORT
+ case UAP_DFS_TESTING:
+ ret = woal_uap_dfs_testing(dev, req);
+ break;
+#endif
+ case UAP_TX_BF_CFG:
+ ret = woal_uap_tx_bf_cfg(dev, req);
+ break;
+ case UAP_HS_CFG:
+ ret = woal_uap_hs_cfg(dev, req, MTRUE);
+ break;
+ case UAP_HS_SET_PARA:
+ ret = woal_uap_hs_set_para(dev, req);
+ break;
+ case UAP_MGMT_FRAME_CONTROL:
+ ret = woal_uap_mgmt_frame_control(dev, req);
+ break;
+ case UAP_TX_RATE_CFG:
+ ret = woal_uap_tx_rate_cfg(dev, req);
+ break;
+ case UAP_ANTENNA_CFG:
+ ret = woal_uap_antenna_cfg(dev, req);
+ break;
+ default:
+ break;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap station deauth ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_sta_deauth_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_deauth_param deauth_param;
+ int ret = 0;
+
+ ENTER();
+
+ memset(&deauth_param, 0, sizeof(mlan_deauth_param));
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_sta_deauth_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&deauth_param, req->ifr_data, sizeof(mlan_deauth_param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ PRINTM(MIOCTL,
+ "ioctl deauth station: %02x:%02x:%02x:%02x:%02x:%02x, reason=%d\n",
+ deauth_param.mac_addr[0], deauth_param.mac_addr[1],
+ deauth_param.mac_addr[2], deauth_param.mac_addr[3],
+ deauth_param.mac_addr[4], deauth_param.mac_addr[5],
+ deauth_param.reason_code);
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) ioctl_req->pbuf;
+
+ bss->sub_command = MLAN_OID_UAP_DEAUTH_STA;
+ ioctl_req->req_id = MLAN_IOCTL_BSS;
+ ioctl_req->action = MLAN_ACT_SET;
+
+ memcpy(&bss->param.deauth_param, &deauth_param, sizeof(mlan_deauth_param));
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ if (copy_to_user(req->ifr_data, &ioctl_req->status_code, sizeof(t_u32)))
+ PRINTM(MERROR, "Copy to user failed!\n");
+ goto done;
+ }
+
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set/Get radio
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_radio_ctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0;
+ mlan_ds_radio_cfg *radio = NULL;
+ mlan_ioctl_req *mreq = NULL;
+ int data[2] = { 0, 0 };
+ mlan_bss_info bss_info;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_radio_ctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Get user data */
+ if (copy_from_user(&data, req->ifr_data, sizeof(data))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (data[0]) {
+ mreq = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_radio_cfg));
+ if (mreq == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ radio = (mlan_ds_radio_cfg *) mreq->pbuf;
+ radio->sub_command = MLAN_OID_RADIO_CTRL;
+ mreq->req_id = MLAN_IOCTL_RADIO_CFG;
+ mreq->action = MLAN_ACT_SET;
+ radio->param.radio_on_off = (t_u32) data[1];
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, mreq, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ }
+ if (mreq)
+ kfree(mreq);
+ } else {
+ /* Get radio status */
+ memset(&bss_info, 0, sizeof(bss_info));
+ woal_get_bss_info(priv, MOAL_IOCTL_WAIT, &bss_info);
+
+ data[1] = bss_info.radio_on;
+ if (copy_to_user(req->ifr_data, data, sizeof(data))) {
+ PRINTM(MERROR, "Copy to user failed\n");
+ ret = -EFAULT;
+ }
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap bss control ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_bss_ctrl_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0, data = 0;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_bss_ctrl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&data, req->ifr_data, sizeof(data))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, data);
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap power mode ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_power_mode_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ mlan_ioctl_req *ioctl_req = NULL;
+ mlan_ds_pm_cfg *pm_cfg = NULL;
+ mlan_ds_ps_mgmt ps_mgmt;
+ int ret = 0;
+
+ ENTER();
+
+ memset(&ps_mgmt, 0, sizeof(mlan_ds_ps_mgmt));
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_power_mode_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ if (copy_from_user(&ps_mgmt, req->ifr_data, sizeof(mlan_ds_ps_mgmt))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ PRINTM(MIOCTL,
+ "ioctl power: flag=0x%x ps_mode=%d ctrl_bitmap=%d min_sleep=%d max_sleep=%d "
+ "inact_to=%d min_awake=%d max_awake=%d\n", ps_mgmt.flags,
+ (int) ps_mgmt.ps_mode, (int) ps_mgmt.sleep_param.ctrl_bitmap,
+ (int) ps_mgmt.sleep_param.min_sleep,
+ (int) ps_mgmt.sleep_param.max_sleep,
+ (int) ps_mgmt.inact_param.inactivity_to,
+ (int) ps_mgmt.inact_param.min_awake,
+ (int) ps_mgmt.inact_param.max_awake);
+
+ if (ps_mgmt.
+ flags & ~(PS_FLAG_PS_MODE | PS_FLAG_SLEEP_PARAM |
+ PS_FLAG_INACT_SLEEP_PARAM)) {
+ PRINTM(MERROR, "Invalid parameter: flags = 0x%x\n", ps_mgmt.flags);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (ps_mgmt.ps_mode > PS_MODE_INACTIVITY) {
+ PRINTM(MERROR, "Invalid parameter: ps_mode = %d\n",
+ (int) ps_mgmt.flags);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ioctl_req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_pm_cfg));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ pm_cfg = (mlan_ds_pm_cfg *) ioctl_req->pbuf;
+ pm_cfg->sub_command = MLAN_OID_PM_CFG_PS_MODE;
+ ioctl_req->req_id = MLAN_IOCTL_PM_CFG;
+ if (ps_mgmt.flags) {
+ ioctl_req->action = MLAN_ACT_SET;
+ memcpy(&pm_cfg->param.ps_mgmt, &ps_mgmt, sizeof(mlan_ds_ps_mgmt));
+ } else {
+ ioctl_req->action = MLAN_ACT_GET;
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ if (copy_to_user(req->ifr_data, &ioctl_req->status_code, sizeof(t_u32)))
+ PRINTM(MERROR, "Copy to user failed!\n");
+ goto done;
+ }
+ if (!ps_mgmt.flags) {
+ /* Copy to user */
+ if (copy_to_user
+ (req->ifr_data, &pm_cfg->param.ps_mgmt, sizeof(mlan_ds_ps_mgmt))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap BSS config ioctl handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_bss_cfg_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *ioctl_req = NULL;
+ int offset = 0;
+ t_u32 action = 0;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_bss_cfg_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Get action */
+ if (copy_from_user(&action, req->ifr_data + offset, sizeof(action))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ offset += sizeof(action);
+
+ /* Allocate an IOCTL request buffer */
+ ioctl_req =
+ (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ bss = (mlan_ds_bss *) ioctl_req->pbuf;
+ bss->sub_command = MLAN_OID_UAP_BSS_CONFIG;
+ ioctl_req->req_id = MLAN_IOCTL_BSS;
+ if (action == 1) {
+ ioctl_req->action = MLAN_ACT_SET;
+ } else {
+ ioctl_req->action = MLAN_ACT_GET;
+ }
+
+ if (ioctl_req->action == MLAN_ACT_SET) {
+ /* Get the BSS config from user */
+ if (copy_from_user
+ (&bss->param.bss_config, req->ifr_data + offset,
+ sizeof(mlan_uap_bss_param))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (ioctl_req->action == MLAN_ACT_GET) {
+ offset = sizeof(action);
+
+ /* Copy to user : BSS config */
+ if (copy_to_user
+ (req->ifr_data + offset, &bss->param.bss_config,
+ sizeof(mlan_uap_bss_param))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap get station list handler
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_get_sta_list_ioctl(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ int ret = 0;
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *ioctl_req = NULL;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_get_sta_list_ioctl() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Allocate an IOCTL request buffer */
+ ioctl_req =
+ (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (ioctl_req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ info = (mlan_ds_get_info *) ioctl_req->pbuf;
+ info->sub_command = MLAN_OID_UAP_STA_LIST;
+ ioctl_req->req_id = MLAN_IOCTL_GET_INFO;
+ ioctl_req->action = MLAN_ACT_GET;
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_request_ioctl(priv, ioctl_req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (ioctl_req->action == MLAN_ACT_GET) {
+ /* Copy to user : sta_list */
+ if (copy_to_user
+ (req->ifr_data, &info->param.sta_list, sizeof(mlan_ds_sta_list))) {
+ PRINTM(MERROR, "Copy to user failed!\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+ done:
+ if (ioctl_req)
+ kfree(ioctl_req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uAP set WAPI key ioctl
+ *
+ * @param priv A pointer to moal_private structure
+ * @param msg A pointer to wapi_msg structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_set_wapi_key_ioctl(moal_private * priv, wapi_msg * msg)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_sec_cfg *sec = NULL;
+ int ret = 0;
+ wapi_key_msg *key_msg = NULL;
+ t_u8 bcast_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ ENTER();
+ if (msg->msg_len != sizeof(wapi_key_msg)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ key_msg = (wapi_key_msg *) msg->msg;
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ sec = (mlan_ds_sec_cfg *) req->pbuf;
+ sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
+ req->req_id = MLAN_IOCTL_SEC_CFG;
+ req->action = MLAN_ACT_SET;
+
+ sec->param.encrypt_key.is_wapi_key = MTRUE;
+ sec->param.encrypt_key.key_len = MLAN_MAX_KEY_LENGTH;
+ memcpy(sec->param.encrypt_key.mac_addr, key_msg->mac_addr, ETH_ALEN);
+ sec->param.encrypt_key.key_index = key_msg->key_id;
+ if (0 == memcmp(key_msg->mac_addr, bcast_addr, ETH_ALEN))
+ sec->param.encrypt_key.key_flags = KEY_FLAG_GROUP_KEY;
+ else
+ sec->param.encrypt_key.key_flags = KEY_FLAG_SET_TX_KEY;
+ memcpy(sec->param.encrypt_key.key_material, key_msg->key,
+ sec->param.encrypt_key.key_len);
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT))
+ ret = -EFAULT;
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Enable/Disable wapi in firmware
+ *
+ * @param priv A pointer to moal_private structure
+ * @param enable MTRUE/MFALSE
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+static mlan_status
+woal_enable_wapi(moal_private * priv, t_u8 enable)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ mlan_status status;
+
+ ENTER();
+
+ /* Allocate an IOCTL request buffer */
+ req = (mlan_ioctl_req *) woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ /* Fill request buffer */
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_UAP_BSS_CONFIG;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Get AP setting failed! status=%d, error_code=0x%x\n",
+ status, req->status_code);
+ }
+
+ /* Change AP default setting */
+ req->action = MLAN_ACT_SET;
+ if (enable == MFALSE) {
+ bss->param.bss_config.auth_mode = MLAN_AUTH_MODE_OPEN;
+ bss->param.bss_config.protocol = PROTOCOL_NO_SECURITY;
+ } else {
+ bss->param.bss_config.auth_mode = MLAN_AUTH_MODE_OPEN;
+ bss->param.bss_config.protocol = PROTOCOL_WAPI;
+ }
+
+ /* Send IOCTL request to MLAN */
+ status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Set AP setting failed! status=%d, error_code=0x%x\n",
+ status, req->status_code);
+ }
+ if (enable)
+ woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START);
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief uAP set WAPI flag ioctl
+ *
+ * @param priv A pointer to moal_private structure
+ * @param msg A pointer to wapi_msg structure
+ *
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_set_wapi_flag_ioctl(moal_private * priv, wapi_msg * msg)
+{
+ t_u8 wapi_psk_ie[] =
+ { 0x44, 0x14, 0x01, 0x00, 0x01, 0x00, 0x00, 0x14, 0x72, 0x02,
+ 0x01, 0x00, 0x00, 0x14, 0x72, 0x01, 0x00, 0x14, 0x72, 0x01,
+ 0x00, 0x00
+ };
+ t_u8 wapi_cert_ie[] =
+ { 0x44, 0x14, 0x01, 0x00, 0x01, 0x00, 0x00, 0x14, 0x72, 0x01,
+ 0x01, 0x00, 0x00, 0x14, 0x72, 0x01, 0x00, 0x14, 0x72, 0x01,
+ 0x00, 0x00
+ };
+ mlan_ds_misc_cfg *misc = NULL;
+ mlan_ioctl_req *req = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP);
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_misc_cfg));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ misc = (mlan_ds_misc_cfg *) req->pbuf;
+ misc->sub_command = MLAN_OID_MISC_GEN_IE;
+ req->req_id = MLAN_IOCTL_MISC_CFG;
+ req->action = MLAN_ACT_SET;
+
+ misc->param.gen_ie.type = MLAN_IE_TYPE_GEN_IE;
+ misc->param.gen_ie.len = sizeof(wapi_psk_ie);
+ if (msg->msg[0] & WAPI_MODE_PSK) {
+ memcpy(misc->param.gen_ie.ie_data, wapi_psk_ie, misc->param.gen_ie.len);
+ } else if (msg->msg[0] & WAPI_MODE_CERT) {
+ memcpy(misc->param.gen_ie.ie_data, wapi_cert_ie,
+ misc->param.gen_ie.len);
+ } else if (msg->msg[0] == 0) {
+ /* disable WAPI in driver */
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_wapi_enable(priv, MOAL_IOCTL_WAIT, 0))
+ ret = -EFAULT;
+ woal_enable_wapi(priv, MFALSE);
+ goto done;
+ } else {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ woal_enable_wapi(priv, MTRUE);
+ done:
+ if (req)
+ kfree(req);
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief set wapi ioctl function
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @return 0 --success, otherwise fail
+ */
+static int
+woal_uap_set_wapi(struct net_device *dev, struct ifreq *req)
+{
+ moal_private *priv = (moal_private *) netdev_priv(dev);
+ wapi_msg msg;
+ int ret = 0;
+
+ ENTER();
+
+ /* Sanity check */
+ if (req->ifr_data == NULL) {
+ PRINTM(MERROR, "uap_set_wapi() corrupt data\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ memset(&msg, 0, sizeof(msg));
+
+ if (copy_from_user(&msg, req->ifr_data, sizeof(msg))) {
+ PRINTM(MERROR, "Copy from user failed\n");
+ ret = -EFAULT;
+ goto done;
+ }
+
+ PRINTM(MIOCTL, "set wapi msg_type = %d, msg_len=%d\n", msg.msg_type,
+ msg.msg_len);
+ DBG_HEXDUMP(MCMD_D, "wapi msg", msg.msg, MIN(msg.msg_len, sizeof(msg.msg)));
+
+ switch (msg.msg_type) {
+ case P80211_PACKET_WAPIFLAG:
+ ret = woal_uap_set_wapi_flag_ioctl(priv, &msg);
+ break;
+ case P80211_PACKET_SETKEY:
+ ret = woal_uap_set_wapi_key_ioctl(priv, &msg);
+ break;
+ default:
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ done:
+ LEAVE();
+ return ret;
+}
+
+/********************************************************
+ Global Functions
+********************************************************/
+/**
+ * @brief Initialize the members of mlan_uap_bss_param
+ * which are uploaded from firmware
+ *
+ * @param priv A pointer to moal_private structure
+ * @param sys_cfg A pointer to mlan_uap_bss_param structure
+ * @param wait_option Wait option
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_uap_get_bss_param(moal_private * priv, mlan_uap_bss_param * sys_cfg,
+ t_u8 wait_option)
+{
+ mlan_ds_bss *info = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ info = (mlan_ds_bss *) req->pbuf;
+ info->sub_command = MLAN_OID_UAP_BSS_CONFIG;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status != MLAN_STATUS_SUCCESS) {
+ PRINTM(MERROR, "Get bss info failed!\n");
+ status = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+ memcpy(sys_cfg, &info->param.bss_config, sizeof(mlan_uap_bss_param));
+
+ done:
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set 11n status based on the configured security mode
+ *
+ * @param sys_cfg A pointer to mlan_uap_bss_param structure
+ * @param action MLAN_ACT_DISABLE or MLAN_ACT_ENABLE
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_uap_set_11n_status(mlan_uap_bss_param * sys_cfg, t_u8 action)
+{
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+ if (action == MLAN_ACT_DISABLE) {
+ if ((sys_cfg->supported_mcs_set[0] == 0)
+ && (sys_cfg->supported_mcs_set[4] == 0)
+ && (sys_cfg->supported_mcs_set[1] == 0)
+ ) {
+ goto done;
+ } else {
+ sys_cfg->supported_mcs_set[0] = 0;
+ sys_cfg->supported_mcs_set[4] = 0;
+ sys_cfg->supported_mcs_set[1] = 0;
+ }
+ }
+
+ if (action == MLAN_ACT_ENABLE) {
+ if ((sys_cfg->supported_mcs_set[0] != 0)
+ || (sys_cfg->supported_mcs_set[4] != 0)
+ || (sys_cfg->supported_mcs_set[1] != 0)
+ ) {
+ goto done;
+ } else {
+ sys_cfg->supported_mcs_set[0] = 0xFF;
+ sys_cfg->supported_mcs_set[4] = 0x01;
+ sys_cfg->supported_mcs_set[1] = 0xFF;
+ }
+ }
+
+ done:
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Parse AP configuration from ASCII string
+ *
+ * @param ap_cfg A pointer to mlan_uap_bss_param structure
+ * @param buf A pointer to user data
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_uap_ap_cfg_parse_data(mlan_uap_bss_param * ap_cfg, t_s8 * buf)
+{
+ int ret = 0, atoi_ret;
+ int set_sec = 0, set_key = 0, set_chan = 0;
+ int set_preamble = 0, set_scb = 0, set_ssid = 0;
+ t_s8 *begin = buf, *value = NULL, *opt = NULL;
+
+ ENTER();
+
+ while (begin) {
+ value = woal_strsep(&begin, ',', '/');
+ opt = woal_strsep(&value, '=', '/');
+ if (opt && !strncmp(opt, "END", strlen("END"))) {
+ if (!ap_cfg->ssid.ssid_len) {
+ PRINTM(MERROR, "Minimum option required is SSID\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ PRINTM(MINFO, "Parsing terminated by string END\n");
+ break;
+ }
+ if (!opt || !value || !value[0]) {
+ PRINTM(MERROR, "Invalid option\n");
+ ret = -EINVAL;
+ goto done;
+ } else if (!strncmp(opt, "ASCII_CMD", strlen("ASCII_CMD"))) {
+ if (strncmp(value, "AP_CFG", strlen("AP_CFG"))) {
+ PRINTM(MERROR, "ASCII_CMD: %s not matched with AP_CFG\n",
+ value);
+ ret = -EFAULT;
+ goto done;
+ }
+ value = woal_strsep(&begin, ',', '/');
+ opt = woal_strsep(&value, '=', '/');
+ if (!opt || !value || !value[0]) {
+ PRINTM(MERROR, "Minimum option required is SSID\n");
+ ret = -EINVAL;
+ goto done;
+ } else if (!strncmp(opt, "SSID", strlen("SSID"))) {
+ if (set_ssid) {
+ PRINTM(MWARN, "Skipping SSID, found again!\n");
+ continue;
+ }
+ if (strlen(value) > MLAN_MAX_SSID_LENGTH) {
+ PRINTM(MERROR, "SSID length exceeds max length\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ ap_cfg->ssid.ssid_len = strlen(value);
+ strncpy((char *) ap_cfg->ssid.ssid, value, strlen(value));
+ PRINTM(MINFO, "ssid=%s, len=%d\n", ap_cfg->ssid.ssid,
+ (int) ap_cfg->ssid.ssid_len);
+ set_ssid = 1;
+ } else {
+ PRINTM(MERROR, "AP_CFG: Invalid option %s, "
+ "expect SSID\n", opt);
+ ret = -EINVAL;
+ goto done;
+ }
+ } else if (!strncmp(opt, "SEC", strlen("SEC"))) {
+ if (set_sec) {
+ PRINTM(MWARN, "Skipping SEC, found again!\n");
+ continue;
+ }
+ if (!strnicmp(value, "open", strlen("open"))) {
+ ap_cfg->auth_mode = MLAN_AUTH_MODE_OPEN;
+ if (set_key)
+ ap_cfg->wpa_cfg.length = 0;
+ ap_cfg->key_mgmt = KEY_MGMT_NONE;
+ ap_cfg->protocol = PROTOCOL_NO_SECURITY;
+ } else if (!strnicmp(value, "wpa2-psk", strlen("wpa2-psk"))) {
+ ap_cfg->auth_mode = MLAN_AUTH_MODE_OPEN;
+ ap_cfg->protocol = PROTOCOL_WPA2;
+ ap_cfg->key_mgmt = KEY_MGMT_PSK;
+ ap_cfg->wpa_cfg.pairwise_cipher_wpa = CIPHER_AES_CCMP;
+ ap_cfg->wpa_cfg.pairwise_cipher_wpa2 = CIPHER_AES_CCMP;
+ ap_cfg->wpa_cfg.group_cipher = CIPHER_AES_CCMP;
+ } else if (!strnicmp(value, "wpa-psk", strlen("wpa-psk"))) {
+ ap_cfg->auth_mode = MLAN_AUTH_MODE_OPEN;
+ ap_cfg->protocol = PROTOCOL_WPA;
+ ap_cfg->key_mgmt = KEY_MGMT_PSK;
+ ap_cfg->wpa_cfg.pairwise_cipher_wpa = CIPHER_TKIP;
+ ap_cfg->wpa_cfg.group_cipher = CIPHER_TKIP;
+ } else if (!strnicmp(value, "wep128", strlen("wep128"))) {
+ ap_cfg->auth_mode = MLAN_AUTH_MODE_OPEN;
+ if (set_key)
+ ap_cfg->wpa_cfg.length = 0;
+ ap_cfg->key_mgmt = KEY_MGMT_NONE;
+ ap_cfg->protocol = PROTOCOL_STATIC_WEP;
+ } else {
+ PRINTM(MERROR, "AP_CFG: Invalid value=%s for %s\n", value, opt);
+ ret = -EFAULT;
+ goto done;
+ }
+ set_sec = 1;
+ } else if (!strncmp(opt, "KEY", strlen("KEY"))) {
+ if (set_key) {
+ PRINTM(MWARN, "Skipping KEY, found again!\n");
+ continue;
+ }
+ if (set_sec && ap_cfg->protocol == PROTOCOL_STATIC_WEP) {
+ if (strlen(value) != MAX_WEP_KEY_SIZE) {
+ PRINTM(MERROR, "Invalid WEP KEY length\n");
+ ret = -EFAULT;
+ goto done;
+ }
+ ap_cfg->wep_cfg.key0.key_index = 0;
+ ap_cfg->wep_cfg.key0.is_default = 1;
+ ap_cfg->wep_cfg.key0.length = strlen(value);
+ memcpy(ap_cfg->wep_cfg.key0.key, value, strlen(value));
+ set_key = 1;
+ continue;
+ }
+ if (set_sec && ap_cfg->protocol != PROTOCOL_WPA2
+ && ap_cfg->protocol != PROTOCOL_WPA) {
+ PRINTM(MWARN, "Warning! No KEY for open mode\n");
+ set_key = 1;
+ continue;
+ }
+ if (strlen(value) < MLAN_MIN_PASSPHRASE_LENGTH ||
+ strlen(value) > MLAN_PMK_HEXSTR_LENGTH) {
+ PRINTM(MERROR, "Invalid PSK/PMK length\n");
+ ret = -EINVAL;
+ goto done;
+ }
+ ap_cfg->wpa_cfg.length = strlen(value);
+ memcpy(ap_cfg->wpa_cfg.passphrase, value, strlen(value));
+ set_key = 1;
+ } else if (!strncmp(opt, "CHANNEL", strlen("CHANNEL"))) {
+ if (set_chan) {
+ PRINTM(MWARN, "Skipping CHANNEL, found again!\n");
+ continue;
+ }
+ if (woal_atoi(&atoi_ret, value)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (atoi_ret < 1 || atoi_ret > MLAN_MAX_CHANNEL) {
+ PRINTM(MERROR, "AP_CFG: Channel must be between 1 and %d"
+ "(both included)\n", MLAN_MAX_CHANNEL);
+ ret = -EINVAL;
+ goto done;
+ }
+ ap_cfg->channel = atoi_ret;
+ set_chan = 1;
+ } else if (!strncmp(opt, "PREAMBLE", strlen("PREAMBLE"))) {
+ if (set_preamble) {
+ PRINTM(MWARN, "Skipping PREAMBLE, found again!\n");
+ continue;
+ }
+ if (woal_atoi(&atoi_ret, value)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ /* This is a READ only value from FW, so we can not set this and
+ pass it successfully */
+ set_preamble = 1;
+ } else if (!strncmp(opt, "MAX_SCB", strlen("MAX_SCB"))) {
+ if (set_scb) {
+ PRINTM(MWARN, "Skipping MAX_SCB, found again!\n");
+ continue;
+ }
+ if (woal_atoi(&atoi_ret, value)) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if (atoi_ret < 1 || atoi_ret > MAX_STA_COUNT) {
+ PRINTM(MERROR, "AP_CFG: MAX_SCB must be between 1 to %d "
+ "(both included)\n", MAX_STA_COUNT);
+ ret = -EINVAL;
+ goto done;
+ }
+ ap_cfg->max_sta_count = (t_u16) atoi_ret;
+ set_scb = 1;
+ } else {
+ PRINTM(MERROR, "Invalid option %s\n", opt);
+ ret = -EINVAL;
+ goto done;
+ }
+ }
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set AP configuration
+ *
+ * @param priv A pointer to moal_private structure
+ * @param data A pointer to user data
+ * @param len Length of buf
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_uap_set_ap_cfg(moal_private * priv, t_u8 * data, int len)
+{
+ int ret = 0;
+ static t_s8 buf[MAX_BUF_LEN];
+ mlan_uap_bss_param sys_config;
+ int restart = 0;
+
+ ENTER();
+
+#define MIN_AP_CFG_CMD_LEN 16 /* strlen("ASCII_CMD=AP_CFG") */
+ if ((len - 1) <= MIN_AP_CFG_CMD_LEN) {
+ PRINTM(MERROR, "Invalid length of command\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ memset(buf, 0, MAX_BUF_LEN);
+ memcpy(buf, data, len);
+
+ /* Initialize the uap bss values which are uploaded from firmware */
+ woal_uap_get_bss_param(priv, &sys_config, MOAL_IOCTL_WAIT);
+
+ /* Setting the default values */
+ sys_config.channel = 6;
+ sys_config.preamble_type = 0;
+
+ if ((ret = woal_uap_ap_cfg_parse_data(&sys_config, buf)))
+ goto done;
+
+ /* If BSS already started stop it first and restart after changing the
+ setting */
+ if (priv->bss_started == MTRUE) {
+ if ((ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_STOP)))
+ goto done;
+ restart = 1;
+ }
+
+ /* If the security mode is configured as WEP or WPA-PSK, it will disable
+ 11n automatically, and if configured as open(off) or wpa2-psk, it will
+ automatically enable 11n */
+ if ((sys_config.protocol == PROTOCOL_STATIC_WEP) ||
+ (sys_config.protocol == PROTOCOL_WPA)) {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_uap_set_11n_status(&sys_config, MLAN_ACT_DISABLE)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ } else {
+ if (MLAN_STATUS_SUCCESS !=
+ woal_uap_set_11n_status(&sys_config, MLAN_ACT_ENABLE)) {
+ ret = -EFAULT;
+ goto done;
+ }
+ }
+
+ if (MLAN_STATUS_SUCCESS !=
+ woal_set_get_sys_config(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT,
+ &sys_config)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ /* Start the BSS after successful configuration */
+ if (restart)
+ ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT, UAP_BSS_START);
+
+ done:
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief uap BSS control ioctl handler
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param data BSS control type
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_uap_bss_ctrl(moal_private * priv, t_u8 wait_option, int data)
+{
+ mlan_ioctl_req *req = NULL;
+ mlan_ds_bss *bss = NULL;
+ int ret = 0;
+
+ ENTER();
+
+ PRINTM(MIOCTL, "ioctl bss ctrl=%d\n", data);
+ if ((data != UAP_BSS_START) && (data != UAP_BSS_STOP) &&
+ (data != UAP_BSS_RESET)) {
+ PRINTM(MERROR, "Invalid parameter: %d\n", data);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+ bss = (mlan_ds_bss *) req->pbuf;
+ switch (data) {
+ case UAP_BSS_START:
+ if (priv->bss_started == MTRUE) {
+ PRINTM(MWARN, "Warning: BSS already started!\n");
+ // goto done;
+ } else {
+ /* about to start bss: issue channel check */
+ woal_11h_channel_check_ioctl(priv);
+ }
+ bss->sub_command = MLAN_OID_BSS_START;
+ break;
+ case UAP_BSS_STOP:
+ if (priv->bss_started == MFALSE) {
+ PRINTM(MWARN, "Warning: BSS already stopped!\n");
+ // goto done;
+ }
+ bss->sub_command = MLAN_OID_BSS_STOP;
+ break;
+ case UAP_BSS_RESET:
+ bss->sub_command = MLAN_OID_UAP_BSS_RESET;
+ woal_cancel_cac_block(priv);
+ break;
+ }
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = MLAN_ACT_SET;
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ if (data == UAP_BSS_STOP || data == UAP_BSS_RESET)
+ priv->bss_started = MFALSE;
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief This function sets multicast addresses to firmware
+ *
+ * @param dev A pointer to net_device structure
+ * @return N/A
+ */
+void
+woal_uap_set_multicast_list(struct net_device *dev)
+{
+ ENTER();
+
+ LEAVE();
+}
+
+/**
+ * @brief ioctl function - entry point
+ *
+ * @param dev A pointer to net_device structure
+ * @param req A pointer to ifreq structure
+ * @param cmd Command
+ *
+ * @return 0 --success, otherwise fail
+ */
+int
+woal_uap_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+ int ret = 0;
+ ENTER();
+ PRINTM(MIOCTL, "uap_do_ioctl: ioctl cmd = 0x%x\n", cmd);
+ switch (cmd) {
+ case UAP_HOSTCMD:
+ ret = woal_hostcmd_ioctl(dev, req);
+ break;
+ case UAP_IOCTL_CMD:
+ ret = woal_uap_ioctl(dev, req);
+ break;
+ case UAP_POWER_MODE:
+ ret = woal_uap_power_mode_ioctl(dev, req);
+ break;
+ case UAP_BSS_CTRL:
+ ret = woal_uap_bss_ctrl_ioctl(dev, req);
+ break;
+ case UAP_WAPI_MSG:
+ ret = woal_uap_set_wapi(dev, req);
+ break;
+ case UAP_BSS_CONFIG:
+ ret = woal_uap_bss_cfg_ioctl(dev, req);
+ break;
+ case UAP_STA_DEAUTH:
+ ret = woal_uap_sta_deauth_ioctl(dev, req);
+ break;
+ case UAP_RADIO_CTL:
+ ret = woal_uap_radio_ctl(dev, req);
+ break;
+ case UAP_GET_STA_LIST:
+ ret = woal_uap_get_sta_list_ioctl(dev, req);
+ break;
+ case UAP_CUSTOM_IE:
+ ret = woal_custom_ie_ioctl(dev, req);
+ break;
+ case UAP_GET_BSS_TYPE:
+ ret = woal_get_bss_type(dev, req);
+ break;
+ case WOAL_ANDROID_PRIV_CMD:
+ ret = woal_android_priv_cmd(dev, req);
+ break;
+ default:
+#ifdef UAP_WEXT
+ ret = woal_uap_do_priv_ioctl(dev, req, cmd);
+#else
+ ret = -EOPNOTSUPP;
+#endif
+ break;
+ }
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Get version
+ *
+ * @param priv A pointer to moal_private structure
+ * @param version A pointer to version buffer
+ * @param max_len max length of version buffer
+ *
+ * @return N/A
+ */
+void
+woal_uap_get_version(moal_private * priv, char *version, int max_len)
+{
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ LEAVE();
+ return;
+ }
+
+ info = (mlan_ds_get_info *) req->pbuf;
+ info->sub_command = MLAN_OID_GET_VER_EXT;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, req, MOAL_PROC_WAIT);
+ if (status == MLAN_STATUS_SUCCESS) {
+ PRINTM(MINFO, "MOAL UAP VERSION: %s\n",
+ info->param.ver_ext.version_str);
+ snprintf(version, max_len, driver_version,
+ info->param.ver_ext.version_str);
+ }
+
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+
+ LEAVE();
+ return;
+}
+
+/**
+ * @brief Get uap statistics
+ *
+ * @param priv A pointer to moal_private structure
+ * @param wait_option Wait option
+ * @param ustats A pointer to mlan_ds_uap_stats structure
+ *
+ * @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING -- success, otherwise fail
+ */
+mlan_status
+woal_uap_get_stats(moal_private * priv, t_u8 wait_option,
+ mlan_ds_uap_stats * ustats)
+{
+ mlan_ds_get_info *info = NULL;
+ mlan_ioctl_req *req = NULL;
+ mlan_status status = MLAN_STATUS_SUCCESS;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_get_info));
+ if (req == NULL) {
+ LEAVE();
+ return MLAN_STATUS_FAILURE;
+ }
+
+ info = (mlan_ds_get_info *) req->pbuf;
+ info->sub_command = MLAN_OID_GET_STATS;
+ req->req_id = MLAN_IOCTL_GET_INFO;
+ req->action = MLAN_ACT_GET;
+
+ status = woal_request_ioctl(priv, req, wait_option);
+ if (status == MLAN_STATUS_SUCCESS) {
+ if (ustats)
+ memcpy(ustats, &info->param.ustats, sizeof(mlan_ds_uap_stats));
+#ifdef UAP_WEXT
+ priv->w_stats.discard.fragment = info->param.ustats.fcs_error_count;
+ priv->w_stats.discard.retries = info->param.ustats.retry_count;
+ priv->w_stats.discard.misc = info->param.ustats.ack_failure_count;
+#endif
+ }
+
+ if (req && (status != MLAN_STATUS_PENDING))
+ kfree(req);
+
+ LEAVE();
+ return status;
+}
+
+/**
+ * @brief Set/Get system configuration parameters
+ *
+ * @param priv A pointer to moal_private structure
+ * @param action MLAN_ACT_SET or MLAN_ACT_GET
+ * @param wait_option Wait option
+ * @param sys_cfg A pointer to mlan_uap_bss_param structure
+ *
+ * @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
+ */
+mlan_status
+woal_set_get_sys_config(moal_private * priv, t_u16 action, t_u8 wait_option,
+ mlan_uap_bss_param * sys_cfg)
+{
+ mlan_status ret = MLAN_STATUS_SUCCESS;
+ mlan_ds_bss *bss = NULL;
+ mlan_ioctl_req *req = NULL;
+
+ ENTER();
+
+ req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
+ if (req == NULL) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ bss = (mlan_ds_bss *) req->pbuf;
+ bss->sub_command = MLAN_OID_UAP_BSS_CONFIG;
+ req->req_id = MLAN_IOCTL_BSS;
+ req->action = action;
+
+ if (action == MLAN_ACT_SET) {
+ memcpy(&bss->param.bss_config, sys_cfg, sizeof(mlan_uap_bss_param));
+ }
+
+ if (MLAN_STATUS_SUCCESS != woal_request_ioctl(priv, req, wait_option)) {
+ ret = MLAN_STATUS_FAILURE;
+ goto done;
+ }
+
+ if (action == MLAN_ACT_GET) {
+ memcpy(sys_cfg, &bss->param.bss_config, sizeof(mlan_uap_bss_param));
+ }
+
+ done:
+ if (req)
+ kfree(req);
+
+ LEAVE();
+ return ret;
+}
+
+/**
+ * @brief Set invalid data for each member of mlan_uap_bss_param
+ * structure
+ *
+ * @param config A pointer to mlan_uap_bss_param structure
+ *
+ * @return N/A
+ */
+void
+woal_set_sys_config_invalid_data(mlan_uap_bss_param * config)
+{
+ ENTER();
+
+ memset(config, 0, sizeof(mlan_uap_bss_param));
+ config->bcast_ssid_ctl = 0x7F;
+ config->radio_ctl = 0x7F;
+ config->dtim_period = 0x7F;
+ config->beacon_period = 0x7FFF;
+ config->tx_data_rate = 0x7FFF;
+ config->mcbc_data_rate = 0x7FFF;
+ config->tx_power_level = 0x7F;
+ config->tx_antenna = 0x7F;
+ config->rx_antenna = 0x7F;
+ config->pkt_forward_ctl = 0x7F;
+ config->max_sta_count = 0x7FFF;
+ config->auth_mode = 0x7F;
+ config->sta_ageout_timer = 0x7FFFFFFF;
+ config->pairwise_update_timeout = 0x7FFFFFFF;
+ config->pwk_retries = 0x7FFFFFFF;
+ config->groupwise_update_timeout = 0x7FFFFFFF;
+ config->gwk_retries = 0x7FFFFFFF;
+ config->mgmt_ie_passthru_mask = 0x7FFFFFFF;
+ config->ps_sta_ageout_timer = 0x7FFFFFFF;
+ config->rts_threshold = 0x7FFF;
+ config->frag_threshold = 0x7FFF;
+ config->retry_limit = 0x7FFF;
+ config->filter.filter_mode = 0x7FFF;
+ config->filter.mac_count = 0x7FFF;
+ config->wpa_cfg.rsn_protection = 0x7F;
+ config->wpa_cfg.gk_rekey_time = 0x7FFFFFFF;
+ config->enable_2040coex = 0x7F;
+ config->wmm_para.qos_info = 0x7F;
+
+ LEAVE();
+}