mirror of
https://github.com/nxp-imx/mwifiex.git
synced 2024-11-01 05:25:21 +00:00
26246bf60a
Corresponding firmware version: SDIO-UART W8987 Firmware version 16.92.21.p99.2 PCIE-UART W8997 Firmware version 16.92.21.p84.4 SDIO-UART W8997 Firmware version 16.92.21.p84.4 SDIO-UART IW416 Firmware version 16.92.21.p84.3 SDIO_UART IW612 Firmware version 18.99.2.p19.15 SDIO-UART W8801 Firmware version 14.92.36.p182 SDIO-UART W9098 Firmware version 17.92.1.p136.131 PCIE-UART W9098 Firmware version 17.92.1.p136.131 Signed-off-by: Sherry Sun <sherry.sun@nxp.com>
1919 lines
55 KiB
C
1919 lines
55 KiB
C
/** @file moal_uap_wext.c
|
|
*
|
|
* @brief This file contains wireless extension standard ioctl functions
|
|
*
|
|
*
|
|
* Copyright 2010-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:
|
|
08/06/2010: initial version
|
|
************************************************************************/
|
|
|
|
#include "moal_main.h"
|
|
#include "moal_uap.h"
|
|
#include "moal_wext.h"
|
|
#include "moal_uap_priv.h"
|
|
|
|
/********************************************************
|
|
Global Variables
|
|
********************************************************/
|
|
typedef struct _chan_to_freq_t {
|
|
/** Channel */
|
|
t_u16 channel;
|
|
/** Frequency */
|
|
t_u32 freq;
|
|
/** Band */
|
|
t_u8 band;
|
|
} chan_to_freq_t;
|
|
|
|
static const chan_to_freq_t chan_to_freq[] = {
|
|
{1, 2412, 0}, {2, 2417, 0}, {3, 2422, 0}, {4, 2427, 0},
|
|
{5, 2432, 0}, {6, 2437, 0}, {7, 2442, 0}, {8, 2447, 0},
|
|
{9, 2452, 0}, {10, 2457, 0}, {11, 2462, 0}, {12, 2467, 0},
|
|
{13, 2472, 0}, {14, 2484, 0}, {183, 4915, 1}, {184, 4920, 1},
|
|
{185, 4925, 1}, {187, 4935, 1}, {188, 4940, 1}, {189, 4945, 1},
|
|
{192, 4960, 1}, {196, 4980, 1}, {7, 5035, 1}, {8, 5040, 1},
|
|
{9, 5045, 1}, {11, 5055, 1}, {12, 5060, 1}, {16, 5080, 1},
|
|
{34, 5170, 1}, {36, 5180, 1}, {38, 5190, 1}, {40, 5200, 1},
|
|
{42, 5210, 1}, {44, 5220, 1}, {46, 5230, 1}, {48, 5240, 1},
|
|
{52, 5260, 1}, {56, 5280, 1}, {60, 5300, 1}, {64, 5320, 1},
|
|
{100, 5500, 1}, {104, 5520, 1}, {108, 5540, 1}, {112, 5560, 1},
|
|
{116, 5580, 1}, {120, 5600, 1}, {124, 5620, 1}, {128, 5640, 1},
|
|
{132, 5660, 1}, {136, 5680, 1}, {140, 5700, 1}, {144, 5720, 1},
|
|
{149, 5745, 1}, {153, 5765, 1}, {157, 5785, 1}, {161, 5805, 1},
|
|
{165, 5825, 1}, {169, 5845, 1}, {173, 5865, 1}, {177, 5885, 1},
|
|
};
|
|
|
|
/**
|
|
* iwpriv ioctl handlers
|
|
*/
|
|
static const struct iw_priv_args woal_uap_priv_args[] = {
|
|
{WOAL_UAP_SETNONE_GETNONE, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE, ""},
|
|
{WOAL_UAP_START, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE, "start"},
|
|
{WOAL_UAP_STOP, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE, "stop"},
|
|
{WOAL_AP_BSS_START, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE, "bssstart"},
|
|
{WOAL_AP_BSS_STOP, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE, "bssstop"},
|
|
{WOAL_UAP_SETONEINT_GETWORDCHAR, IW_PRIV_TYPE_INT | 1,
|
|
IW_PRIV_TYPE_CHAR | 128, ""},
|
|
{WOAL_UAP_VERSION, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_CHAR | 128,
|
|
"version"},
|
|
{WOAL_UAP_VEREXT, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_CHAR | 128,
|
|
"verext"},
|
|
{WOAL_UAP_SETONEINT_GETONEINT, IW_PRIV_TYPE_INT | 1,
|
|
IW_PRIV_TYPE_INT | 1, ""},
|
|
#ifdef WIFI_DIRECT_SUPPORT
|
|
#if defined(STA_SUPPORT) && defined(UAP_SUPPORT)
|
|
{WOAL_UAP_SET_GET_BSS_ROLE, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
|
|
"bssrole"},
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(UAP_CFG80211)
|
|
{WOAL_UAP_SET_MODE, IW_PRIV_TYPE_INT | 1, IW_PRIV_TYPE_INT | 1,
|
|
"setmode"},
|
|
#endif
|
|
{WOAL_UAP_SET_GET_256_CHAR, IW_PRIV_TYPE_CHAR | 256,
|
|
IW_PRIV_TYPE_CHAR | 256, ""},
|
|
{WOAL_WL_FW_RELOAD, IW_PRIV_TYPE_CHAR | 256, IW_PRIV_TYPE_CHAR | 256,
|
|
"fwreload"},
|
|
{WOAL_AP_SET_CFG, IW_PRIV_TYPE_CHAR | 256, IW_PRIV_TYPE_CHAR | 256,
|
|
"apcfg"},
|
|
{WOAL_UAP_HOST_CMD, IW_PRIV_TYPE_BYTE | 2047, IW_PRIV_TYPE_BYTE | 2047,
|
|
"hostcmd"},
|
|
{WOAL_UAP_FROYO_START, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE, "START"},
|
|
{WOAL_UAP_FROYO_STOP, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE, "STOP"},
|
|
{WOAL_UAP_FROYO_AP_BSS_START, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE,
|
|
"AP_BSS_START"},
|
|
{WOAL_UAP_FROYO_AP_BSS_STOP, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_NONE,
|
|
"AP_BSS_STOP"},
|
|
{WOAL_UAP_FROYO_WL_FW_RELOAD, IW_PRIV_TYPE_CHAR | 256,
|
|
IW_PRIV_TYPE_CHAR | 256, "WL_FW_RELOAD"},
|
|
{WOAL_UAP_FROYO_AP_SET_CFG, IW_PRIV_TYPE_CHAR | 256,
|
|
IW_PRIV_TYPE_CHAR | 256, "AP_SET_CFG"},
|
|
};
|
|
|
|
/** Convertion from frequency to channel */
|
|
#define freq_to_chan(x) ((((x)-2412) / 5) + 1)
|
|
|
|
/********************************************************
|
|
Local Functions
|
|
********************************************************/
|
|
|
|
/**
|
|
* @brief Sort Channels
|
|
*
|
|
* @param freq A pointer to iw_freq structure
|
|
* @param num Number of Channels
|
|
*
|
|
* @return N/A
|
|
*/
|
|
static inline void woal_sort_channels(struct iw_freq *freq, int num)
|
|
{
|
|
int i, j;
|
|
struct iw_freq temp;
|
|
|
|
for (i = 0; i < num; i++)
|
|
for (j = i + 1; j < num; j++)
|
|
if (freq[i].i > freq[j].i) {
|
|
temp.i = freq[i].i;
|
|
temp.m = freq[i].m;
|
|
|
|
freq[i].i = freq[j].i;
|
|
freq[i].m = freq[j].m;
|
|
|
|
freq[j].i = temp.i;
|
|
freq[j].m = temp.m;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Get frequency for channel in given band
|
|
*
|
|
* @param channel channel
|
|
* @param band band
|
|
*
|
|
* @return freq
|
|
*/
|
|
static int channel_to_frequency(t_u16 channel, t_u8 band)
|
|
{
|
|
int i = 0;
|
|
|
|
ENTER();
|
|
for (i = 0; i < (int)ARRAY_SIZE(chan_to_freq); i++) {
|
|
if (channel == chan_to_freq[i].channel &&
|
|
band == chan_to_freq[i].band) {
|
|
LEAVE();
|
|
return chan_to_freq[i].freq;
|
|
}
|
|
}
|
|
LEAVE();
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Commit handler: called after a bunch of SET operations
|
|
*
|
|
* @param dev A pointer to net_device structure
|
|
* @param info A pointer to iw_request_info structure
|
|
* @param cwrq A pointer to char buffer
|
|
* @param extra A pointer to extra data buf
|
|
*
|
|
* @return 0 --success
|
|
*/
|
|
static int woal_config_commit(struct net_device *dev,
|
|
struct iw_request_info *info,
|
|
union iwreq_data *cwrq, char *extra)
|
|
{
|
|
ENTER();
|
|
|
|
LEAVE();
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Get name
|
|
*
|
|
* @param dev A pointer to net_device structure
|
|
* @param info A pointer to iw_request_info structure
|
|
* @param cwrq A pointer to char buffer
|
|
* @param extra A pointer to extra data buf
|
|
*
|
|
* @return 0 --success
|
|
*/
|
|
static int woal_get_name(struct net_device *dev, struct iw_request_info *info,
|
|
union iwreq_data *wrqu, char *extra)
|
|
{
|
|
char *cwrq = wrqu->name;
|
|
ENTER();
|
|
strncpy(cwrq, "IEEE 802.11-DS", IFNAMSIZ);
|
|
LEAVE();
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Get current BSSID
|
|
*
|
|
* @param dev A pointer to net_device structure
|
|
* @param info A pointer to iw_request_info structure
|
|
* @param awrq A pointer to sockaddr structure
|
|
* @param extra A pointer to extra data buf
|
|
*
|
|
* @return 0 --success
|
|
*/
|
|
static int woal_get_wap(struct net_device *dev, struct iw_request_info *info,
|
|
union iwreq_data *wrqu, char *extra)
|
|
{
|
|
moal_private *priv = (moal_private *)netdev_priv(dev);
|
|
struct sockaddr *awrq = &wrqu->addr;
|
|
int ret = 0;
|
|
|
|
ENTER();
|
|
|
|
if (priv->bss_started)
|
|
moal_memcpy_ext(priv->phandle, awrq->sa_data,
|
|
priv->current_addr, MLAN_MAC_ADDR_LENGTH,
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 2, 0)
|
|
sizeof(awrq->sa_data_min));
|
|
#else
|
|
sizeof(awrq->sa_data));
|
|
#endif
|
|
else
|
|
memset(awrq->sa_data, 0, MLAN_MAC_ADDR_LENGTH);
|
|
awrq->sa_family = ARPHRD_ETHER;
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Change the AP BSSID
|
|
*
|
|
* @param dev A pointer to net_device structure
|
|
* @param info A pointer to iw_request_info structure
|
|
* @param awrq A pointer to iw_param structure
|
|
* @param extra A pointer to extra data buf
|
|
*
|
|
* @return 0 --success, otherwise fail
|
|
*/
|
|
static int woal_set_wap(struct net_device *dev, struct iw_request_info *info,
|
|
union iwreq_data *wrqu, char *extra)
|
|
{
|
|
int ret = 0;
|
|
moal_private *priv = (moal_private *)netdev_priv(dev);
|
|
struct sockaddr *awrq = &wrqu->addr;
|
|
const t_u8 zero_mac[MLAN_MAC_ADDR_LENGTH] = {0, 0, 0, 0, 0, 0};
|
|
|
|
ENTER();
|
|
|
|
if (awrq->sa_family != ARPHRD_ETHER) {
|
|
ret = -EINVAL;
|
|
goto done;
|
|
}
|
|
|
|
PRINTM(MINFO, "ASSOC: WAP: uAP bss : " MACSTR "\n",
|
|
MAC2STR((t_u8 *)awrq->sa_data));
|
|
|
|
/*
|
|
* Using this ioctl to start/stop the BSS, return if bss
|
|
* is already started/stopped.
|
|
*/
|
|
if (memcmp(zero_mac, awrq->sa_data, MLAN_MAC_ADDR_LENGTH)) {
|
|
if (priv->bss_started == MFALSE)
|
|
ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT,
|
|
UAP_BSS_START);
|
|
else
|
|
PRINTM(MINFO, "BSS is already started.\n");
|
|
} else {
|
|
/* zero_mac means bss_stop */
|
|
if (priv->bss_started == MTRUE)
|
|
ret = woal_uap_bss_ctrl(priv, MOAL_IOCTL_WAIT,
|
|
UAP_BSS_STOP);
|
|
else
|
|
PRINTM(MINFO, "BSS is already stopped.\n");
|
|
}
|
|
|
|
done:
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Set frequency/channel
|
|
*
|
|
* @param dev A pointer to net_device structure
|
|
* @param info A pointer to iw_request_info structure
|
|
* @param fwrq A pointer to iw_freq structure
|
|
* @param extra A pointer to extra data buf
|
|
*
|
|
* @return 0 --success, otherwise fail
|
|
*/
|
|
static int woal_set_freq(struct net_device *dev, struct iw_request_info *info,
|
|
union iwreq_data *wrqu, char *extra)
|
|
{
|
|
moal_private *priv = (moal_private *)netdev_priv(dev);
|
|
struct iw_freq *fwrq = &wrqu->freq;
|
|
mlan_uap_bss_param *sys_cfg = NULL, *ap_cfg = NULL;
|
|
int ret = 0, chan = 0, i = 0;
|
|
|
|
ENTER();
|
|
|
|
ap_cfg = kmalloc(sizeof(mlan_uap_bss_param), GFP_KERNEL);
|
|
if (ap_cfg == NULL) {
|
|
ret = -ENOMEM;
|
|
goto done;
|
|
}
|
|
|
|
sys_cfg = kmalloc(sizeof(mlan_uap_bss_param), GFP_KERNEL);
|
|
if (sys_cfg == NULL) {
|
|
ret = -ENOMEM;
|
|
goto done;
|
|
}
|
|
|
|
if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_GET,
|
|
MOAL_IOCTL_WAIT,
|
|
ap_cfg)) {
|
|
PRINTM(MERROR, "Error getting AP confiruration\n");
|
|
ret = -EFAULT;
|
|
goto done;
|
|
}
|
|
i = ap_cfg->num_of_chan;
|
|
|
|
/* Initialize the invalid values so that the correct values
|
|
* below are downloaded to firmware */
|
|
woal_set_sys_config_invalid_data(sys_cfg);
|
|
|
|
/* If setting by frequency, convert to a channel */
|
|
if (fwrq->e == 1)
|
|
chan = freq_to_chan(fwrq->m / 100000);
|
|
else
|
|
chan = fwrq->m;
|
|
if (chan > 0 && chan < MLAN_MAX_CHANNEL)
|
|
sys_cfg->channel = chan;
|
|
else {
|
|
ret = -EINVAL;
|
|
goto done;
|
|
}
|
|
for (i = 0; i < (int)ap_cfg->num_of_chan; i++)
|
|
if (ap_cfg->chan_list[i].chan_number == chan)
|
|
break;
|
|
if (i == (int)ap_cfg->num_of_chan) {
|
|
PRINTM(MERROR, "Channel %d is not supported\n", chan);
|
|
ret = -EINVAL;
|
|
goto done;
|
|
}
|
|
|
|
if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_SET,
|
|
MOAL_IOCTL_WAIT,
|
|
sys_cfg)) {
|
|
PRINTM(MERROR, "Error setting AP confiruration\n");
|
|
ret = -EFAULT;
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
kfree(sys_cfg);
|
|
kfree(ap_cfg);
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Get frequency and channel
|
|
*
|
|
* @param dev A pointer to net_device structure
|
|
* @param info A pointer to iw_request_info structure
|
|
* @param fwrq A pointer to iw_freq structure
|
|
* @param extra A pointer to extra data buf
|
|
*
|
|
* @return 0 --success, otherwise fail
|
|
*/
|
|
static int woal_get_freq(struct net_device *dev, struct iw_request_info *info,
|
|
union iwreq_data *wrqu, char *extra)
|
|
{
|
|
moal_private *priv = (moal_private *)netdev_priv(dev);
|
|
struct iw_freq *fwrq = &wrqu->freq;
|
|
mlan_uap_bss_param *ap_cfg = NULL;
|
|
t_u8 band = 0;
|
|
int ret = 0;
|
|
|
|
ENTER();
|
|
|
|
ap_cfg = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
|
|
if (!ap_cfg) {
|
|
PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
|
|
return -EFAULT;
|
|
}
|
|
|
|
if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_GET,
|
|
MOAL_IOCTL_WAIT,
|
|
ap_cfg)) {
|
|
PRINTM(MERROR, "Error getting AP confiruration\n");
|
|
kfree(ap_cfg);
|
|
LEAVE();
|
|
return -EFAULT;
|
|
}
|
|
|
|
band = (((ap_cfg->bandcfg.chanBand == BAND_5GHZ) ? 1 : 0));
|
|
fwrq->m = (long)channel_to_frequency(ap_cfg->channel, band);
|
|
fwrq->i = (long)ap_cfg->channel;
|
|
fwrq->e = 6;
|
|
|
|
kfree(ap_cfg);
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Set wlan mode
|
|
*
|
|
* @param dev A pointer to net_device structure
|
|
* @param info A pointer to iw_request_info structure
|
|
* @param uwrq A pointer to t_u32 string
|
|
* @param extra A pointer to extra data buf
|
|
*
|
|
* @return 0 --success, otherwise fail
|
|
*/
|
|
static int woal_set_bss_mode(struct net_device *dev,
|
|
struct iw_request_info *info,
|
|
union iwreq_data *wrqu, char *extra)
|
|
{
|
|
int ret = 0;
|
|
t_u32 *uwrq = &wrqu->mode;
|
|
ENTER();
|
|
|
|
switch (*uwrq) {
|
|
case IW_MODE_AUTO:
|
|
case IW_MODE_MASTER:
|
|
PRINTM(MINFO, "This is correct mode in AP mode\n");
|
|
break;
|
|
default:
|
|
PRINTM(MERROR, "Invalid mode for AP\n");
|
|
ret = -EINVAL;
|
|
}
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Get wlan mode
|
|
*
|
|
* @param dev A pointer to net_device structure
|
|
* @param info A pointer to iw_request_info structure
|
|
* @param uwrq A pointer to t_u32 string
|
|
* @param extra A pointer to extra data buf
|
|
*
|
|
* @return 0 --success
|
|
*/
|
|
static int woal_get_bss_mode(struct net_device *dev,
|
|
struct iw_request_info *info,
|
|
union iwreq_data *wrqu, char *extra)
|
|
{
|
|
t_u32 *uwrq = &wrqu->mode;
|
|
ENTER();
|
|
|
|
*uwrq = IW_MODE_MASTER;
|
|
|
|
LEAVE();
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Set encryption key
|
|
*
|
|
* @param dev A pointer to net_device structure
|
|
* @param info A pointer to iw_request_info structure
|
|
* @param dwrq A pointer to iw_point structure
|
|
* @param extra A pointer to extra data buf
|
|
*
|
|
* @return 0 --success, otherwise fail
|
|
*/
|
|
static int woal_set_encode(struct net_device *dev, struct iw_request_info *info,
|
|
struct iw_point *dwrq, char *extra)
|
|
{
|
|
int ret = 0;
|
|
moal_private *priv = (moal_private *)netdev_priv(dev);
|
|
mlan_uap_bss_param *sys_cfg = NULL, *ap_cfg = NULL;
|
|
wep_key *pkey = NULL;
|
|
int key_index = 0;
|
|
|
|
ENTER();
|
|
|
|
/* Check index */
|
|
key_index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
|
|
if (key_index > 3) {
|
|
PRINTM(MERROR, "Key index #%d out of range\n", key_index);
|
|
ret = -EINVAL;
|
|
goto done;
|
|
}
|
|
|
|
ap_cfg = kmalloc(sizeof(mlan_uap_bss_param), GFP_KERNEL);
|
|
if (ap_cfg == NULL) {
|
|
ret = -ENOMEM;
|
|
goto done;
|
|
}
|
|
|
|
sys_cfg = kmalloc(sizeof(mlan_uap_bss_param), GFP_KERNEL);
|
|
if (sys_cfg == NULL) {
|
|
ret = -ENOMEM;
|
|
goto done;
|
|
}
|
|
|
|
if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_GET,
|
|
MOAL_IOCTL_WAIT,
|
|
ap_cfg)) {
|
|
PRINTM(MERROR, "Error getting AP confiruration\n");
|
|
ret = -EFAULT;
|
|
goto done;
|
|
}
|
|
|
|
/* Initialize the invalid values so that the correct values
|
|
* below are downloaded to firmware */
|
|
woal_set_sys_config_invalid_data(sys_cfg);
|
|
sys_cfg->wep_cfg.key0.key_index = 0;
|
|
sys_cfg->wep_cfg.key1.key_index = 1;
|
|
sys_cfg->wep_cfg.key2.key_index = 2;
|
|
sys_cfg->wep_cfg.key3.key_index = 3;
|
|
|
|
if (key_index >= 0 && key_index <= 3) {
|
|
if (key_index == 0)
|
|
pkey = &sys_cfg->wep_cfg.key0;
|
|
else if (key_index == 1)
|
|
pkey = &sys_cfg->wep_cfg.key1;
|
|
else if (key_index == 2)
|
|
pkey = &sys_cfg->wep_cfg.key2;
|
|
else if (key_index == 3)
|
|
pkey = &sys_cfg->wep_cfg.key3;
|
|
}
|
|
|
|
if (!(dwrq->flags & IW_ENCODE_NOKEY) && dwrq->length) {
|
|
if (dwrq->length > MAX_WEP_KEY_SIZE) {
|
|
PRINTM(MERROR, "Key length (%d) out of range\n",
|
|
dwrq->length);
|
|
ret = -E2BIG;
|
|
goto done;
|
|
}
|
|
if (key_index < 0) {
|
|
/* Get current default key index */
|
|
if (ap_cfg->wep_cfg.key0.is_default)
|
|
pkey = &sys_cfg->wep_cfg.key0;
|
|
if (ap_cfg->wep_cfg.key1.is_default)
|
|
pkey = &sys_cfg->wep_cfg.key1;
|
|
if (ap_cfg->wep_cfg.key2.is_default)
|
|
pkey = &sys_cfg->wep_cfg.key2;
|
|
if (ap_cfg->wep_cfg.key3.is_default)
|
|
pkey = &sys_cfg->wep_cfg.key3;
|
|
else { /* Something wrong, select first key as default
|
|
*/
|
|
PRINTM(MERROR,
|
|
"No default key set! Selecting first key.\n");
|
|
pkey = &sys_cfg->wep_cfg.key0;
|
|
}
|
|
}
|
|
|
|
sys_cfg->protocol = PROTOCOL_STATIC_WEP;
|
|
if (extra)
|
|
moal_memcpy_ext(priv->phandle, pkey->key, extra,
|
|
dwrq->length, sizeof(pkey->key));
|
|
/* Set the length */
|
|
if (dwrq->length > MIN_WEP_KEY_SIZE)
|
|
pkey->length = MAX_WEP_KEY_SIZE;
|
|
else
|
|
pkey->length = MIN_WEP_KEY_SIZE;
|
|
/* Set current key index as default */
|
|
pkey->is_default = MTRUE;
|
|
} else {
|
|
/*
|
|
* No key provided so it is either enable key,
|
|
* on or off
|
|
*/
|
|
if (dwrq->flags & IW_ENCODE_DISABLED) {
|
|
PRINTM(MINFO, "*** iwconfig mlanX key off ***\n");
|
|
sys_cfg->protocol = PROTOCOL_NO_SECURITY;
|
|
} else {
|
|
/*
|
|
* iwconfig mlanX key [n]
|
|
* iwconfig mlanX key on
|
|
* Do we want to just set the transmit key index ?
|
|
*/
|
|
if (key_index < 0) {
|
|
PRINTM(MINFO,
|
|
"*** iwconfig mlanX key on ***\n");
|
|
} else {
|
|
/* Get current key configuration at key_index */
|
|
if (key_index == 0)
|
|
moal_memcpy_ext(priv->phandle, pkey,
|
|
&ap_cfg->wep_cfg.key0,
|
|
sizeof(wep_key),
|
|
sizeof(wep_key));
|
|
if (key_index == 1)
|
|
moal_memcpy_ext(priv->phandle, pkey,
|
|
&ap_cfg->wep_cfg.key1,
|
|
sizeof(wep_key),
|
|
sizeof(wep_key));
|
|
if (key_index == 2)
|
|
moal_memcpy_ext(priv->phandle, pkey,
|
|
&ap_cfg->wep_cfg.key2,
|
|
sizeof(wep_key),
|
|
sizeof(wep_key));
|
|
if (key_index == 3)
|
|
moal_memcpy_ext(priv->phandle, pkey,
|
|
&ap_cfg->wep_cfg.key3,
|
|
sizeof(wep_key),
|
|
sizeof(wep_key));
|
|
/* Set current key index as default */
|
|
pkey->is_default = MTRUE;
|
|
}
|
|
}
|
|
}
|
|
if (dwrq->flags & (IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN)) {
|
|
switch (dwrq->flags & 0xf000) {
|
|
case IW_ENCODE_RESTRICTED:
|
|
/* iwconfig mlanX restricted key [1] */
|
|
sys_cfg->auth_mode = MLAN_AUTH_MODE_SHARED;
|
|
PRINTM(MINFO, "Auth mode restricted!\n");
|
|
break;
|
|
case IW_ENCODE_OPEN:
|
|
/* iwconfig mlanX key [2] open */
|
|
sys_cfg->auth_mode = MLAN_AUTH_MODE_OPEN;
|
|
PRINTM(MINFO, "Auth mode open!\n");
|
|
break;
|
|
case IW_ENCODE_RESTRICTED | IW_ENCODE_OPEN:
|
|
default:
|
|
/* iwconfig mlanX key [2] open restricted */
|
|
PRINTM(MINFO, "Auth mode auto!\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_SET,
|
|
MOAL_IOCTL_WAIT,
|
|
sys_cfg)) {
|
|
PRINTM(MERROR, "Error setting AP confiruration\n");
|
|
ret = -EFAULT;
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
kfree(sys_cfg);
|
|
kfree(ap_cfg);
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Get encryption key
|
|
*
|
|
* @param dev A pointer to net_device structure
|
|
* @param info A pointer to iw_request_info structure
|
|
* @param dwrq A pointer to iw_point structure
|
|
* @param extra A pointer to extra data buf
|
|
*
|
|
* @return 0 --success, otherwise fail
|
|
*/
|
|
static int woal_get_encode(struct net_device *dev, struct iw_request_info *info,
|
|
union iwreq_data *wrqu, char *extra)
|
|
{
|
|
moal_private *priv = (moal_private *)netdev_priv(dev);
|
|
struct iw_point *dwrq = &wrqu->data;
|
|
int index = (dwrq->flags & IW_ENCODE_INDEX);
|
|
wep_key *pkey = NULL;
|
|
mlan_uap_bss_param *ap_cfg = NULL;
|
|
int ret = 0;
|
|
|
|
ENTER();
|
|
if (index < 0 || index > 4) {
|
|
PRINTM(MERROR, "Key index #%d out of range\n", index);
|
|
ret = -EINVAL;
|
|
goto done;
|
|
}
|
|
ap_cfg = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
|
|
if (!ap_cfg) {
|
|
PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
|
|
ret = -EFAULT;
|
|
goto done;
|
|
}
|
|
|
|
if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_GET,
|
|
MOAL_IOCTL_WAIT,
|
|
ap_cfg)) {
|
|
PRINTM(MERROR, "Error getting AP confiruration\n");
|
|
ret = -EFAULT;
|
|
goto done;
|
|
}
|
|
|
|
dwrq->flags = 0;
|
|
/*
|
|
* Check encryption mode
|
|
*/
|
|
switch (ap_cfg->auth_mode) {
|
|
case MLAN_AUTH_MODE_OPEN:
|
|
dwrq->flags = IW_ENCODE_OPEN;
|
|
break;
|
|
case MLAN_AUTH_MODE_SHARED:
|
|
case MLAN_AUTH_MODE_NETWORKEAP:
|
|
dwrq->flags = IW_ENCODE_RESTRICTED;
|
|
break;
|
|
default:
|
|
dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN;
|
|
break;
|
|
}
|
|
|
|
switch (ap_cfg->protocol) {
|
|
case PROTOCOL_NO_SECURITY:
|
|
dwrq->flags |= IW_ENCODE_DISABLED;
|
|
break;
|
|
case PROTOCOL_STATIC_WEP:
|
|
if (ap_cfg->wep_cfg.key0.is_default)
|
|
pkey = &ap_cfg->wep_cfg.key0;
|
|
else if (ap_cfg->wep_cfg.key1.is_default)
|
|
pkey = &ap_cfg->wep_cfg.key1;
|
|
else if (ap_cfg->wep_cfg.key2.is_default)
|
|
pkey = &ap_cfg->wep_cfg.key2;
|
|
else if (ap_cfg->wep_cfg.key3.is_default)
|
|
pkey = &ap_cfg->wep_cfg.key3;
|
|
if (pkey) {
|
|
dwrq->flags |= (pkey->key_index + 1);
|
|
dwrq->length = pkey->length;
|
|
moal_memcpy_ext(priv->phandle, extra, pkey->key,
|
|
pkey->length, pkey->length);
|
|
dwrq->flags &= ~IW_ENCODE_DISABLED;
|
|
} else {
|
|
ret = -EFAULT;
|
|
}
|
|
break;
|
|
case PROTOCOL_WPA:
|
|
case PROTOCOL_WPA2:
|
|
case PROTOCOL_WPA2_MIXED:
|
|
moal_memcpy_ext(priv->phandle, extra,
|
|
ap_cfg->wpa_cfg.passphrase,
|
|
ap_cfg->wpa_cfg.length, ap_cfg->wpa_cfg.length);
|
|
if (ap_cfg->wpa_cfg.length)
|
|
dwrq->length = ap_cfg->wpa_cfg.length;
|
|
else
|
|
dwrq->length = 16;
|
|
dwrq->flags |= 1;
|
|
dwrq->flags &= ~IW_ENCODE_DISABLED;
|
|
break;
|
|
default:
|
|
dwrq->flags &= ~IW_ENCODE_DISABLED;
|
|
break;
|
|
}
|
|
dwrq->flags |= IW_ENCODE_NOKEY;
|
|
|
|
done:
|
|
kfree(ap_cfg);
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
#if (WIRELESS_EXT >= 18)
|
|
/**
|
|
* @brief Get IE
|
|
*
|
|
* @param dev A pointer to net_device structure
|
|
* @param info A pointer to iw_request_info structure
|
|
* @param dwrq A pointer to iw_point structure
|
|
* @param extra A pointer to extra data buf
|
|
*
|
|
* @return -EOPNOTSUPP
|
|
*/
|
|
static int woal_get_gen_ie(struct net_device *dev, struct iw_request_info *info,
|
|
union iwreq_data *wrqu, char *extra)
|
|
{
|
|
ENTER();
|
|
LEAVE();
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
/**
|
|
* @brief Set IE
|
|
*
|
|
* Pass an opaque block of data, expected to be IEEE IEs, to the driver
|
|
* for eventual passthrough to the firmware in an associate/join
|
|
* (and potentially start) command.
|
|
*
|
|
* @param dev A pointer to net_device structure
|
|
* @param info A pointer to iw_request_info structure
|
|
* @param dwrq A pointer to iw_point structure
|
|
* @param extra A pointer to extra data buf
|
|
*
|
|
* @return 0 --success, otherwise fail
|
|
*/
|
|
static int woal_set_gen_ie(struct net_device *dev, struct iw_request_info *info,
|
|
union iwreq_data *wrqu, char *extra)
|
|
{
|
|
moal_private *priv = (moal_private *)netdev_priv(dev);
|
|
struct iw_point *dwrq = &wrqu->data;
|
|
mlan_uap_bss_param *sys_cfg = NULL;
|
|
IEEEtypes_Header_t *tlv = NULL;
|
|
int tlv_hdr_len = sizeof(IEEEtypes_Header_t), tlv_buf_left = 0;
|
|
int ret = 0;
|
|
|
|
ENTER();
|
|
|
|
sys_cfg = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
|
|
if (!sys_cfg) {
|
|
PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
|
|
LEAVE();
|
|
return -EFAULT;
|
|
}
|
|
|
|
/* Initialize the invalid values so that the correct values
|
|
* below are downloaded to firmware */
|
|
woal_set_sys_config_invalid_data(sys_cfg);
|
|
|
|
tlv_buf_left = dwrq->length;
|
|
tlv = (IEEEtypes_Header_t *)extra;
|
|
while (tlv_buf_left >= tlv_hdr_len) {
|
|
if (tlv->element_id == WPA_IE) {
|
|
sys_cfg->protocol |= PROTOCOL_WPA;
|
|
if (priv->pairwise_cipher == CIPHER_TKIP) {
|
|
sys_cfg->wpa_cfg.pairwise_cipher_wpa =
|
|
CIPHER_TKIP;
|
|
PRINTM(MINFO, "Set IE Cipher TKIP\n");
|
|
}
|
|
if (priv->pairwise_cipher == CIPHER_AES_CCMP) {
|
|
sys_cfg->wpa_cfg.pairwise_cipher_wpa =
|
|
CIPHER_AES_CCMP;
|
|
PRINTM(MINFO, "Set IE Cipher CCMP\n");
|
|
}
|
|
if (priv->pairwise_cipher ==
|
|
(CIPHER_TKIP | CIPHER_AES_CCMP)) {
|
|
sys_cfg->wpa_cfg.pairwise_cipher_wpa =
|
|
CIPHER_TKIP | CIPHER_AES_CCMP;
|
|
PRINTM(MINFO, "Set IE Cipher TKIP + CCMP\n");
|
|
}
|
|
moal_memcpy_ext(priv->phandle,
|
|
priv->bcn_ie_buf + priv->bcn_ie_len,
|
|
((t_u8 *)tlv),
|
|
sizeof(IEEEtypes_Header_t) + tlv->len,
|
|
sizeof(priv->bcn_ie_buf) -
|
|
priv->bcn_ie_len);
|
|
priv->bcn_ie_len +=
|
|
sizeof(IEEEtypes_Header_t) + tlv->len;
|
|
}
|
|
if (tlv->element_id == RSN_IE) {
|
|
sys_cfg->protocol |= PROTOCOL_WPA2;
|
|
if (priv->pairwise_cipher == CIPHER_TKIP) {
|
|
sys_cfg->wpa_cfg.pairwise_cipher_wpa2 =
|
|
CIPHER_TKIP;
|
|
}
|
|
if (priv->pairwise_cipher == CIPHER_AES_CCMP) {
|
|
sys_cfg->wpa_cfg.pairwise_cipher_wpa2 =
|
|
CIPHER_AES_CCMP;
|
|
}
|
|
if (priv->pairwise_cipher ==
|
|
(CIPHER_TKIP | CIPHER_AES_CCMP)) {
|
|
sys_cfg->wpa_cfg.pairwise_cipher_wpa2 =
|
|
(CIPHER_TKIP | CIPHER_AES_CCMP);
|
|
}
|
|
moal_memcpy_ext(priv->phandle,
|
|
priv->bcn_ie_buf + priv->bcn_ie_len,
|
|
((t_u8 *)tlv),
|
|
sizeof(IEEEtypes_Header_t) + tlv->len,
|
|
sizeof(priv->bcn_ie_buf) -
|
|
priv->bcn_ie_len);
|
|
priv->bcn_ie_len +=
|
|
sizeof(IEEEtypes_Header_t) + tlv->len;
|
|
}
|
|
if (priv->group_cipher == CIPHER_TKIP)
|
|
sys_cfg->wpa_cfg.group_cipher = CIPHER_TKIP;
|
|
if (priv->group_cipher == CIPHER_AES_CCMP)
|
|
sys_cfg->wpa_cfg.group_cipher = CIPHER_AES_CCMP;
|
|
tlv_buf_left -= (tlv_hdr_len + tlv->len);
|
|
tlv = (IEEEtypes_Header_t *)((t_u8 *)tlv + tlv_hdr_len +
|
|
tlv->len);
|
|
}
|
|
sys_cfg->key_mgmt = priv->uap_key_mgmt;
|
|
if (sys_cfg->key_mgmt & KEY_MGMT_PSK)
|
|
sys_cfg->key_mgmt_operation |= 0x01;
|
|
if (sys_cfg->key_mgmt & KEY_MGMT_EAP)
|
|
sys_cfg->key_mgmt_operation |= 0x03;
|
|
|
|
if (sys_cfg->protocol) {
|
|
if (MLAN_STATUS_SUCCESS !=
|
|
woal_set_get_sys_config(priv, MLAN_ACT_SET, MOAL_IOCTL_WAIT,
|
|
sys_cfg)) {
|
|
PRINTM(MERROR, "Error setting AP configuration\n");
|
|
ret = -EFAULT;
|
|
goto done;
|
|
}
|
|
priv->pairwise_cipher = 0;
|
|
priv->group_cipher = 0;
|
|
|
|
/* custom IE command to set priv->bcn_ie_buf */
|
|
if (MLAN_STATUS_SUCCESS !=
|
|
#define UAP_RSN_MASK (BIT(8) | BIT(5) | BIT(1) | BIT(3))
|
|
woal_set_get_custom_ie(priv, UAP_RSN_MASK, priv->bcn_ie_buf,
|
|
priv->bcn_ie_len)) {
|
|
PRINTM(MERROR, "Error setting wpa-rsn IE\n");
|
|
ret = -EFAULT;
|
|
}
|
|
} else if (dwrq->length == 0) {
|
|
/* custom IE command to re-set priv->bcn_ie_buf */
|
|
if (MLAN_STATUS_SUCCESS !=
|
|
woal_set_get_custom_ie(priv, 0, priv->bcn_ie_buf,
|
|
priv->bcn_ie_len)) {
|
|
PRINTM(MERROR, "Error resetting wpa-rsn IE\n");
|
|
ret = -EFAULT;
|
|
}
|
|
priv->bcn_ie_len = 0;
|
|
}
|
|
|
|
done:
|
|
kfree(sys_cfg);
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Extended version of encoding configuration
|
|
*
|
|
* @param dev A pointer to net_device structure
|
|
* @param info A pointer to iw_request_info structure
|
|
* @param dwrq A pointer to iw_point structure
|
|
* @param extra A pointer to extra data buf
|
|
*
|
|
* @return 0 --success, otherwise fail
|
|
*/
|
|
static int woal_set_encode_ext(struct net_device *dev,
|
|
struct iw_request_info *info,
|
|
union iwreq_data *wrqu, char *extra)
|
|
{
|
|
struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
|
|
moal_private *priv = (moal_private *)netdev_priv(dev);
|
|
struct iw_point *dwrq = &wrqu->data;
|
|
int key_index;
|
|
t_u8 *pkey_material = NULL;
|
|
mlan_ioctl_req *req = NULL;
|
|
mlan_ds_sec_cfg *sec = NULL;
|
|
mlan_uap_bss_param *sys_cfg = NULL;
|
|
wep_key *pwep_key = NULL;
|
|
int ret = 0;
|
|
mlan_status status = MLAN_STATUS_SUCCESS;
|
|
|
|
ENTER();
|
|
|
|
key_index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
|
|
if (key_index < 0 || key_index > 5) {
|
|
ret = -EINVAL;
|
|
goto done;
|
|
}
|
|
if (ext->key_len > (dwrq->length - sizeof(struct iw_encode_ext))) {
|
|
ret = -EINVAL;
|
|
goto done;
|
|
}
|
|
sys_cfg = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
|
|
if (!sys_cfg) {
|
|
PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
|
|
ret = -EFAULT;
|
|
goto done;
|
|
}
|
|
|
|
/* Initialize the invalid values so that the correct values
|
|
* below are downloaded to firmware */
|
|
woal_set_sys_config_invalid_data(sys_cfg);
|
|
|
|
pkey_material = (t_u8 *)(ext + 1);
|
|
/* Disable Key */
|
|
if ((dwrq->flags & IW_ENCODE_DISABLED) && !ext->key_len) {
|
|
sys_cfg->protocol = PROTOCOL_NO_SECURITY;
|
|
} else if (ext->alg == IW_ENCODE_ALG_WEP) {
|
|
sys_cfg->protocol = PROTOCOL_STATIC_WEP;
|
|
/* Set WEP key */
|
|
switch (key_index) {
|
|
case 0:
|
|
pwep_key = &sys_cfg->wep_cfg.key0;
|
|
break;
|
|
case 1:
|
|
pwep_key = &sys_cfg->wep_cfg.key1;
|
|
break;
|
|
case 2:
|
|
pwep_key = &sys_cfg->wep_cfg.key2;
|
|
break;
|
|
case 3:
|
|
pwep_key = &sys_cfg->wep_cfg.key3;
|
|
break;
|
|
}
|
|
if (pwep_key) {
|
|
pwep_key->key_index = key_index;
|
|
pwep_key->is_default = MTRUE;
|
|
pwep_key->length = ext->key_len;
|
|
moal_memcpy_ext(priv->phandle, pwep_key->key,
|
|
pkey_material, ext->key_len,
|
|
sizeof(pwep_key->key));
|
|
}
|
|
} else {
|
|
/* Set GTK/PTK key */
|
|
req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_sec_cfg));
|
|
if (req == NULL) {
|
|
ret = -ENOMEM;
|
|
goto done;
|
|
}
|
|
sec = (mlan_ds_sec_cfg *)req->pbuf;
|
|
sec->sub_command = MLAN_OID_SEC_CFG_ENCRYPT_KEY;
|
|
req->req_id = MLAN_IOCTL_SEC_CFG;
|
|
req->action = MLAN_ACT_SET;
|
|
sec->param.encrypt_key.key_len = ext->key_len;
|
|
sec->param.encrypt_key.key_index = key_index;
|
|
moal_memcpy_ext(priv->phandle,
|
|
sec->param.encrypt_key.key_material,
|
|
pkey_material, ext->key_len,
|
|
sizeof(sec->param.encrypt_key.key_material));
|
|
moal_memcpy_ext(priv->phandle, sec->param.encrypt_key.mac_addr,
|
|
ext->addr.sa_data, ETH_ALEN,
|
|
sizeof(sec->param.encrypt_key.mac_addr));
|
|
sec->param.encrypt_key.key_flags = ext->ext_flags;
|
|
if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
|
|
moal_memcpy_ext(priv->phandle,
|
|
sec->param.encrypt_key.pn,
|
|
(t_u8 *)ext->rx_seq, SEQ_MAX_SIZE,
|
|
sizeof(sec->param.encrypt_key.pn));
|
|
DBG_HEXDUMP(MCMD_D, "Uap Rx PN",
|
|
sec->param.encrypt_key.pn, SEQ_MAX_SIZE);
|
|
}
|
|
if (ext->ext_flags & IW_ENCODE_EXT_TX_SEQ_VALID) {
|
|
moal_memcpy_ext(priv->phandle,
|
|
sec->param.encrypt_key.pn,
|
|
(t_u8 *)ext->tx_seq, SEQ_MAX_SIZE,
|
|
sizeof(sec->param.encrypt_key.pn));
|
|
DBG_HEXDUMP(MCMD_D, "Uap Tx PN",
|
|
sec->param.encrypt_key.pn, SEQ_MAX_SIZE);
|
|
}
|
|
PRINTM(MIOCTL,
|
|
"set uap wpa key key_index=%d, key_len=%d key_flags=0x%x " MACSTR
|
|
"\n",
|
|
key_index, ext->key_len,
|
|
sec->param.encrypt_key.key_flags,
|
|
MAC2STR(sec->param.encrypt_key.mac_addr));
|
|
DBG_HEXDUMP(MCMD_D, "uap wpa key", pkey_material, ext->key_len);
|
|
#define IW_ENCODE_ALG_AES_CMAC 5
|
|
|
|
if (ext->alg == IW_ENCODE_ALG_AES_CMAC)
|
|
sec->param.encrypt_key.key_flags |=
|
|
KEY_FLAG_AES_MCAST_IGTK;
|
|
status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
|
|
if (status != MLAN_STATUS_SUCCESS)
|
|
ret = -EFAULT;
|
|
/* Cipher set will be done in set generic IE */
|
|
priv->pairwise_cipher = ext->alg;
|
|
priv->group_cipher = ext->alg;
|
|
goto done; /* No AP configuration */
|
|
}
|
|
if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_SET,
|
|
MOAL_IOCTL_WAIT,
|
|
sys_cfg)) {
|
|
PRINTM(MERROR, "Error setting AP confiruration\n");
|
|
ret = -EFAULT;
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
kfree(sys_cfg);
|
|
if (status != MLAN_STATUS_PENDING)
|
|
kfree(req);
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Extended version of encoding configuration
|
|
*
|
|
* @param dev A pointer to net_device structure
|
|
* @param info A pointer to iw_request_info structure
|
|
* @param dwrq A pointer to iw_point structure
|
|
* @param extra A pointer to extra data buf
|
|
*
|
|
* @return -EOPNOTSUPP
|
|
*/
|
|
static int woal_get_encode_ext(struct net_device *dev,
|
|
struct iw_request_info *info,
|
|
union iwreq_data *wrqu, char *extra)
|
|
{
|
|
ENTER();
|
|
LEAVE();
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
/**
|
|
* @brief Request MLME operation
|
|
*
|
|
* @param dev A pointer to net_device structure
|
|
* @param info A pointer to iw_request_info structure
|
|
* @param dwrq A pointer to iw_point structure
|
|
* @param extra A pointer to extra data buf
|
|
*
|
|
* @return 0--success, otherwise fail
|
|
*/
|
|
static int woal_set_mlme(struct net_device *dev, struct iw_request_info *info,
|
|
union iwreq_data *wrqu, char *extra)
|
|
{
|
|
struct iw_mlme *mlme = (struct iw_mlme *)extra;
|
|
moal_private *priv = (moal_private *)netdev_priv(dev);
|
|
mlan_ds_bss *bss = NULL;
|
|
mlan_ds_get_info *pinfo = NULL;
|
|
mlan_ioctl_req *req = NULL;
|
|
mlan_ds_sta_list *sta_list = NULL;
|
|
const t_u8 bc_addr[] = {0XFF, 0XFF, 0XFF, 0XFF, 0XFF, 0XFF};
|
|
t_u8 sta_addr[ETH_ALEN];
|
|
int ret = 0, i;
|
|
mlan_status status = MLAN_STATUS_SUCCESS;
|
|
|
|
ENTER();
|
|
|
|
memset(sta_addr, 0, ETH_ALEN);
|
|
if ((mlme->cmd == IW_MLME_DEAUTH) || (mlme->cmd == IW_MLME_DISASSOC)) {
|
|
moal_memcpy_ext(priv->phandle, sta_addr,
|
|
(t_u8 *)mlme->addr.sa_data, ETH_ALEN,
|
|
sizeof(sta_addr));
|
|
PRINTM(MIOCTL, "Deauth station: " MACSTR ", reason=%d\n",
|
|
MAC2STR(sta_addr), mlme->reason_code);
|
|
|
|
/* FIXME: For flushing all stations we need to use zero MAC,
|
|
* but right now the FW does not support this. So, manually
|
|
* delete each one individually.
|
|
*/
|
|
/* If deauth all station, get the connected STA list first */
|
|
if (!memcmp(bc_addr, sta_addr, ETH_ALEN)) {
|
|
PRINTM(MIOCTL, "Deauth all stations\n");
|
|
req = woal_alloc_mlan_ioctl_req(
|
|
sizeof(mlan_ds_get_info) +
|
|
(MAX_STA_LIST_IE_SIZE * MAX_NUM_CLIENTS));
|
|
if (req == NULL) {
|
|
LEAVE();
|
|
return -ENOMEM;
|
|
}
|
|
pinfo = (mlan_ds_get_info *)req->pbuf;
|
|
pinfo->sub_command = MLAN_OID_UAP_STA_LIST;
|
|
req->req_id = MLAN_IOCTL_GET_INFO;
|
|
req->action = MLAN_ACT_GET;
|
|
status = woal_request_ioctl(priv, req, MOAL_IOCTL_WAIT);
|
|
if (status != MLAN_STATUS_SUCCESS) {
|
|
ret = -EFAULT;
|
|
goto done;
|
|
}
|
|
sta_list =
|
|
kmalloc(sizeof(mlan_ds_sta_list), GFP_KERNEL);
|
|
if (sta_list == NULL) {
|
|
PRINTM(MERROR, "Memory allocation failed!\n");
|
|
ret = -ENOMEM;
|
|
goto done;
|
|
}
|
|
moal_memcpy_ext(priv->phandle, sta_list,
|
|
&pinfo->param.sta_list,
|
|
sizeof(mlan_ds_sta_list),
|
|
sizeof(mlan_ds_sta_list));
|
|
kfree(req);
|
|
req = NULL;
|
|
}
|
|
req = woal_alloc_mlan_ioctl_req(sizeof(mlan_ds_bss));
|
|
if (req == NULL) {
|
|
ret = -ENOMEM;
|
|
goto done;
|
|
}
|
|
bss = (mlan_ds_bss *)req->pbuf;
|
|
bss->sub_command = MLAN_OID_UAP_DEAUTH_STA;
|
|
req->req_id = MLAN_IOCTL_BSS;
|
|
req->action = MLAN_ACT_SET;
|
|
|
|
if (sta_list && !memcmp(bc_addr, sta_addr, ETH_ALEN)) {
|
|
for (i = 0; i < sta_list->sta_count; i++) {
|
|
moal_memcpy_ext(
|
|
priv->phandle,
|
|
bss->param.deauth_param.mac_addr,
|
|
sta_list->info[i].mac_address, ETH_ALEN,
|
|
sizeof(bss->param.deauth_param
|
|
.mac_addr));
|
|
bss->param.deauth_param.reason_code =
|
|
mlme->reason_code;
|
|
|
|
status = woal_request_ioctl(priv, req,
|
|
MOAL_IOCTL_WAIT);
|
|
if (status != MLAN_STATUS_SUCCESS) {
|
|
ret = -EFAULT;
|
|
goto done;
|
|
}
|
|
}
|
|
} else {
|
|
moal_memcpy_ext(
|
|
priv->phandle, bss->param.deauth_param.mac_addr,
|
|
sta_addr, ETH_ALEN,
|
|
sizeof(bss->param.deauth_param.mac_addr));
|
|
bss->param.deauth_param.reason_code = mlme->reason_code;
|
|
|
|
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);
|
|
kfree(sta_list);
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/** @brief Set authentication mode parameters
|
|
*
|
|
* @param dev A pointer to net_device structure
|
|
* @param info A pointer to iw_request_info structure
|
|
* @param vwrq A pointer to iw_param structure
|
|
* @param extra A pointer to extra data buf
|
|
*
|
|
* @return 0 --success, otherwise fail
|
|
*/
|
|
static int woal_set_auth(struct net_device *dev, struct iw_request_info *info,
|
|
union iwreq_data *wrqu, char *extra)
|
|
{
|
|
moal_private *priv = (moal_private *)netdev_priv(dev);
|
|
struct iw_param *vwrq = &wrqu->param;
|
|
mlan_uap_bss_param *sys_cfg = NULL;
|
|
|
|
ENTER();
|
|
|
|
sys_cfg = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
|
|
if (!sys_cfg) {
|
|
PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
|
|
LEAVE();
|
|
return -EFAULT;
|
|
}
|
|
/* Initialize the invalid values so that the correct values
|
|
* below are downloaded to firmware */
|
|
woal_set_sys_config_invalid_data(sys_cfg);
|
|
|
|
switch (vwrq->flags & IW_AUTH_INDEX) {
|
|
case IW_AUTH_CIPHER_PAIRWISE:
|
|
/* Rest are not supported now */
|
|
if (vwrq->value & IW_AUTH_CIPHER_NONE)
|
|
/* XXX Do not delete no-operation line */
|
|
;
|
|
else if (vwrq->value & IW_AUTH_CIPHER_WEP40)
|
|
/* XXX Do not delete no-operation line */
|
|
;
|
|
else if (vwrq->value & IW_AUTH_CIPHER_WEP104)
|
|
/* XXX Do not delete no-operation line */
|
|
;
|
|
else if (vwrq->value == IW_AUTH_CIPHER_TKIP) {
|
|
sys_cfg->wpa_cfg.pairwise_cipher_wpa = CIPHER_TKIP;
|
|
sys_cfg->wpa_cfg.pairwise_cipher_wpa2 = CIPHER_TKIP;
|
|
priv->pairwise_cipher = CIPHER_TKIP;
|
|
if (!priv->uap_key_mgmt)
|
|
priv->uap_key_mgmt = KEY_MGMT_PSK;
|
|
PRINTM(MINFO, "Set Auth Cipher TKIP\n");
|
|
} else if (vwrq->value == IW_AUTH_CIPHER_CCMP) {
|
|
sys_cfg->wpa_cfg.pairwise_cipher_wpa = CIPHER_AES_CCMP;
|
|
sys_cfg->wpa_cfg.pairwise_cipher_wpa2 = CIPHER_AES_CCMP;
|
|
priv->pairwise_cipher = CIPHER_AES_CCMP;
|
|
if (!priv->uap_key_mgmt)
|
|
priv->uap_key_mgmt = KEY_MGMT_PSK;
|
|
PRINTM(MINFO, "Set Auth Cipher CCMP\n");
|
|
} else if (vwrq->value ==
|
|
(IW_AUTH_CIPHER_TKIP | IW_AUTH_CIPHER_CCMP)) {
|
|
sys_cfg->wpa_cfg.pairwise_cipher_wpa =
|
|
(CIPHER_TKIP | CIPHER_AES_CCMP);
|
|
sys_cfg->wpa_cfg.pairwise_cipher_wpa2 =
|
|
(CIPHER_TKIP | CIPHER_AES_CCMP);
|
|
priv->pairwise_cipher = (CIPHER_TKIP | CIPHER_AES_CCMP);
|
|
if (!priv->uap_key_mgmt)
|
|
priv->uap_key_mgmt = KEY_MGMT_PSK;
|
|
PRINTM(MINFO, "Set Auth Cipher TKIP + CCMP\n");
|
|
}
|
|
break;
|
|
case IW_AUTH_CIPHER_GROUP:
|
|
/* Rest are not supported now */
|
|
if (vwrq->value & IW_AUTH_CIPHER_NONE)
|
|
/* XXX Do not delete no-operation line */
|
|
;
|
|
else if (vwrq->value & IW_AUTH_CIPHER_WEP40)
|
|
/* XXX Do not delete no-operation line */
|
|
;
|
|
else if (vwrq->value & IW_AUTH_CIPHER_WEP104)
|
|
/* XXX Do not delete no-operation line */
|
|
;
|
|
else if (vwrq->value & IW_AUTH_CIPHER_TKIP) {
|
|
sys_cfg->wpa_cfg.group_cipher = CIPHER_TKIP;
|
|
priv->group_cipher = CIPHER_TKIP;
|
|
if (!priv->uap_key_mgmt)
|
|
priv->uap_key_mgmt = KEY_MGMT_PSK;
|
|
PRINTM(MINFO, "Set Auth Cipher TKIP\n");
|
|
} else if (vwrq->value & IW_AUTH_CIPHER_CCMP) {
|
|
sys_cfg->wpa_cfg.group_cipher = CIPHER_AES_CCMP;
|
|
priv->group_cipher = CIPHER_AES_CCMP;
|
|
if (!priv->uap_key_mgmt)
|
|
priv->uap_key_mgmt = KEY_MGMT_PSK;
|
|
PRINTM(MINFO, "Set Auth Cipher CCMP\n");
|
|
}
|
|
break;
|
|
case IW_AUTH_80211_AUTH_ALG:
|
|
switch (vwrq->value) {
|
|
case IW_AUTH_ALG_SHARED_KEY:
|
|
PRINTM(MINFO, "Auth mode shared key!\n");
|
|
sys_cfg->auth_mode = MLAN_AUTH_MODE_SHARED;
|
|
break;
|
|
case IW_AUTH_ALG_LEAP:
|
|
break;
|
|
case IW_AUTH_ALG_OPEN_SYSTEM:
|
|
PRINTM(MINFO, "Auth mode open!\n");
|
|
sys_cfg->auth_mode = MLAN_AUTH_MODE_OPEN;
|
|
break;
|
|
default:
|
|
PRINTM(MINFO, "Auth mode auto!\n");
|
|
break;
|
|
}
|
|
break;
|
|
case IW_AUTH_WPA_VERSION:
|
|
switch (vwrq->value) {
|
|
case IW_AUTH_WPA_VERSION_DISABLED:
|
|
sys_cfg->protocol = PROTOCOL_NO_SECURITY;
|
|
break;
|
|
case IW_AUTH_WPA_VERSION_WPA:
|
|
sys_cfg->protocol = PROTOCOL_WPA;
|
|
break;
|
|
case IW_AUTH_WPA_VERSION_WPA2:
|
|
sys_cfg->protocol = PROTOCOL_WPA2;
|
|
break;
|
|
case IW_AUTH_WPA_VERSION_WPA | IW_AUTH_WPA_VERSION_WPA2:
|
|
sys_cfg->protocol = PROTOCOL_WPA2_MIXED;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
priv->uap_protocol = sys_cfg->protocol;
|
|
break;
|
|
case IW_AUTH_KEY_MGMT:
|
|
switch (vwrq->value) {
|
|
case IW_AUTH_KEY_MGMT_802_1X:
|
|
sys_cfg->key_mgmt |= KEY_MGMT_EAP;
|
|
priv->uap_key_mgmt |= KEY_MGMT_EAP;
|
|
break;
|
|
case IW_AUTH_KEY_MGMT_PSK:
|
|
sys_cfg->key_mgmt |= KEY_MGMT_PSK;
|
|
priv->uap_key_mgmt |= KEY_MGMT_PSK;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case IW_AUTH_WPA_ENABLED:
|
|
case IW_AUTH_TKIP_COUNTERMEASURES:
|
|
case IW_AUTH_DROP_UNENCRYPTED:
|
|
case IW_AUTH_RX_UNENCRYPTED_EAPOL:
|
|
case IW_AUTH_ROAMING_CONTROL:
|
|
case IW_AUTH_PRIVACY_INVOKED:
|
|
default:
|
|
kfree(sys_cfg);
|
|
LEAVE();
|
|
return -EOPNOTSUPP; /* No AP configuration */
|
|
}
|
|
if (!sys_cfg->key_mgmt)
|
|
sys_cfg->key_mgmt = priv->uap_key_mgmt;
|
|
if (sys_cfg->key_mgmt & KEY_MGMT_PSK)
|
|
sys_cfg->key_mgmt_operation |= 0x01;
|
|
if (sys_cfg->key_mgmt & KEY_MGMT_EAP)
|
|
sys_cfg->key_mgmt_operation |= 0x03;
|
|
if (!sys_cfg->protocol)
|
|
sys_cfg->protocol = priv->uap_protocol;
|
|
|
|
/* Set AP configuration */
|
|
if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_SET,
|
|
MOAL_IOCTL_WAIT,
|
|
sys_cfg)) {
|
|
PRINTM(MERROR, "Error setting AP confiruration\n");
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
kfree(sys_cfg);
|
|
LEAVE();
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Get authentication mode parameters
|
|
*
|
|
* @param dev A pointer to net_device structure
|
|
* @param info A pointer to iw_request_info structure
|
|
* @param vwrq A pointer to iw_param structure
|
|
* @param extra A pointer to extra data buf
|
|
*
|
|
* @return 0 --success, otherwise fail
|
|
*/
|
|
static int woal_get_auth(struct net_device *dev, struct iw_request_info *info,
|
|
union iwreq_data *wrqu, char *extra)
|
|
{
|
|
moal_private *priv = (moal_private *)netdev_priv(dev);
|
|
struct iw_param *vwrq = &wrqu->param;
|
|
mlan_uap_bss_param *ap_cfg = NULL;
|
|
|
|
ENTER();
|
|
|
|
ap_cfg = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
|
|
if (!ap_cfg) {
|
|
PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
|
|
LEAVE();
|
|
return -EFAULT;
|
|
}
|
|
|
|
if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_GET,
|
|
MOAL_IOCTL_WAIT,
|
|
ap_cfg)) {
|
|
PRINTM(MERROR, "Error getting AP confiruration\n");
|
|
kfree(ap_cfg);
|
|
LEAVE();
|
|
return -EFAULT;
|
|
}
|
|
switch (vwrq->flags & IW_AUTH_INDEX) {
|
|
case IW_AUTH_CIPHER_PAIRWISE:
|
|
if (ap_cfg->wpa_cfg.pairwise_cipher_wpa == CIPHER_TKIP ||
|
|
ap_cfg->wpa_cfg.pairwise_cipher_wpa2 == CIPHER_TKIP)
|
|
vwrq->value = IW_AUTH_CIPHER_TKIP;
|
|
else if (ap_cfg->wpa_cfg.pairwise_cipher_wpa ==
|
|
CIPHER_AES_CCMP ||
|
|
ap_cfg->wpa_cfg.pairwise_cipher_wpa2 ==
|
|
CIPHER_AES_CCMP)
|
|
vwrq->value = IW_AUTH_CIPHER_CCMP;
|
|
else
|
|
vwrq->value = IW_AUTH_CIPHER_NONE;
|
|
break;
|
|
case IW_AUTH_CIPHER_GROUP:
|
|
if (ap_cfg->wpa_cfg.group_cipher == CIPHER_TKIP)
|
|
vwrq->value = IW_AUTH_CIPHER_TKIP;
|
|
else if (ap_cfg->wpa_cfg.group_cipher == CIPHER_AES_CCMP)
|
|
vwrq->value = IW_AUTH_CIPHER_CCMP;
|
|
else
|
|
vwrq->value = IW_AUTH_CIPHER_NONE;
|
|
break;
|
|
case IW_AUTH_80211_AUTH_ALG:
|
|
if (ap_cfg->auth_mode == MLAN_AUTH_MODE_SHARED)
|
|
vwrq->value = IW_AUTH_ALG_SHARED_KEY;
|
|
else if (ap_cfg->auth_mode == MLAN_AUTH_MODE_NETWORKEAP)
|
|
vwrq->value = IW_AUTH_ALG_LEAP;
|
|
else
|
|
vwrq->value = IW_AUTH_ALG_OPEN_SYSTEM;
|
|
break;
|
|
case IW_AUTH_WPA_ENABLED:
|
|
if (ap_cfg->protocol == PROTOCOL_WPA ||
|
|
ap_cfg->protocol == PROTOCOL_WPA2 ||
|
|
ap_cfg->protocol == PROTOCOL_WPA2_MIXED)
|
|
vwrq->value = 1;
|
|
else
|
|
vwrq->value = 0;
|
|
break;
|
|
case IW_AUTH_KEY_MGMT:
|
|
if (ap_cfg->key_mgmt & KEY_MGMT_EAP)
|
|
vwrq->value |= IW_AUTH_KEY_MGMT_802_1X;
|
|
if (ap_cfg->key_mgmt & KEY_MGMT_PSK)
|
|
vwrq->value |= IW_AUTH_KEY_MGMT_PSK;
|
|
break;
|
|
case IW_AUTH_WPA_VERSION:
|
|
case IW_AUTH_TKIP_COUNTERMEASURES:
|
|
case IW_AUTH_DROP_UNENCRYPTED:
|
|
case IW_AUTH_RX_UNENCRYPTED_EAPOL:
|
|
case IW_AUTH_ROAMING_CONTROL:
|
|
case IW_AUTH_PRIVACY_INVOKED:
|
|
default:
|
|
kfree(ap_cfg);
|
|
LEAVE();
|
|
return -EOPNOTSUPP;
|
|
}
|
|
kfree(ap_cfg);
|
|
LEAVE();
|
|
return 0;
|
|
}
|
|
#endif /* WE >= 18 */
|
|
|
|
/* Data rate listing
|
|
* MULTI_BANDS:
|
|
* abg a b b/g
|
|
* Infra G(12) A(8) B(4) G(12)
|
|
* Adhoc A+B(12) A(8) B(4) B(4)
|
|
* non-MULTI_BANDS:
|
|
b b/g
|
|
* Infra B(4) G(12)
|
|
* Adhoc B(4) B(4)
|
|
*/
|
|
/**
|
|
* @brief Get Range Info
|
|
*
|
|
* @param dev A pointer to net_device structure
|
|
* @param info A pointer to iw_request_info structure
|
|
* @param dwrq A pointer to iw_point structure
|
|
* @param extra A pointer to extra data buf
|
|
*
|
|
* @return 0 --success, otherwise fail
|
|
*/
|
|
static int woal_get_range(struct net_device *dev, struct iw_request_info *info,
|
|
union iwreq_data *wrqu, char *extra)
|
|
{
|
|
moal_private *priv = (moal_private *)netdev_priv(dev);
|
|
struct iw_point *dwrq = &wrqu->data;
|
|
mlan_uap_bss_param *ap_cfg = NULL;
|
|
struct iw_range *range = (struct iw_range *)extra;
|
|
t_u8 band = 0;
|
|
int i;
|
|
|
|
ENTER();
|
|
|
|
ap_cfg = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
|
|
if (!ap_cfg) {
|
|
PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
|
|
LEAVE();
|
|
return -EFAULT;
|
|
}
|
|
|
|
if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_GET,
|
|
MOAL_IOCTL_WAIT,
|
|
ap_cfg)) {
|
|
PRINTM(MERROR, "Error getting AP confiruration\n");
|
|
kfree(ap_cfg);
|
|
LEAVE();
|
|
return -EFAULT;
|
|
}
|
|
dwrq->length = sizeof(struct iw_range);
|
|
memset(range, 0, sizeof(struct iw_range));
|
|
|
|
range->min_nwid = 0;
|
|
range->max_nwid = 0;
|
|
|
|
range->num_bitrates = MAX_DATA_RATES;
|
|
for (i = 0;
|
|
i < MIN(MAX_DATA_RATES, IW_MAX_BITRATES) && ap_cfg->rates[i];
|
|
i++) {
|
|
range->bitrate[i] = (ap_cfg->rates[i] & 0x7f) * 500000;
|
|
}
|
|
range->num_bitrates = i;
|
|
PRINTM(MINFO, "IW_MAX_BITRATES=%d num_bitrates=%d\n", IW_MAX_BITRATES,
|
|
range->num_bitrates);
|
|
|
|
range->num_frequency = MIN(ap_cfg->num_of_chan, IW_MAX_FREQUENCIES);
|
|
|
|
for (i = 0; i < range->num_frequency; i++) {
|
|
range->freq[i].i = (long)ap_cfg->chan_list[i].chan_number;
|
|
band = (ap_cfg->chan_list[i].bandcfg.chanBand == BAND_5GHZ);
|
|
range->freq[i].m =
|
|
(long)channel_to_frequency(
|
|
ap_cfg->chan_list[i].chan_number, band) *
|
|
100000;
|
|
range->freq[i].e = 1;
|
|
}
|
|
|
|
PRINTM(MINFO, "IW_MAX_FREQUENCIES=%d num_frequency=%d\n",
|
|
IW_MAX_FREQUENCIES, range->num_frequency);
|
|
|
|
range->num_channels = range->num_frequency;
|
|
|
|
woal_sort_channels(&range->freq[0], range->num_frequency);
|
|
|
|
/*
|
|
* Set an indication of the max TCP throughput in bit/s that we can
|
|
* expect using this interface
|
|
*/
|
|
if (i > 2)
|
|
range->throughput = 5000 * 1000;
|
|
else
|
|
range->throughput = 1500 * 1000;
|
|
|
|
range->min_rts = MLAN_RTS_MIN_VALUE;
|
|
range->max_rts = MLAN_RTS_MAX_VALUE;
|
|
range->min_frag = MLAN_FRAG_MIN_VALUE;
|
|
range->max_frag = MLAN_FRAG_MAX_VALUE;
|
|
|
|
range->encoding_size[0] = 5;
|
|
range->encoding_size[1] = 13;
|
|
range->num_encoding_sizes = 2;
|
|
range->max_encoding_tokens = 4;
|
|
|
|
/** Minimum power period */
|
|
#define IW_POWER_PERIOD_MIN 1000000 /* 1 sec */
|
|
/** Maximum power period */
|
|
#define IW_POWER_PERIOD_MAX 120000000 /* 2 min */
|
|
/** Minimum power timeout value */
|
|
#define IW_POWER_TIMEOUT_MIN 1000 /* 1 ms */
|
|
/** Maximim power timeout value */
|
|
#define IW_POWER_TIMEOUT_MAX 1000000 /* 1 sec */
|
|
|
|
/* Power Management duration & timeout */
|
|
range->min_pmp = IW_POWER_PERIOD_MIN;
|
|
range->max_pmp = IW_POWER_PERIOD_MAX;
|
|
range->min_pmt = IW_POWER_TIMEOUT_MIN;
|
|
range->max_pmt = IW_POWER_TIMEOUT_MAX;
|
|
range->pmp_flags = IW_POWER_PERIOD;
|
|
range->pmt_flags = IW_POWER_TIMEOUT;
|
|
range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R;
|
|
|
|
/*
|
|
* Minimum version we recommend
|
|
*/
|
|
range->we_version_source = 15;
|
|
|
|
/*
|
|
* Version we are compiled with
|
|
*/
|
|
range->we_version_compiled = WIRELESS_EXT;
|
|
|
|
range->retry_capa = IW_RETRY_LIMIT;
|
|
range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
|
|
|
|
range->min_retry = MLAN_TX_RETRY_MIN;
|
|
range->max_retry = MLAN_TX_RETRY_MAX;
|
|
|
|
#if (WIRELESS_EXT >= 18)
|
|
if (ap_cfg->protocol & PROTOCOL_WPA)
|
|
range->enc_capa |= IW_ENC_CAPA_WPA;
|
|
if (ap_cfg->protocol & PROTOCOL_WPA2)
|
|
range->enc_capa |= IW_ENC_CAPA_WPA2;
|
|
if (ap_cfg->wpa_cfg.pairwise_cipher_wpa == CIPHER_TKIP ||
|
|
ap_cfg->wpa_cfg.pairwise_cipher_wpa2 == CIPHER_TKIP ||
|
|
ap_cfg->wpa_cfg.group_cipher == CIPHER_TKIP)
|
|
range->enc_capa |= IW_ENC_CAPA_CIPHER_TKIP;
|
|
if (ap_cfg->wpa_cfg.pairwise_cipher_wpa == CIPHER_AES_CCMP ||
|
|
ap_cfg->wpa_cfg.pairwise_cipher_wpa2 == CIPHER_AES_CCMP ||
|
|
ap_cfg->wpa_cfg.group_cipher == CIPHER_AES_CCMP)
|
|
range->enc_capa |= IW_ENC_CAPA_CIPHER_CCMP;
|
|
#endif
|
|
kfree(ap_cfg);
|
|
LEAVE();
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Set priv command
|
|
*
|
|
* @param dev A pointer to net_device structure
|
|
* @param info A pointer to iw_request_info structure
|
|
* @param dwrq A pointer to iw_point structure
|
|
* @param extra A pointer to extra data buf
|
|
*
|
|
* @return 0 --success, otherwise fail
|
|
*/
|
|
static int woal_set_priv(struct net_device *dev, struct iw_request_info *info,
|
|
union iwreq_data *wrqu, char *extra)
|
|
{
|
|
ENTER();
|
|
LEAVE();
|
|
return -EOPNOTSUPP;
|
|
}
|
|
|
|
/**
|
|
* @brief Set essid
|
|
*
|
|
* @param dev A pointer to net_device structure
|
|
* @param info A pointer to iw_request_info structure
|
|
* @param dwrq A pointer to iw_point structure
|
|
* @param extra A pointer to extra data buf
|
|
*
|
|
* @return 0--success, otherwise fail
|
|
*/
|
|
static int woal_set_essid(struct net_device *dev, struct iw_request_info *info,
|
|
union iwreq_data *wrqu, char *extra)
|
|
{
|
|
moal_private *priv = (moal_private *)netdev_priv(dev);
|
|
struct iw_point *dwrq = &wrqu->data;
|
|
mlan_uap_bss_param *sys_cfg = NULL;
|
|
int ret = 0;
|
|
|
|
ENTER();
|
|
|
|
/* Check the size of the string */
|
|
if (dwrq->length > IW_ESSID_MAX_SIZE + 1) {
|
|
ret = -E2BIG;
|
|
goto done;
|
|
}
|
|
sys_cfg = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
|
|
if (!sys_cfg) {
|
|
PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
|
|
ret = -EFAULT;
|
|
goto done;
|
|
}
|
|
|
|
/* Initialize the invalid values so that the correct values
|
|
* below are downloaded to firmware */
|
|
woal_set_sys_config_invalid_data(sys_cfg);
|
|
|
|
/* Set the SSID */
|
|
#if WIRELESS_EXT > 20
|
|
sys_cfg->ssid.ssid_len = dwrq->length;
|
|
#else
|
|
sys_cfg->ssid.ssid_len = dwrq->length - 1;
|
|
#endif
|
|
|
|
moal_memcpy_ext(priv->phandle, sys_cfg->ssid.ssid, extra,
|
|
sys_cfg->ssid.ssid_len, sizeof(sys_cfg->ssid.ssid));
|
|
if (!sys_cfg->ssid.ssid_len || sys_cfg->ssid.ssid[0] < 0x20) {
|
|
PRINTM(MERROR, "Invalid SSID - aborting set_essid\n");
|
|
ret = -EINVAL;
|
|
goto done;
|
|
}
|
|
PRINTM(MINFO, "Requested new SSID = %s\n",
|
|
(sys_cfg->ssid.ssid_len > 0) ? (char *)sys_cfg->ssid.ssid :
|
|
"NULL");
|
|
|
|
/* Set AP configuration */
|
|
if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_SET,
|
|
MOAL_IOCTL_WAIT,
|
|
sys_cfg)) {
|
|
PRINTM(MERROR, "Error setting AP confiruration\n");
|
|
ret = -EFAULT;
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
kfree(sys_cfg);
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief Get current essid
|
|
*
|
|
* @param dev A pointer to net_device structure
|
|
* @param info A pointer to iw_request_info structure
|
|
* @param dwrq A pointer to iw_point structure
|
|
* @param extra A pointer to extra data buf
|
|
*
|
|
* @return 0--success, otherwise fail
|
|
*/
|
|
static int woal_get_essid(struct net_device *dev, struct iw_request_info *info,
|
|
struct iw_point *dwrq, char *extra)
|
|
{
|
|
moal_private *priv = (moal_private *)netdev_priv(dev);
|
|
mlan_uap_bss_param *ap_cfg = NULL;
|
|
|
|
ENTER();
|
|
|
|
ap_cfg = kzalloc(sizeof(mlan_uap_bss_param), GFP_ATOMIC);
|
|
if (!ap_cfg) {
|
|
PRINTM(MERROR, "Fail to alloc memory for mlan_uap_bss_param\n");
|
|
return -EFAULT;
|
|
}
|
|
|
|
if (MLAN_STATUS_SUCCESS != woal_set_get_sys_config(priv, MLAN_ACT_GET,
|
|
MOAL_IOCTL_WAIT,
|
|
ap_cfg)) {
|
|
PRINTM(MERROR, "Error getting AP confiruration\n");
|
|
kfree(ap_cfg);
|
|
LEAVE();
|
|
return -EFAULT;
|
|
}
|
|
|
|
if (priv->bss_started) {
|
|
dwrq->length = MIN(dwrq->length, ap_cfg->ssid.ssid_len);
|
|
moal_memcpy_ext(priv->phandle, extra, ap_cfg->ssid.ssid,
|
|
dwrq->length, dwrq->length);
|
|
} else
|
|
dwrq->length = 0;
|
|
|
|
dwrq->flags = 1;
|
|
kfree(ap_cfg);
|
|
LEAVE();
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* iwconfig settable callbacks
|
|
*/
|
|
static const iw_handler woal_handler[] = {
|
|
(iw_handler)woal_config_commit, /* SIOCSIWCOMMIT */
|
|
(iw_handler)woal_get_name, /* SIOCGIWNAME */
|
|
(iw_handler)NULL, /* SIOCSIWNWID */
|
|
(iw_handler)NULL, /* SIOCGIWNWID */
|
|
(iw_handler)woal_set_freq, /* SIOCSIWFREQ */
|
|
(iw_handler)woal_get_freq, /* SIOCGIWFREQ */
|
|
(iw_handler)woal_set_bss_mode, /* SIOCSIWMODE */
|
|
(iw_handler)woal_get_bss_mode, /* SIOCGIWMODE */
|
|
(iw_handler)NULL, /* SIOCSIWSENS */
|
|
(iw_handler)NULL, /* SIOCGIWSENS */
|
|
(iw_handler)NULL, /* SIOCSIWRANGE */
|
|
(iw_handler)woal_get_range, /* SIOCGIWRANGE */
|
|
(iw_handler)woal_set_priv, /* SIOCSIWPRIV */
|
|
(iw_handler)NULL, /* SIOCGIWPRIV */
|
|
(iw_handler)NULL, /* SIOCSIWSTATS */
|
|
(iw_handler)NULL, /* SIOCGIWSTATS */
|
|
#if WIRELESS_EXT > 15
|
|
#ifdef CONFIG_WEXT_SPY
|
|
iw_handler_set_spy, /* SIOCSIWSPY */
|
|
iw_handler_get_spy, /* SIOCGIWSPY */
|
|
iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
|
|
iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
|
|
#else
|
|
(iw_handler)NULL, /* -- hole -- */
|
|
(iw_handler)NULL, /* -- hole -- */
|
|
(iw_handler)NULL, /* -- hole -- */
|
|
(iw_handler)NULL, /* -- hole -- */
|
|
#endif
|
|
#else /* WIRELESS_EXT > 15 */
|
|
(iw_handler)NULL, /* -- hole -- */
|
|
(iw_handler)NULL, /* -- hole -- */
|
|
(iw_handler)NULL, /* -- hole -- */
|
|
(iw_handler)NULL, /* -- hole -- */
|
|
#endif /* WIRELESS_EXT > 15 */
|
|
(iw_handler)woal_set_wap, /* SIOCSIWAP */
|
|
(iw_handler)woal_get_wap, /* SIOCGIWAP */
|
|
#if WIRELESS_EXT >= 18
|
|
(iw_handler)woal_set_mlme, /* SIOCSIWMLME */
|
|
#else
|
|
(iw_handler)NULL, /* -- hole -- */
|
|
#endif
|
|
/* (iw_handler) wlan_get_aplist, */ /* SIOCGIWAPLIST */
|
|
NULL, /* SIOCGIWAPLIST */
|
|
#if WIRELESS_EXT > 13
|
|
(iw_handler)NULL, /* SIOCSIWSCAN */
|
|
(iw_handler)NULL, /* SIOCGIWSCAN */
|
|
#else /* WIRELESS_EXT > 13 */
|
|
(iw_handler)NULL, /* SIOCSIWSCAN */
|
|
(iw_handler)NULL, /* SIOCGIWSCAN */
|
|
#endif /* WIRELESS_EXT > 13 */
|
|
(iw_handler)woal_set_essid, /* SIOCSIWESSID */
|
|
(iw_handler)woal_get_essid, /* SIOCGIWESSID */
|
|
(iw_handler)NULL, /* SIOCSIWNICKN */
|
|
(iw_handler)NULL, /* SIOCGIWNICKN */
|
|
(iw_handler)NULL, /* -- hole -- */
|
|
(iw_handler)NULL, /* -- hole -- */
|
|
(iw_handler)NULL, /* SIOCSIWRATE */
|
|
(iw_handler)NULL, /* SIOCGIWRATE */
|
|
(iw_handler)NULL, /* SIOCSIWRTS */
|
|
(iw_handler)NULL, /* SIOCGIWRTS */
|
|
(iw_handler)NULL, /* SIOCSIWFRAG */
|
|
(iw_handler)NULL, /* SIOCGIWFRAG */
|
|
(iw_handler)NULL, /* SIOCSIWTXPOW */
|
|
(iw_handler)NULL, /* SIOCGIWTXPOW */
|
|
(iw_handler)NULL, /* SIOCSIWRETRY */
|
|
(iw_handler)NULL, /* SIOCGIWRETRY */
|
|
(iw_handler)woal_set_encode, /* SIOCSIWENCODE */
|
|
(iw_handler)woal_get_encode, /* SIOCGIWENCODE */
|
|
(iw_handler)NULL, /* SIOCSIWPOWER */
|
|
(iw_handler)NULL, /* SIOCGIWPOWER */
|
|
#if (WIRELESS_EXT >= 18)
|
|
(iw_handler)NULL, /* -- hole -- */
|
|
(iw_handler)NULL, /* -- hole -- */
|
|
(iw_handler)woal_set_gen_ie, /* SIOCSIWGENIE */
|
|
(iw_handler)woal_get_gen_ie, /* SIOCGIWGENIE */
|
|
(iw_handler)woal_set_auth, /* SIOCSIWAUTH */
|
|
(iw_handler)woal_get_auth, /* SIOCGIWAUTH */
|
|
(iw_handler)woal_set_encode_ext, /* SIOCSIWENCODEEXT */
|
|
(iw_handler)woal_get_encode_ext, /* SIOCGIWENCODEEXT */
|
|
#endif /* WIRELESSS_EXT >= 18 */
|
|
};
|
|
|
|
/**
|
|
* iwpriv settable callbacks
|
|
*/
|
|
static const iw_handler woal_private_handler[] = {
|
|
NULL, /* SIOCIWFIRSTPRIV */
|
|
};
|
|
|
|
/********************************************************
|
|
Global Functions
|
|
********************************************************/
|
|
|
|
// clang-format off
|
|
/** wlan_handler_def */
|
|
struct iw_handler_def woal_uap_handler_def = {
|
|
.num_standard = ARRAY_SIZE(woal_handler),
|
|
.num_private = ARRAY_SIZE(woal_private_handler),
|
|
.num_private_args = ARRAY_SIZE(woal_uap_priv_args),
|
|
.standard = (iw_handler *)woal_handler,
|
|
.private = (iw_handler *)woal_private_handler,
|
|
.private_args = (struct iw_priv_args *)woal_uap_priv_args,
|
|
#if WIRELESS_EXT > 20
|
|
.get_wireless_stats = woal_get_uap_wireless_stats,
|
|
#endif
|
|
};
|
|
// clang-format on
|
|
|
|
/**
|
|
* @brief Get wireless statistics
|
|
*
|
|
* @param dev A pointer to net_device structure
|
|
*
|
|
* @return A pointer to iw_statistics buf
|
|
*/
|
|
struct iw_statistics *woal_get_uap_wireless_stats(struct net_device *dev)
|
|
{
|
|
moal_private *priv = (moal_private *)netdev_priv(dev);
|
|
t_u16 wait_option = MOAL_IOCTL_WAIT;
|
|
|
|
ENTER();
|
|
|
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
|
|
/*
|
|
* Since schedule() is not allowed from an atomic context
|
|
* such as when dev_base_lock for netdevices is acquired
|
|
* for reading/writing in kernel before this call, HostCmd
|
|
* is issued in non-blocking way in such contexts and
|
|
* blocking in other cases.
|
|
*/
|
|
if (in_atomic() || !write_can_lock(&dev_base_lock))
|
|
wait_option = MOAL_NO_WAIT;
|
|
#endif
|
|
|
|
priv->w_stats.qual.qual = 0;
|
|
priv->w_stats.qual.level = 0;
|
|
priv->w_stats.discard.code = 0;
|
|
priv->w_stats.status = IW_MODE_MASTER;
|
|
woal_uap_get_stats(priv, wait_option, NULL);
|
|
|
|
LEAVE();
|
|
return &priv->w_stats;
|
|
}
|