6123 lines
199 KiB
C
Executable file
6123 lines
199 KiB
C
Executable file
/****************************************************************************
|
|
*
|
|
* Copyright (c) 2012 - 2021 Samsung Electronics Co., Ltd. All rights reserved
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include "ioctl.h"
|
|
#include "debug.h"
|
|
#include "mlme.h"
|
|
#include "mgt.h"
|
|
#include "cac.h"
|
|
#include "hip.h"
|
|
#include "netif.h"
|
|
#include "cfg80211_ops.h"
|
|
#include <net/netlink.h>
|
|
#include <linux/netdevice.h>
|
|
#include <linux/ieee80211.h>
|
|
#include <linux/igmp.h>
|
|
#include "mib.h"
|
|
#include <scsc/scsc_mx.h>
|
|
#include <scsc/scsc_log_collector.h>
|
|
#include "dev.h"
|
|
#include "fapi.h"
|
|
|
|
#define CMD_RXFILTERADD "RXFILTER-ADD"
|
|
#define CMD_RXFILTERREMOVE "RXFILTER-REMOVE"
|
|
#define CMD_RXFILTERSTART "RXFILTER-START"
|
|
#define CMD_RXFILTERSTOP "RXFILTER-STOP"
|
|
#define CMD_SETCOUNTRYREV "SETCOUNTRYREV"
|
|
#define CMD_GETCOUNTRYREV "GETCOUNTRYREV"
|
|
#define CMD_SETROAMTRIGGER_LEGACY "SETROAMTRIGGER_LEGACY"
|
|
#define CMD_GETROAMTRIGGER_LEGACY "GETROAMTRIGGER_LEGACY"
|
|
#define CMD_REASSOC_LEGACY "REASSOC_LEGACY"
|
|
#define CMD_REASSOC_FREQUENCY_LEGACY "REASSOC_FREQUENCY_LEGACY"
|
|
#define CMD_SETROAMTRIGGER "SETROAMTRIGGER"
|
|
#define CMD_GETROAMTRIGGER "GETROAMTRIGGER"
|
|
#define CMD_ADDROAMSCANCHANNELS_LEGACY "ADDROAMSCANCHANNELS_LEGACY"
|
|
#define CMD_ADDROAMSCANFREQUENCIES_LEGACY "ADDROAMSCANFREQUENCIES_LEGACY"
|
|
#define CMD_SETSUSPENDMODE "SETSUSPENDMODE"
|
|
#define CMD_SETROAMDELTA "SETROAMDELTA"
|
|
#define CMD_GETROAMDELTA "GETROAMDELTA"
|
|
#define CMD_SETROAMSCANPERIOD "SETROAMSCANPERIOD"
|
|
#define CMD_GETROAMSCANPERIOD "GETROAMSCANPERIOD"
|
|
#define CMD_SETFULLROAMSCANPERIOD "SETFULLROAMSCANPERIOD"
|
|
#define CMD_GETFULLROAMSCANPERIOD "GETFULLROAMSCANPERIOD"
|
|
#define CMD_SETSCANCHANNELTIME "SETSCANCHANNELTIME"
|
|
#define CMD_GETSCANCHANNELTIME "GETSCANCHANNELTIME"
|
|
#define CMD_SETSCANNPROBES "SETSCANNPROBES"
|
|
#define CMD_GETSCANNPROBES "GETSCANNPROBES"
|
|
#define CMD_SETROAMMODE "SETROAMMODE"
|
|
#define CMD_GETROAMMODE "GETROAMMODE"
|
|
#define CMD_SETROAMINTRABAND "SETROAMINTRABAND"
|
|
#define CMD_GETROAMINTRABAND "GETROAMINTRABAND"
|
|
#define CMD_SETROAMBAND "SETROAMBAND"
|
|
#define CMD_GETROAMBAND "GETROAMBAND"
|
|
#define CMD_SETROAMSCANCONTROL "SETROAMSCANCONTROL"
|
|
#define CMD_GETROAMSCANCONTROL "GETROAMSCANCONTROL"
|
|
#define CMD_SETSCANHOMETIME "SETSCANHOMETIME"
|
|
#define CMD_GETSCANHOMETIME "GETSCANHOMETIME"
|
|
#define CMD_SETSCANHOMEAWAYTIME "SETSCANHOMEAWAYTIME"
|
|
#define CMD_GETSCANHOMEAWAYTIME "GETSCANHOMEAWAYTIME"
|
|
#define CMD_SETSCANHOMEAWAYTIME_LEGACY "SETSCANHOMEAWAYTIME_LEGACY"
|
|
#define CMD_SETSCANHOMETIME_LEGACY "SETSCANHOMETIME_LEGACY"
|
|
#define CMD_SETSCANCHANNELTIME_LEGACY "SETSCANCHANNELTIME_LEGACY"
|
|
#define CMD_SETSCANPASSIVETIME_LEGACY "SETSCANPASSIVETIME_LEGACY"
|
|
#define CMD_SET_TID "SET_TID"
|
|
#define CMD_SETOKCMODE "SETOKCMODE"
|
|
#define CMD_GETOKCMODE "GETOKCMODE"
|
|
#define CMD_SETWESMODE "SETWESMODE"
|
|
#define CMD_GETWESMODE "GETWESMODE"
|
|
#define CMD_SET_PMK "SET_PMK"
|
|
#define CMD_HAPD_GET_CHANNEL "HAPD_GET_CHANNEL"
|
|
#define CMD_SET_SAP_CHANNEL_LIST "SET_SAP_CHANNEL_LIST"
|
|
#define CMD_REASSOC "REASSOC"
|
|
#define CMD_REASSOC_FREQUENCY "REASSOC_FREQUENCY"
|
|
#define CMD_SETROAMSCANCHANNELS "SETROAMSCANCHANNELS"
|
|
#define CMD_SETROAMSCANFREQUENCIES "SETROAMSCANFREQUENCIES"
|
|
#define CMD_GETROAMSCANCHANNELS "GETROAMSCANCHANNELS"
|
|
#define CMD_GETROAMSCANFREQUENCIES "GETROAMSCANFREQUENCIES"
|
|
#define CMD_GETROAMSCANCHANNELS_LEGACY "GETROAMSCANCHANNELS_LEGACY"
|
|
#define CMD_GETROAMSCANFREQUENCIES_LEGACY "GETROAMSCANFREQUENCIES_LEGACY"
|
|
#define CMD_ADDROAMSCANCHANNELS "ADDROAMSCANCHANNELS"
|
|
#define CMD_ADDROAMSCANFREQUENCIES "ADDROAMSCANFREQUENCIES"
|
|
#define CMD_SENDACTIONFRAME "SENDACTIONFRAME"
|
|
#define CMD_CERTSENDACTIONFRAME "CERTSENDACTIONFRAME"
|
|
#ifdef SLSI_TEST_DEV
|
|
#define CMD_GASSENDACTIONFRAME "GASSENDACTIONFRAME"
|
|
#endif
|
|
#define CMD_GETNCHOMODE "GETNCHOMODE"
|
|
#define CMD_SETNCHOMODE "SETNCHOMODE"
|
|
#define CMD_GETDFSSCANMODE "GETDFSSCANMODE"
|
|
#define CMD_SETDFSSCANMODE "SETDFSSCANMODE"
|
|
#define CMD_HAPD_MAX_NUM_STA "HAPD_MAX_NUM_STA"
|
|
#define CMD_COUNTRY "COUNTRY"
|
|
#define CMD_SEND_GK "SEND_GK"
|
|
#define CMD_SETAPP2PWPSIE "SET_AP_P2P_WPS_IE"
|
|
#define CMD_P2PSETPS "P2P_SET_PS"
|
|
#define CMD_P2PSETNOA "P2P_SET_NOA"
|
|
#define CMD_P2PECSA "P2P_ECSA"
|
|
#define CMD_P2PLOSTART "P2P_LO_START"
|
|
#define CMD_P2PLOSTOP "P2P_LO_STOP"
|
|
#define CMD_TDLSCHANNELSWITCH "TDLS_CHANNEL_SWITCH"
|
|
#define CMD_SETROAMOFFLOAD "SETROAMOFFLOAD"
|
|
#define CMD_SETROAMOFFLAPLIST "SETROAMOFFLAPLIST"
|
|
#ifdef CONFIG_SCSC_WLAN_LOW_LATENCY_MODE
|
|
#define CMD_SET_LATENCY_MODE "SET_LATENCY_MODE"
|
|
#define CMD_SET_POWER_MGMT "SET_POWER_MGMT"
|
|
#endif
|
|
#define CMD_SET_LATENCY_CRT_DATA "SET_LATENCY_CRT_DATA"
|
|
#define CMD_SET_DISCONNECT_IES "SET_DISCONNECT_IES"
|
|
#define CMD_SETBANDWIDTH "SETBANDWIDTH"
|
|
#define CMD_SET_BSS_CHANNEL_WIDTH "SET_BSS_CHANNEL_WIDTH"
|
|
|
|
#define CMD_SETBAND "SETBAND"
|
|
#define CMD_GETBAND "GETBAND"
|
|
#define CMD_FACTORY_SETBAND "FACTORY_SETBAND"
|
|
#define CMD_SET_FCC_CHANNEL "SET_FCC_CHANNEL"
|
|
|
|
#define CMD_FAKEMAC "FAKEMAC"
|
|
|
|
#define CMD_GETBSSRSSI "GET_BSS_RSSI"
|
|
#define CMD_GETBSSINFO "GETBSSINFO"
|
|
#define CMD_GETSTAINFO "GETSTAINFO"
|
|
#define CMD_GETASSOCREJECTINFO "GETASSOCREJECTINFO"
|
|
#define CMD_SET_DWELL_TIME "SET_DWELL_TIME"
|
|
|
|
#if defined(CONFIG_SLSI_WLAN_STA_FWD_BEACON) && (defined(SCSC_SEP_VERSION) && SCSC_SEP_VERSION >= 10)
|
|
#define CMD_BEACON_RECV "BEACON_RECV"
|
|
#endif
|
|
#ifdef CONFIG_SCSC_WLAN_STA_ENHANCED_ARP_DETECT
|
|
#define CMD_SET_ENHANCED_ARP_TARGET "SET_ENHANCED_ARP_TARGET"
|
|
#define CMD_GET_ENHANCED_ARP_COUNTS "GET_ENHANCED_ARP_COUNTS"
|
|
#endif
|
|
|
|
/* Known commands from framework for which no handlers */
|
|
#define CMD_AMPDU_MPDU "AMPDU_MPDU"
|
|
#define CMD_BTCOEXMODE "BTCOEXMODE"
|
|
#define CMD_BTCOEXSCAN_START "BTCOEXSCAN-START"
|
|
#define CMD_BTCOEXSCAN_STOP "BTCOEXSCAN-STOP"
|
|
#define CMD_CHANGE_RL "CHANGE_RL"
|
|
#define CMD_INTERFACE_CREATE "INTERFACE_CREATE"
|
|
#define CMD_INTERFACE_DELETE "INTERFACE_DELETE"
|
|
#define CMD_SET_INDOOR_CHANNELS "SET_INDOOR_CHANNELS"
|
|
#define CMD_GET_INDOOR_CHANNELS "GET_INDOOR_CHANNELS"
|
|
#define CMD_LTECOEX "LTECOEX"
|
|
#define CMD_MIRACAST "MIRACAST"
|
|
#define CMD_RESTORE_RL "RESTORE_RL"
|
|
#define CMD_RPSMODE "RPSMODE"
|
|
#define CMD_SETCCXMODE "SETCCXMODE"
|
|
#define CMD_SETDFSSCANMODE "SETDFSSCANMODE"
|
|
#define CMD_SETJOINPREFER "SETJOINPREFER"
|
|
#define CMD_SETSINGLEANT "SETSINGLEANT"
|
|
#define CMD_SET_TX_POWER_CALLING "SET_TX_POWER_CALLING"
|
|
#define CMD_GET_CU "GET_CU"
|
|
|
|
#define CMD_DRIVERDEBUGDUMP "DEBUG_DUMP"
|
|
#define CMD_DRIVERDEBUGCOMMAND "DEBUG_COMMAND"
|
|
#define CMD_TESTFORCEHANG "SLSI_TEST_FORCE_HANG"
|
|
#define CMD_GETREGULATORY "GETREGULATORY"
|
|
|
|
#define CMD_SET_TX_POWER_SAR "SET_TX_POWER_SAR"
|
|
#define CMD_GET_TX_POWER_SAR "GET_TX_POWER_SAR"
|
|
#define CMD_SET_TX_POWER_SUB6_BAND "SET_TX_POWER_SUB6_BAND"
|
|
|
|
#define CMD_POWER_MEASUREMENT_START "POWER_MEASUREMENT_START"
|
|
|
|
#ifdef CONFIG_SCSC_WLAN_ENHANCED_PKT_FILTER
|
|
#define CMD_ENHANCED_PKT_FILTER "ENHANCED_PKT_FILTER"
|
|
#endif
|
|
|
|
#ifdef CONFIG_SCSC_WLAN_MAX_LINK_SPEED
|
|
#define CMD_GET_MAX_LINK_SPEED "GET_MAX_LINK_SPEED"
|
|
#endif
|
|
|
|
#ifdef CONFIG_SCSC_WLAN_NUM_ANTENNAS
|
|
#define CMD_SET_NUM_ANTENNAS "SET_NUM_ANTENNAS"
|
|
#define CMD_GET_NUM_ANTENNAS "GET_NUM_ANTENNAS"
|
|
#endif
|
|
|
|
#ifdef CONFIG_SCSC_WLAN_DYNAMIC_ITO
|
|
#define CMD_SET_ITO "SET_ITO"
|
|
#define CMD_ENABLE_ITO "ENABLE_ITO"
|
|
#endif
|
|
|
|
#define CMD_ELNA_BYPASS "ELNA_BYPASS"
|
|
#define CMD_ELNA_BYPASS_INT "ELNA_BYPASS_INT"
|
|
#define CMD_MAX_DTIM_IN_SUSPEND "MAX_DTIM_IN_SUSPEND"
|
|
#define CMD_SET_DTIM_IN_SUSPEND "SET_DTIM_IN_SUSPEND"
|
|
#define CMD_FORCE_ROAMING_BSSID "FORCE_ROAMING_BSSID"
|
|
#define CMD_ROAMING_BLACKLIST_ADD "ROAMING_BLACKLIST_ADD"
|
|
#define CMD_ROAMING_BLACKLIST_REMOVE "ROAMING_BLACKLIST_REMOVE"
|
|
|
|
#define ROAMOFFLAPLIST_MIN 1
|
|
#define ROAMOFFLAPLIST_MAX 100
|
|
|
|
#ifdef CONFIG_SCSC_WLAN_SUPPORT_6G
|
|
#define SLSI_MAX_BAND_VALUE SLSI_FREQ_BAND_2_4GHZ_6GHZ
|
|
#define SLSI_MAX_ROAMBAND_VALUE FAPI_BAND_2_4GHZ_5GHZ_6GHZ
|
|
#else
|
|
#define SLSI_MAX_BAND_VALUE SLSI_FREQ_BAND_2GHZ
|
|
#define SLSI_MAX_ROAMBAND_VALUE FAPI_BAND_2_4GHZ_5GHZ
|
|
#endif
|
|
|
|
|
|
struct slsi_ioctl_args *slsi_get_private_command_args(char *buffer, int buf_len, int max_arg_count)
|
|
{
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
char *pos = buffer;
|
|
|
|
ioctl_args = kmalloc(sizeof(*ioctl_args) + sizeof(u8 *) * max_arg_count, GFP_KERNEL);
|
|
if (!ioctl_args)
|
|
return NULL;
|
|
memset(ioctl_args->args, '\0', sizeof(u8 *) * max_arg_count);
|
|
|
|
ioctl_args->arg_count = 0;
|
|
while (buf_len > 0 && ioctl_args->arg_count < max_arg_count) {
|
|
pos = strchr(pos, ' ');
|
|
if (!pos)
|
|
break;
|
|
buf_len = buf_len - (pos - buffer + 1);
|
|
if (buf_len <= 0)
|
|
break;
|
|
*pos = '\0';
|
|
pos++;
|
|
while (*pos == ' ')
|
|
pos++;
|
|
buffer = pos;
|
|
ioctl_args->args[ioctl_args->arg_count++] = pos;
|
|
}
|
|
return ioctl_args;
|
|
}
|
|
|
|
static int slsi_parse_hex(unsigned char c)
|
|
{
|
|
if (c >= '0' && c <= '9')
|
|
return c - '0';
|
|
if (c >= 'a' && c <= 'f')
|
|
return c - 'a' + 10;
|
|
if (c >= 'A' && c <= 'F')
|
|
return c - 'A' + 10;
|
|
return 0;
|
|
}
|
|
|
|
void slsi_convert_space_seperation(char *buf, int buf_len)
|
|
{
|
|
int i = 0;
|
|
|
|
while (buf[i] != '\0' && i < buf_len) {
|
|
if (buf[i] == ',' || buf[i] == '=')
|
|
buf[i] = ' ';
|
|
i++;
|
|
}
|
|
}
|
|
|
|
static int slsi_is_bw_valid(char *str)
|
|
{
|
|
if ((slsi_str_cmp(str, "20") == 0) || (slsi_str_cmp(str, "40") == 0) ||
|
|
(slsi_str_cmp(str, "80") == 0))
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void slsi_machexstring_to_macarray(char *mac_str, u8 *mac_arr)
|
|
{
|
|
mac_arr[0] = slsi_parse_hex(mac_str[0]) << 4 | slsi_parse_hex(mac_str[1]);
|
|
mac_arr[1] = slsi_parse_hex(mac_str[3]) << 4 | slsi_parse_hex(mac_str[4]);
|
|
mac_arr[2] = slsi_parse_hex(mac_str[6]) << 4 | slsi_parse_hex(mac_str[7]);
|
|
mac_arr[3] = slsi_parse_hex(mac_str[9]) << 4 | slsi_parse_hex(mac_str[10]);
|
|
mac_arr[4] = slsi_parse_hex(mac_str[12]) << 4 | slsi_parse_hex(mac_str[13]);
|
|
mac_arr[5] = slsi_parse_hex(mac_str[15]) << 4 | slsi_parse_hex(mac_str[16]);
|
|
}
|
|
|
|
static int slsi_get_rcl_freq_list(struct slsi_dev *sdev, struct sk_buff *skb, int *freq_list)
|
|
{
|
|
int i = 7; /* 1byte (id) + 1byte(length) + 3byte (oui) + 2byte */
|
|
int ie_len = 0;
|
|
u8 *ptr;
|
|
u16 freq_val = 0;
|
|
__le16 *le16_ptr = NULL;
|
|
u32 freq_count = 0;
|
|
|
|
SLSI_DBG3(sdev, SLSI_MLME, "RCL Channel List Indication received\n");
|
|
ptr = fapi_get_data(skb);
|
|
ie_len = ptr[1];
|
|
while (i < ie_len) {
|
|
le16_ptr = (__le16 *)&ptr[i];
|
|
freq_val = le16_to_cpu(*le16_ptr);
|
|
freq_list[freq_count] = freq_val / 2;
|
|
|
|
if (freq_list[freq_count] < 2412 || freq_list[freq_count] > 5885) {
|
|
SLSI_ERR(sdev, "ERR: Invalid freq received %d\n", freq_list[freq_count]);
|
|
kfree_skb(skb);
|
|
return 0;
|
|
}
|
|
|
|
i += SLSI_SCAN_CHANNEL_DESCRIPTOR_SIZE;
|
|
freq_count += 1;
|
|
if (freq_count >= MAX_FREQUENCY_COUNT) {
|
|
SLSI_ERR(sdev, "ERR: Frequency list received >= %d\n", MAX_FREQUENCY_COUNT);
|
|
kfree_skb(skb);
|
|
return 0;
|
|
}
|
|
}
|
|
kfree_skb(skb);
|
|
return freq_count;
|
|
}
|
|
|
|
static int slsi_get_rcl_channel_list(struct slsi_dev *sdev, struct sk_buff *skb, u16 *channel_list)
|
|
{
|
|
u32 channel_count = 0;
|
|
int i = 7; /* 1byte (id) + 1byte(length) + 3byte (oui) + 2byte */
|
|
int ie_len = 0;
|
|
u8 *ptr;
|
|
u16 channel_val = 0;
|
|
__le16 *le16_ptr = NULL;
|
|
|
|
SLSI_DBG3(sdev, SLSI_MLME, "RCL Channel List Indication received\n");
|
|
ptr = fapi_get_data(skb);
|
|
ie_len = ptr[1];
|
|
while (i < ie_len) {
|
|
le16_ptr = (__le16 *)&ptr[i];
|
|
channel_val = le16_to_cpu(*le16_ptr);
|
|
channel_list[channel_count] = ieee80211_frequency_to_channel(channel_val / 2);
|
|
if (channel_list[channel_count] < 1 || channel_list[channel_count] > 196) {
|
|
SLSI_ERR(sdev, "ERR: Invalid channel received %d\n", channel_list[channel_count]);
|
|
kfree_skb(skb);
|
|
return 0;
|
|
}
|
|
i += SLSI_SCAN_CHANNEL_DESCRIPTOR_SIZE;
|
|
channel_count += 1;
|
|
if (channel_count >= MAX_CHANNEL_COUNT) {
|
|
SLSI_ERR(sdev, "ERR: Channel list received >= %d\n", MAX_CHANNEL_COUNT);
|
|
kfree_skb(skb);
|
|
return 0;
|
|
}
|
|
}
|
|
kfree_skb(skb);
|
|
return channel_count;
|
|
}
|
|
|
|
void slsi_update_multicast_addr(struct slsi_dev *sdev, struct net_device *dev)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct in_device *in_dev = NULL;
|
|
struct ip_mc_list *im = NULL;
|
|
static __be32 multicast_ip_list[65] = {0};
|
|
int size = 0, i = 0, ip_found = 0;
|
|
|
|
WARN_ON(!SLSI_MUTEX_IS_LOCKED(ndev_vif->vif_mutex));
|
|
WARN_ON(ndev_vif->vif_type != FAPI_VIFTYPE_STATION);
|
|
in_dev = __in_dev_get_rtnl(dev);
|
|
if (!in_dev)
|
|
return;
|
|
|
|
for (im = rtnl_dereference(in_dev->mc_list); im != NULL; im = rtnl_dereference(im->next_rcu)) {
|
|
ip_found = 0;
|
|
for (i = 0; i < size; i++) {
|
|
if (!memcmp(&im->multiaddr, &multicast_ip_list[i], sizeof(__be32))) {
|
|
ip_found = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!ip_found) {
|
|
memcpy(&multicast_ip_list[size], &im->multiaddr, sizeof(__be32));
|
|
size++;
|
|
}
|
|
if (size >= 65)
|
|
break;
|
|
}
|
|
slsi_mlme_set_multicast_ip(sdev, dev, multicast_ip_list, size);
|
|
}
|
|
|
|
static int slsi_set_suspend_mode(struct net_device *dev, char *command, int cmd_len)
|
|
{
|
|
struct netdev_vif *netdev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = netdev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int user_suspend_mode;
|
|
int previous_suspend_mode;
|
|
u16 host_state;
|
|
int ret = 0;
|
|
int vif;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, cmd_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
user_suspend_mode = *ioctl_args->args[0] - '0';
|
|
if (user_suspend_mode != 0 && user_suspend_mode != 1) {
|
|
SLSI_ERR(sdev, "Invalid value of user_suspend_mode %d\n", user_suspend_mode);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
previous_suspend_mode = sdev->device_config.user_suspend_mode;
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
if (user_suspend_mode != previous_suspend_mode) {
|
|
SLSI_MUTEX_LOCK(sdev->netdev_add_remove_mutex);
|
|
for (vif = 1; vif <= CONFIG_SCSC_WLAN_MAX_INTERFACES; vif++) {
|
|
struct net_device *dev = slsi_get_netdev_locked(sdev, vif);
|
|
struct netdev_vif *ndev_vif;
|
|
|
|
if (!dev)
|
|
continue;
|
|
|
|
ndev_vif = netdev_priv(dev);
|
|
if (!user_suspend_mode)
|
|
cancel_work_sync(&ndev_vif->update_pkt_filter_work);
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
if (ndev_vif->activated &&
|
|
ndev_vif->vif_type == FAPI_VIFTYPE_STATION &&
|
|
ndev_vif->sta.vif_status == SLSI_VIF_STATUS_CONNECTED) {
|
|
if (user_suspend_mode) {
|
|
ret = slsi_update_packet_filters(sdev, dev);
|
|
if (sdev->igmp_offload_activated)
|
|
slsi_update_multicast_addr(sdev, dev);
|
|
} else {
|
|
ret = slsi_clear_packet_filters(sdev, dev);
|
|
}
|
|
if (ret != 0)
|
|
SLSI_NET_ERR(dev, "Error in updating /clearing the packet filters,ret=%d", ret);
|
|
}
|
|
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->netdev_add_remove_mutex);
|
|
} else {
|
|
SLSI_NET_INFO(dev, "Current suspend mode (%d) and requested mode(%d) are same\n", previous_suspend_mode, user_suspend_mode);
|
|
}
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
sdev->device_config.user_suspend_mode = user_suspend_mode;
|
|
host_state = sdev->device_config.host_state;
|
|
|
|
if (!sdev->device_config.user_suspend_mode)
|
|
host_state = host_state | SLSI_HOSTSTATE_LCD_ACTIVE;
|
|
else
|
|
host_state = host_state & ~SLSI_HOSTSTATE_LCD_ACTIVE;
|
|
sdev->device_config.host_state = host_state;
|
|
|
|
ret = slsi_mlme_set_host_state(sdev, dev, host_state);
|
|
if (ret != 0)
|
|
SLSI_NET_ERR(dev, "Error in setting the Host State, ret=%d", ret);
|
|
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return ret;
|
|
}
|
|
|
|
static int slsi_set_p2p_oppps(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
unsigned int ct_param;
|
|
unsigned int legacy_ps;
|
|
unsigned int opp_ps;
|
|
int result = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 3);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
|
|
if (ioctl_args->arg_count < 3) {
|
|
SLSI_ERR(sdev, "Invalid argument count = %d\n", ioctl_args->arg_count);
|
|
result = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
/* The NOA param shall be added only after P2P-VIF is active */
|
|
if (!ndev_vif->activated || ndev_vif->iftype != NL80211_IFTYPE_P2P_GO) {
|
|
SLSI_ERR_NODEV("P2P GO vif not activated\n");
|
|
result = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &legacy_ps)) {
|
|
SLSI_ERR(sdev, "legacy_ps: failed to read from string: '%s'\n", ioctl_args->args[0]);
|
|
result = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[1], &opp_ps)) {
|
|
SLSI_ERR(sdev, "opp_ps: failed to read from string: '%s'\n", ioctl_args->args[1]);
|
|
result = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[2], &ct_param)) {
|
|
SLSI_ERR(sdev, "ct_param: failed to read from string: '%s'\n", ioctl_args->args[2]);
|
|
result = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
if (opp_ps == 0)
|
|
result = slsi_mlme_set_ctwindow(sdev, dev, opp_ps);
|
|
else if (ct_param < (unsigned int)ndev_vif->ap.beacon_interval)
|
|
result = slsi_mlme_set_ctwindow(sdev, dev, ct_param);
|
|
else
|
|
SLSI_DBG1(sdev, SLSI_CFG80211, "p2p ct window = %d is out of range for beacon interval(%d)\n", ct_param, ndev_vif->ap.beacon_interval);
|
|
exit:
|
|
kfree(ioctl_args);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
return result;
|
|
}
|
|
|
|
static int slsi_p2p_set_noa_params(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int result = 0;
|
|
unsigned int noa_count;
|
|
unsigned int duration;
|
|
unsigned int interval;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 3);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
|
|
if (ioctl_args->arg_count < 3) {
|
|
SLSI_ERR(sdev, "Invalid argument count = %d\n", ioctl_args->arg_count);
|
|
result = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
/* The NOA param shall be added only after P2P-VIF is active */
|
|
if (!ndev_vif->activated || ndev_vif->iftype != NL80211_IFTYPE_P2P_GO) {
|
|
SLSI_ERR_NODEV("P2P GO vif not activated\n");
|
|
result = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &noa_count)) {
|
|
SLSI_ERR(sdev, "noa_count: failed to read string: '%s'\n", ioctl_args->args[0]);
|
|
result = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[1], &interval)) {
|
|
SLSI_ERR(sdev, "interval: failed to read string: '%s'\n", ioctl_args->args[1]);
|
|
result = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[2], &duration)) {
|
|
SLSI_ERR(sdev, "duration: failed to read string: '%s'\n", ioctl_args->args[2]);
|
|
result = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
/* Skip start time */
|
|
result = slsi_mlme_set_p2p_noa(sdev, dev, noa_count, interval, duration);
|
|
|
|
exit:
|
|
kfree(ioctl_args);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return result;
|
|
}
|
|
|
|
static int slsi_p2p_ecsa(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct netdev_vif *group_dev_vif;
|
|
struct net_device *group_dev = NULL;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int result = 0;
|
|
unsigned int channel;
|
|
unsigned int bandwidth;
|
|
u16 center_freq = 0;
|
|
u16 chan_info = 0;
|
|
struct cfg80211_chan_def chandef;
|
|
enum nl80211_band band;
|
|
enum nl80211_channel_type chan_type = NL80211_CHAN_NO_HT;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 2);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (ioctl_args->arg_count < 2) {
|
|
SLSI_ERR(sdev, "Invalid argument count = %d\n", ioctl_args->arg_count);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
|
|
group_dev = slsi_get_netdev(sdev, SLSI_NET_INDEX_P2PX_SWLAN);
|
|
if (!group_dev) {
|
|
SLSI_INFO(sdev, "No Group net_dev found\n");
|
|
result = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &channel)) {
|
|
SLSI_ERR(sdev, "channel: failed to read string: '%s'\n", ioctl_args->args[0]);
|
|
result = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
if (channel < 1 || channel > 165) {
|
|
SLSI_ERR(sdev, "Invalid channel : %d\n", channel);
|
|
result = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[1], &bandwidth)) {
|
|
SLSI_ERR(sdev, "bandwidth: failed to read string: '%s'\n", ioctl_args->args[1]);
|
|
result = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
band = (channel <= 14) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
|
|
center_freq = ieee80211_channel_to_frequency(channel, band);
|
|
SLSI_DBG1(sdev, SLSI_CFG80211, "p2p ecsa_params (center_freq)= (%d)\n", center_freq);
|
|
chandef.chan = ieee80211_get_channel(sdev->wiphy, center_freq);
|
|
chandef.width = (band == NL80211_BAND_2GHZ) ? NL80211_CHAN_WIDTH_20_NOHT : NL80211_CHAN_WIDTH_80;
|
|
|
|
#ifndef SSB_4963_FIXED
|
|
/* Default HT40 configuration */
|
|
if (sdev->band_5g_supported) {
|
|
if (bandwidth == 80) {
|
|
chandef.width = NL80211_CHAN_WIDTH_40;
|
|
bandwidth = 40;
|
|
if (channel == 36 || channel == 44 || channel == 149 || channel == 157)
|
|
chan_type = NL80211_CHAN_HT40PLUS;
|
|
else
|
|
chan_type = NL80211_CHAN_HT40MINUS;
|
|
}
|
|
}
|
|
#endif
|
|
if (channel == 165 && bandwidth != 20) {
|
|
bandwidth = 20;
|
|
chan_type = NL80211_CHAN_HT20;
|
|
}
|
|
cfg80211_chandef_create(&chandef, chandef.chan, chan_type);
|
|
chan_info = slsi_get_chann_info(sdev, &chandef);
|
|
if (bandwidth != 20)
|
|
center_freq = slsi_get_center_freq1(sdev, chan_info, center_freq);
|
|
group_dev_vif = netdev_priv(group_dev);
|
|
SLSI_MUTEX_LOCK(group_dev_vif->vif_mutex);
|
|
result = slsi_mlme_channel_switch(sdev, group_dev, center_freq, chan_info);
|
|
SLSI_MUTEX_UNLOCK(group_dev_vif->vif_mutex);
|
|
|
|
exit:
|
|
kfree(ioctl_args);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return result;
|
|
}
|
|
|
|
static ssize_t slsi_ap_vendor_ies_write(struct slsi_dev *sdev, struct net_device *dev, u8 *ie,
|
|
size_t ie_len, u16 purpose)
|
|
{
|
|
u8 *vendor_ie = NULL;
|
|
int result = 0;
|
|
struct netdev_vif *ndev_vif;
|
|
|
|
ndev_vif = netdev_priv(dev);
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
/* During AP start before mlme_start_req, supplicant calls set_ap_wps_ie() to send the vendor IEs for each
|
|
* beacon, probe response and association response. As we get all of them in mlme_start_req, ignoring the
|
|
* same which comes before adding GO VIF
|
|
*/
|
|
if (!ndev_vif->activated) {
|
|
SLSI_DBG1(sdev, SLSI_CFG80211, "vif not activated\n");
|
|
result = 0;
|
|
goto exit;
|
|
}
|
|
if (!(ndev_vif->iftype == NL80211_IFTYPE_P2P_GO || ndev_vif->iftype == NL80211_IFTYPE_AP)) {
|
|
SLSI_ERR(sdev, "Not AP or P2P interface. interfaceType:%d\n", ndev_vif->iftype);
|
|
result = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
vendor_ie = kmalloc(ie_len, GFP_KERNEL);
|
|
if (!vendor_ie) {
|
|
SLSI_ERR(sdev, "kmalloc failed\n");
|
|
result = -ENOMEM;
|
|
goto exit;
|
|
}
|
|
memcpy(vendor_ie, ie, ie_len);
|
|
|
|
slsi_clear_cached_ies(&ndev_vif->ap.add_info_ies, &ndev_vif->ap.add_info_ies_len);
|
|
result = slsi_ap_prepare_add_info_ies(ndev_vif, vendor_ie, ie_len);
|
|
|
|
if (result == 0)
|
|
result = slsi_mlme_add_info_elements(sdev, dev, purpose, ndev_vif->ap.add_info_ies, ndev_vif->ap.add_info_ies_len);
|
|
|
|
slsi_clear_cached_ies(&ndev_vif->ap.add_info_ies, &ndev_vif->ap.add_info_ies_len);
|
|
kfree(vendor_ie);
|
|
|
|
exit:
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return result;
|
|
}
|
|
|
|
static int slsi_set_ap_p2p_wps_ie(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int result = 0;
|
|
u8 *params;
|
|
int offset = 0;
|
|
enum if_type {
|
|
IF_TYPE_NONE,
|
|
IF_TYPE_P2P_DEVICE,
|
|
IF_TYPE_AP_P2P
|
|
} iftype = IF_TYPE_NONE;
|
|
enum frame_type {
|
|
FRAME_TYPE_NONE,
|
|
FRAME_TYPE_BEACON,
|
|
FRAME_TYPE_PROBE_RESPONSE,
|
|
FRAME_TYPE_ASSOC_RESPONSE
|
|
} frametype = FRAME_TYPE_NONE;
|
|
int params_len = buf_len - strlen(CMD_SETAPP2PWPSIE) - 1;
|
|
|
|
params = command + strlen(CMD_SETAPP2PWPSIE) + 1;
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 2);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (ioctl_args->arg_count < 2) {
|
|
SLSI_ERR(sdev, "Invalid argument count = %d\n", ioctl_args->arg_count);
|
|
result = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], (int *)&frametype)) {
|
|
SLSI_ERR(sdev, "Failed to read frame type string: '%s'\n", ioctl_args->args[0]);
|
|
result = -EINVAL;
|
|
goto exit;
|
|
}
|
|
offset = offset + strlen(ioctl_args->args[0]) + 1;
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[1], (int *)&iftype)) {
|
|
SLSI_ERR(sdev, "Failed to read iftype string: '%s'\n", ioctl_args->args[1]);
|
|
result = -EINVAL;
|
|
goto exit;
|
|
}
|
|
offset = offset + strlen(ioctl_args->args[1]) + 1;
|
|
params_len = params_len - offset;
|
|
|
|
SLSI_NET_DBG2(dev, SLSI_NETDEV,
|
|
"command=%s, frametype=%d, iftype=%d, total buf_len=%d, params_len=%d\n",
|
|
command, frametype, iftype, buf_len, params_len);
|
|
|
|
/* check the net device interface type */
|
|
if (iftype == IF_TYPE_P2P_DEVICE) {
|
|
u8 *probe_resp_ie = NULL; /* params+offset; */
|
|
|
|
if (frametype != FRAME_TYPE_PROBE_RESPONSE) {
|
|
SLSI_NET_ERR(dev, "Wrong frame type received\n");
|
|
result = -EINVAL;
|
|
goto exit;
|
|
}
|
|
probe_resp_ie = kmalloc(params_len, GFP_KERNEL);
|
|
if (!probe_resp_ie) {
|
|
SLSI_ERR(sdev, "Malloc for IEs failed\n");
|
|
kfree(ioctl_args);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
memcpy(probe_resp_ie, params + offset, params_len);
|
|
|
|
result = slsi_p2p_dev_probe_rsp_ie(sdev, dev, probe_resp_ie, params_len);
|
|
} else if (iftype == IF_TYPE_AP_P2P) {
|
|
if (frametype == FRAME_TYPE_BEACON)
|
|
result = slsi_ap_vendor_ies_write(sdev, dev, params + offset, params_len, FAPI_PURPOSE_BEACON);
|
|
else if (frametype == FRAME_TYPE_PROBE_RESPONSE)
|
|
result = slsi_ap_vendor_ies_write(sdev, dev, params + offset, params_len, FAPI_PURPOSE_PROBE_RESPONSE);
|
|
else if (frametype == FRAME_TYPE_ASSOC_RESPONSE)
|
|
result = slsi_ap_vendor_ies_write(sdev, dev, params + offset, params_len, FAPI_PURPOSE_ASSOCIATION_RESPONSE);
|
|
}
|
|
exit:
|
|
kfree(ioctl_args);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* P2P_LO_START handling.
|
|
* Add unsync vif, register for action frames and set the listen channel.
|
|
* The probe response IEs would be configured later.
|
|
*/
|
|
static int slsi_p2p_lo_start(struct net_device *dev, char *command, int cmd_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct ieee80211_channel *chan = NULL;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
unsigned int channel, duration, interval, count;
|
|
int ret = 0;
|
|
int freq;
|
|
enum nl80211_band band;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, cmd_len, 4);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (ioctl_args->arg_count < 4) {
|
|
SLSI_ERR(sdev, "Invalid argument count = %d\n", ioctl_args->arg_count);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
|
|
/* Reject LO if other operations are in progress. Back to back LO can be received.
|
|
* In such a case, if state is Listening then the listen offload flag should be true else
|
|
* reject the request as the Listening state would then be due to ROC.
|
|
*/
|
|
if (sdev->p2p_state == P2P_SCANNING || sdev->p2p_state > P2P_LISTENING ||
|
|
(sdev->p2p_state == P2P_LISTENING && !ndev_vif->unsync.listen_offload)) {
|
|
SLSI_NET_ERR(dev, "Reject LO due to ongoing P2P operation (state: %s)\n", slsi_p2p_state_text(sdev->p2p_state));
|
|
ret = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &channel)) {
|
|
SLSI_ERR(sdev, "channel: failed to read string: '%s'\n", ioctl_args->args[0]);
|
|
ret = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
if (channel < 1 || channel > 165) {
|
|
SLSI_ERR(sdev, "Invalid channel : %d\n", channel);
|
|
ret = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[1], &duration)) {
|
|
SLSI_ERR(sdev, "duration: failed to read string: '%s'\n", ioctl_args->args[1]);
|
|
ret = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[2], &interval)) {
|
|
SLSI_ERR(sdev, "interval: failed to read string: '%s'\n", ioctl_args->args[2]);
|
|
ret = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[3], &count)) {
|
|
SLSI_ERR(sdev, "count: failed to read string: '%s'\n", ioctl_args->args[3]);
|
|
ret = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
if (!ndev_vif->activated) {
|
|
ret = slsi_mlme_add_vif(sdev, dev, dev->dev_addr, dev->dev_addr);
|
|
if (ret != 0) {
|
|
SLSI_NET_ERR(dev, "Unsync vif addition failed\n");
|
|
goto exit;
|
|
}
|
|
|
|
ndev_vif->activated = true;
|
|
ndev_vif->mgmt_tx_data.exp_frame = SLSI_PA_INVALID;
|
|
SLSI_P2P_STATE_CHANGE(sdev, P2P_IDLE_VIF_ACTIVE);
|
|
|
|
ret = slsi_mlme_register_action_frame(sdev, dev, SLSI_ACTION_FRAME_PUBLIC, SLSI_ACTION_FRAME_PUBLIC);
|
|
if (ret != 0) {
|
|
SLSI_NET_ERR(dev, "Action frame registration for unsync vif failed\n");
|
|
goto exit_with_vif_deactivate;
|
|
}
|
|
}
|
|
|
|
/* Send set_channel irrespective of the values of LO parameters as they are not cached
|
|
* in driver to check whether they have changed.
|
|
*/
|
|
band = (channel <= 14) ? NL80211_BAND_2GHZ : NL80211_BAND_5GHZ;
|
|
freq = ieee80211_channel_to_frequency(channel, band);
|
|
chan = ieee80211_get_channel(sdev->wiphy, freq);
|
|
if (!chan) {
|
|
SLSI_NET_ERR(dev, "Incorrect channel: %u - Listen Offload failed\n", channel);
|
|
ret = -EINVAL;
|
|
goto exit_with_vif_deactivate;
|
|
}
|
|
|
|
ret = slsi_mlme_set_channel(sdev, dev, chan, duration, interval, count);
|
|
if (ret != 0) {
|
|
SLSI_NET_ERR(dev, "Set channel for unsync vif failed\n");
|
|
goto exit_with_vif_deactivate;
|
|
} else {
|
|
ndev_vif->chan = chan;
|
|
ndev_vif->driver_channel = chan->hw_value;
|
|
}
|
|
/* If framework sends the values for listen offload as 1,500,5000 and 6,
|
|
* where 5000ms (5 seconds) is the listen interval which needs to be repeated
|
|
* 6 times(i.e. count). Hence listen_end_ind comes after 30 seconds
|
|
* (6 * 5000 = 30000ms) Hence host should wait 31 seconds to delete the
|
|
* unsync VIF for one such P2P listen offload request.
|
|
*/
|
|
slsi_p2p_queue_unsync_vif_del_work(ndev_vif, interval * count + 1000);
|
|
ndev_vif->unsync.listen_offload = true;
|
|
SLSI_P2P_STATE_CHANGE(ndev_vif->sdev, P2P_LISTENING);
|
|
goto exit;
|
|
|
|
exit_with_vif_deactivate:
|
|
slsi_p2p_vif_deactivate(sdev, dev, true);
|
|
exit:
|
|
kfree(ioctl_args);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* P2P_LO_STOP handling.
|
|
* Clear listen offload flag.
|
|
* Delete the P2P unsynchronized vif.
|
|
*/
|
|
static int slsi_p2p_lo_stop(struct net_device *dev, char *command, int cmd_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
|
|
WARN_ON((!ndev_vif->unsync.listen_offload) || (ndev_vif->sdev->p2p_state != P2P_LISTENING));
|
|
|
|
ndev_vif->unsync.listen_offload = false;
|
|
|
|
/* Deactivating the p2p unsynchronized vif */
|
|
if (ndev_vif->sdev->p2p_state == P2P_LISTENING)
|
|
slsi_p2p_vif_deactivate(ndev_vif->sdev, ndev_vif->wdev.netdev, true);
|
|
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int slsi_rx_filter_add(struct net_device *dev, char *buffer, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int ret = 0;
|
|
int filter_num = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(buffer, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
filter_num = *ioctl_args->args[0] - '0';
|
|
if (filter_num < 0 || filter_num > 3) {
|
|
SLSI_ERR(sdev, "Invalid value of filter_num %d\n", filter_num);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
sdev->device_config.rx_filter_num = filter_num;
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
kfree(ioctl_args);
|
|
return ret;
|
|
}
|
|
|
|
static int slsi_rx_filter_remove(struct net_device *dev, char *buffer, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
sdev->device_config.rx_filter_num = 0;
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef CONFIG_SCSC_WLAN_WIFI_SHARING
|
|
#if !defined(CONFIG_SCSC_WLAN_MHS_STATIC_INTERFACE) || (defined(SCSC_SEP_VERSION) && SCSC_SEP_VERSION < 9)
|
|
static int slsi_create_interface(struct net_device *dev, char *buffer, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
struct net_device *ap_dev;
|
|
char *intf_name = NULL;
|
|
|
|
ioctl_args = slsi_get_private_command_args(buffer, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
intf_name = ioctl_args->args[0];
|
|
if (strcmp(CONFIG_SCSC_AP_INTERFACE_NAME, intf_name) != 0) {
|
|
SLSI_NET_ERR(dev, "Creation of %s not allowed!\n", intf_name);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
ap_dev = slsi_get_netdev(sdev, SLSI_NET_INDEX_P2PX_SWLAN);
|
|
if (ap_dev && (strcmp(ap_dev->name, intf_name) == 0)) {
|
|
SLSI_NET_ERR(dev, "%s already created\n", intf_name);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
ap_dev = slsi_dynamic_interface_create(sdev->wiphy, intf_name, NL80211_IFTYPE_AP, NULL);
|
|
if (ap_dev) {
|
|
sdev->netdev_ap = ap_dev;
|
|
kfree(ioctl_args);
|
|
return 0;
|
|
}
|
|
|
|
SLSI_NET_ERR(dev, "Failed to create AP interface %s\n", intf_name);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
static int slsi_delete_interface(struct net_device *dev, char *buffer, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
char *intf_name = NULL;
|
|
|
|
ioctl_args = slsi_get_private_command_args(buffer, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
intf_name = ioctl_args->args[0];
|
|
if (strcmp(CONFIG_SCSC_AP_INTERFACE_NAME, intf_name) != 0) {
|
|
SLSI_NET_ERR(dev, "Deletion of %s not allowed!\n", intf_name);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
if (strcmp(intf_name, CONFIG_SCSC_AP_INTERFACE_NAME) == 0)
|
|
dev = slsi_get_netdev(sdev, SLSI_NET_INDEX_P2PX_SWLAN);
|
|
|
|
if (!dev) {
|
|
SLSI_WARN(sdev, "AP dev is NULL");
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
ndev_vif = netdev_priv(dev);
|
|
|
|
SLSI_MUTEX_LOCK(sdev->netdev_add_remove_mutex);
|
|
if (ndev_vif->activated)
|
|
slsi_stop_net_dev(sdev, dev);
|
|
SLSI_MUTEX_UNLOCK(sdev->netdev_add_remove_mutex);
|
|
slsi_netif_remove_rtlnl_locked(sdev, dev);
|
|
|
|
sdev->netdev_ap = NULL;
|
|
SLSI_DBG1_NODEV(SLSI_MLME, "Successfully deleted AP interface %s ", intf_name);
|
|
|
|
kfree(ioctl_args);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int slsi_get_indoor_channels(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
char op[150] = "";
|
|
char int_string[30] = "";
|
|
int i;
|
|
int len = 0;
|
|
|
|
SLSI_DBG1_NODEV(SLSI_MLME, "GET_INDOOR_CHANNELS : %d\n", sdev->num_5g_restricted_channels);
|
|
|
|
for (i = 0; i < sdev->num_5g_restricted_channels; i++) {
|
|
sprintf(int_string, "%d", sdev->wifi_sharing_5g_restricted_channels[i]);
|
|
strcat(op, int_string);
|
|
strcat(op, " ");
|
|
}
|
|
|
|
len = snprintf(command, buf_len, "%d %s", sdev->num_5g_restricted_channels, op);
|
|
|
|
return len;
|
|
}
|
|
#endif
|
|
|
|
static int slsi_legacy_roam_trigger_write(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int trigger_value = 0;
|
|
int ret = 0;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &trigger_value)) {
|
|
SLSI_ERR(sdev, "Invalid trigger_value: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (trigger_value > -50 || trigger_value < -100) {
|
|
SLSI_ERR(sdev, "Invalid trigger_value: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
#ifdef CONFIG_SCSC_WLAN_WES_NCHO
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is enabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
#endif
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
if (ndev_vif->sta.vif_status != SLSI_VIF_STATUS_CONNECTED) {
|
|
SLSI_NET_ERR(dev, "sta is not in connected state\n");
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return -EPERM;
|
|
}
|
|
ret = slsi_mlme_set_roaming_parameters(sdev, dev, SLSI_PSID_UNIFI_ROAM_RSSI_SCAN_TRIGGER, trigger_value, 1);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
kfree(ioctl_args);
|
|
return ret;
|
|
}
|
|
|
|
static int slsi_legacy_roam_scan_trigger_read(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int mib_value = 0;
|
|
int res = 0;
|
|
|
|
#ifdef CONFIG_SCSC_WLAN_WES_NCHO
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is enabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
#endif
|
|
|
|
res = slsi_get_mib_roam(sdev, SLSI_PSID_UNIFI_ROAM_RSSI_SCAN_TRIGGER, &mib_value);
|
|
if (res)
|
|
return res;
|
|
res = snprintf(command, buf_len, "%s %d", CMD_GETROAMTRIGGER, mib_value);
|
|
return res;
|
|
}
|
|
|
|
static int slsi_roam_add_scan_frequencies_legacy(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int result = 0;
|
|
int i, j;
|
|
int new_channels[SLSI_MAX_CHANNEL_LIST];
|
|
int curr_channel_count = 0;
|
|
int found = 0;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
const u8 *connected_ssid = NULL;
|
|
u32 network_map_channels_count = 0;
|
|
u8 network_map_channels[SLSI_ROAMING_CHANNELS_MAX];
|
|
u8 merged_channels[SLSI_ROAMING_CHANNELS_MAX * 2];
|
|
u32 merge_chan_count = 0;
|
|
int new_freq_count = 0;
|
|
int new_freqs[SLSI_MAX_FREQUENCY_LIST] = {0};
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 21);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
if (!ndev_vif->activated || ndev_vif->vif_type != FAPI_VIFTYPE_STATION ||
|
|
ndev_vif->sta.vif_status != SLSI_VIF_STATUS_CONNECTED) {
|
|
SLSI_NET_ERR(dev, "Not a STA vif or status is not CONNECTED\n");
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return -EPERM;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
#ifdef CONFIG_SCSC_WLAN_WES_NCHO
|
|
if (sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is enabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
#endif
|
|
|
|
if (sdev->device_config.legacy_roam_scan_list.n == SLSI_MAX_CHANNEL_LIST) {
|
|
SLSI_ERR(sdev, "Roam scan list is already full\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Adding Connected channel to legacy_roam_scan_list */
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
if (sdev->device_config.legacy_roam_scan_list.n == 0) {
|
|
sdev->device_config.legacy_roam_scan_list.n = 1;
|
|
sdev->device_config.legacy_roam_scan_list.channels[0] = ndev_vif->chan->hw_value;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &new_freq_count)) {
|
|
SLSI_ERR(sdev, "Invalid freq_count string: '%s'\n", ioctl_args->args[0]);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (new_freq_count < 1 || new_freq_count > SLSI_MAX_FREQUENCY_LIST ||
|
|
(ioctl_args->arg_count - 1) < new_freq_count) {
|
|
SLSI_ERR(sdev, "Invalid value of freq_count %d\n", new_freq_count);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
curr_channel_count = sdev->device_config.legacy_roam_scan_list.n;
|
|
for (i = 0; i < new_freq_count; i++) {
|
|
if (!slsi_str_to_int(ioctl_args->args[i + 1], &new_freqs[i])) {
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
new_channels[i] = ieee80211_frequency_to_channel(new_freqs[i]);
|
|
|
|
if (new_channels[i] < 1 || new_channels[i] > 165) {
|
|
SLSI_ERR(sdev, "Invalid channel : %d\n", new_channels[i]);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
for (j = 0; j < curr_channel_count; j++) {
|
|
found = 0;
|
|
if (sdev->device_config.legacy_roam_scan_list.channels[j] == new_channels[i]) {
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
sdev->device_config.legacy_roam_scan_list.channels[curr_channel_count] = new_channels[i];
|
|
curr_channel_count++;
|
|
}
|
|
if (curr_channel_count >= SLSI_MAX_CHANNEL_LIST) {
|
|
curr_channel_count = SLSI_MAX_CHANNEL_LIST;
|
|
break;
|
|
}
|
|
}
|
|
|
|
sdev->device_config.legacy_roam_scan_list.n = curr_channel_count;
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
connected_ssid = cfg80211_find_ie(WLAN_EID_SSID, ndev_vif->sta.sta_bss->ies->data,
|
|
ndev_vif->sta.sta_bss->ies->len);
|
|
|
|
network_map_channels_count = slsi_roaming_scan_configure_channels(sdev, dev, connected_ssid, network_map_channels);
|
|
merge_chan_count = slsi_merge_lists(network_map_channels, network_map_channels_count,
|
|
sdev->device_config.legacy_roam_scan_list.channels,
|
|
sdev->device_config.legacy_roam_scan_list.n,
|
|
merged_channels);
|
|
|
|
result = slsi_mlme_set_cached_channels(sdev, dev, merge_chan_count, merged_channels);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
kfree(ioctl_args);
|
|
return result;
|
|
}
|
|
|
|
static int slsi_roam_add_scan_channels_legacy(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int result = 0;
|
|
int i, j, new_channel_count = 0;
|
|
int new_channels[SLSI_MAX_CHANNEL_LIST];
|
|
int curr_channel_count = 0;
|
|
int found = 0;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
const u8 *connected_ssid = NULL;
|
|
u32 network_map_channels_count = 0;
|
|
u8 network_map_channels[SLSI_ROAMING_CHANNELS_MAX];
|
|
u8 merged_channels[SLSI_ROAMING_CHANNELS_MAX * 2];
|
|
u32 merge_chan_count = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 21);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
if (!ndev_vif->activated || ndev_vif->vif_type != FAPI_VIFTYPE_STATION ||
|
|
ndev_vif->sta.vif_status != SLSI_VIF_STATUS_CONNECTED) {
|
|
SLSI_NET_ERR(dev, "Not a STA vif or status is not CONNECTED\n");
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return -EPERM;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
#ifdef CONFIG_SCSC_WLAN_WES_NCHO
|
|
if (sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is enabled.\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
#endif
|
|
|
|
if (sdev->device_config.legacy_roam_scan_list.n == SLSI_MAX_CHANNEL_LIST) {
|
|
SLSI_ERR(sdev, "Roam scan list is already full\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Adding Connected channel to legacy_roam_scan_list */
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
if (sdev->device_config.legacy_roam_scan_list.n == 0 && ndev_vif->chan) {
|
|
sdev->device_config.legacy_roam_scan_list.n = 1;
|
|
sdev->device_config.legacy_roam_scan_list.channels[0] = ndev_vif->chan->hw_value;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &new_channel_count)) {
|
|
SLSI_ERR(sdev, "Invalid channel_count string: '%s'\n", ioctl_args->args[0]);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (new_channel_count < 1 || new_channel_count > SLSI_MAX_CHANNEL_LIST || (ioctl_args->arg_count - 1) < new_channel_count) {
|
|
SLSI_ERR(sdev, "Invalid value of channel_count %d\n", new_channel_count);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
curr_channel_count = sdev->device_config.legacy_roam_scan_list.n;
|
|
|
|
for (i = 0; i < new_channel_count; i++) {
|
|
if (!slsi_str_to_int(ioctl_args->args[i + 1], &new_channels[i])) {
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
if (new_channels[i] < 1 || new_channels[i] > 165) {
|
|
SLSI_ERR(sdev, "Invalid channel : %d\n", new_channels[i]);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
for (j = 0; j < curr_channel_count; j++) {
|
|
found = 0;
|
|
if (sdev->device_config.legacy_roam_scan_list.channels[j] == new_channels[i]) {
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
sdev->device_config.legacy_roam_scan_list.channels[curr_channel_count] = new_channels[i];
|
|
curr_channel_count++;
|
|
}
|
|
if (curr_channel_count >= SLSI_MAX_CHANNEL_LIST) {
|
|
curr_channel_count = SLSI_MAX_CHANNEL_LIST;
|
|
break;
|
|
}
|
|
}
|
|
|
|
sdev->device_config.legacy_roam_scan_list.n = curr_channel_count;
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
connected_ssid = cfg80211_find_ie(WLAN_EID_SSID, ndev_vif->sta.sta_bss->ies->data,
|
|
ndev_vif->sta.sta_bss->ies->len);
|
|
|
|
network_map_channels_count = slsi_roaming_scan_configure_channels(sdev, dev, connected_ssid, network_map_channels);
|
|
merge_chan_count = slsi_merge_lists(network_map_channels, network_map_channels_count,
|
|
sdev->device_config.legacy_roam_scan_list.channels,
|
|
sdev->device_config.legacy_roam_scan_list.n,
|
|
merged_channels);
|
|
|
|
result = slsi_mlme_set_cached_channels(sdev, dev, merge_chan_count, merged_channels);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
kfree(ioctl_args);
|
|
return result;
|
|
}
|
|
|
|
static int slsi_roam_scan_frequencies_read_legacy(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int freq_list[MAX_FREQUENCY_COUNT] = {0};
|
|
struct sk_buff *ind = NULL;
|
|
int pos = 0;
|
|
int i;
|
|
int freq_count = 0;
|
|
|
|
#ifdef CONFIG_SCSC_WLAN_WES_NCHO
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is enabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
#endif
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
if (ndev_vif->sta.vif_status != SLSI_VIF_STATUS_CONNECTED) {
|
|
SLSI_NET_ERR(dev, "STA is not in connected state\n");
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
freq_count = 0;
|
|
goto output;
|
|
}
|
|
|
|
ind = slsi_mlme_roaming_channel_list_req(sdev, dev);
|
|
if (!ind) {
|
|
SLSI_ERR(sdev, "RCL ind is NULL!\n");
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return -EINVAL;
|
|
}
|
|
|
|
freq_count = slsi_get_rcl_freq_list(sdev, ind, freq_list);
|
|
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
if (!freq_count) {
|
|
SLSI_ERR(sdev, "Frequency count is 0!\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
output:
|
|
pos = scnprintf(command, buf_len, "%s %d", CMD_GETROAMSCANFREQUENCIES_LEGACY, freq_count);
|
|
for (i = 0; i < freq_count; i++)
|
|
pos += scnprintf(command + pos, buf_len - pos, " %d", freq_list[i]);
|
|
|
|
return pos;
|
|
}
|
|
|
|
static int slsi_roam_scan_channels_read_legacy(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
u16 channel_list[MAX_CHANNEL_COUNT] = {0};
|
|
struct sk_buff *ind = NULL;
|
|
int pos = 0;
|
|
int i;
|
|
int channel_count = 0;
|
|
|
|
#ifdef CONFIG_SCSC_WLAN_WES_NCHO
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is enabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
#endif
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
if (ndev_vif->sta.vif_status != SLSI_VIF_STATUS_CONNECTED) {
|
|
SLSI_NET_ERR(dev, "STA is not in connected state\n");
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
channel_count = 0;
|
|
goto output;
|
|
}
|
|
|
|
ind = slsi_mlme_roaming_channel_list_req(sdev, dev);
|
|
if (!ind) {
|
|
SLSI_ERR(sdev, "RCL ind is NULL!\n");
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return -EINVAL;
|
|
}
|
|
|
|
channel_count = slsi_get_rcl_channel_list(sdev, ind, channel_list);
|
|
if (!channel_count) {
|
|
SLSI_ERR(sdev, "Channel count is 0!");
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return -EINVAL;
|
|
}
|
|
output:
|
|
pos = scnprintf(command, buf_len, "%s %d", CMD_GETROAMSCANCHANNELS, channel_count);
|
|
for (i = 0; i < channel_count; i++)
|
|
pos += scnprintf(command + pos, buf_len - pos, " %d", channel_list[i]);
|
|
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return pos;
|
|
}
|
|
|
|
static int slsi_reassoc_frequency_write_legacy(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
u8 bssid[6] = { 0 };
|
|
int freq;
|
|
int r = 0;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 2);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
#ifdef CONFIG_SCSC_WLAN_WES_NCHO
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is enabled.\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
#endif
|
|
if (strlen(ioctl_args->args[0]) != 17) {
|
|
SLSI_ERR(sdev, "Invalid MAC address length :%d\n", (int)strlen(ioctl_args->args[0]));
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
slsi_machexstring_to_macarray(ioctl_args->args[0], bssid);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[1], &freq)) {
|
|
SLSI_ERR(sdev, "Invalid frequency string: '%s'\n", ioctl_args->args[1]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
|
|
r = slsi_mlme_roam(sdev, dev, bssid, freq);
|
|
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return r;
|
|
}
|
|
|
|
static int slsi_reassoc_write_legacy(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
u8 bssid[6] = { 0 };
|
|
int channel;
|
|
int freq;
|
|
enum nl80211_band band = NL80211_BAND_2GHZ;
|
|
int r = 0;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 2);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
#ifdef CONFIG_SCSC_WLAN_WES_NCHO
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is enabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
#endif
|
|
if (strlen(ioctl_args->args[0]) != 17) {
|
|
SLSI_ERR(sdev, "Invalid MAC address length :%d\n", (int)strlen(ioctl_args->args[0]));
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
slsi_machexstring_to_macarray(ioctl_args->args[0], bssid);
|
|
if (!slsi_str_to_int(ioctl_args->args[1], &channel)) {
|
|
SLSI_ERR(sdev, "Invalid channel string: '%s'\n", ioctl_args->args[1]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (channel < 1 || channel > 165) {
|
|
SLSI_ERR(sdev, "Invalid channel : %d\n", channel);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (channel > 14)
|
|
band = NL80211_BAND_5GHZ;
|
|
freq = (u16)ieee80211_channel_to_frequency(channel, band);
|
|
|
|
ndev_vif = netdev_priv(dev);
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
|
|
r = slsi_mlme_roam(sdev, dev, bssid, freq);
|
|
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return r;
|
|
}
|
|
|
|
static int slsi_set_country_rev(struct net_device *dev, char *command, int cmd_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
char alpha2_rev[] = {0, 0, 0, 0};
|
|
int status = 0;
|
|
char *country_code = NULL;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, cmd_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
country_code = ioctl_args->args[0];
|
|
memcpy(alpha2_rev, country_code, strlen(country_code) < 4 ? strlen(country_code) : 4);
|
|
|
|
status = slsi_set_country_update_regd(sdev, alpha2_rev, strlen(country_code) < 4 ? strlen(country_code) : 4);
|
|
|
|
kfree(ioctl_args);
|
|
return status;
|
|
}
|
|
|
|
static int slsi_get_country_rev(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
u8 buf[5];
|
|
int len = 0;
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
len = snprintf(command, buf_len, "%s %c%c %d", CMD_GETCOUNTRYREV,
|
|
sdev->device_config.domain_info.regdomain->alpha2[0],
|
|
sdev->device_config.domain_info.regdomain->alpha2[1],
|
|
sdev->device_config.domain_info.regdomain->dfs_region);
|
|
|
|
return len;
|
|
}
|
|
|
|
static int slsi_ioctl_set_roam_band(struct net_device *dev, char *command, int cmd_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
uint roam_band = 0;
|
|
#ifdef CONFIG_SCSC_WLAN_WES_NCHO
|
|
int ret = 0;
|
|
#endif
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, cmd_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
roam_band = *ioctl_args->args[0] - '0';
|
|
if (roam_band > SLSI_MAX_ROAMBAND_VALUE) {
|
|
SLSI_ERR(sdev, "Invalid value for Roam Band %d\n", roam_band);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
/* If SETROAMBAND 0 is received, then roam band will be set to 2GHZ,
|
|
* if 5GHZ supported then 2GHZ+5GHZ, if 6GHZ supported then 2GHZ+5GHZ+6GHZ
|
|
*/
|
|
if (roam_band == FAPI_BAND_AUTO) {
|
|
roam_band = FAPI_BAND_2_4GHZ;
|
|
if (sdev->band_5g_supported)
|
|
roam_band |= FAPI_BAND_5GHZ;
|
|
#ifdef CONFIG_SCSC_WLAN_SUPPORT_6G
|
|
if (sdev->band_6g_supported)
|
|
roam_band |= FAPI_BAND_6GHZ;
|
|
#endif
|
|
}
|
|
|
|
#ifdef CONFIG_SCSC_WLAN_WES_NCHO
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (sdev->device_config.supported_roam_band == roam_band) {
|
|
SLSI_DBG1_NODEV(SLSI_MLME, "roam band is already %d\n", roam_band);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return ret;
|
|
}
|
|
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
ret = slsi_mlme_set_band_req(sdev, dev, roam_band, 1);
|
|
if (ret == -EIO) {
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return ret;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
sdev->device_config.supported_roam_band = roam_band;
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return ret;
|
|
#else
|
|
SLSI_ERR(sdev, "NCHO is not supported\n");
|
|
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
#endif
|
|
}
|
|
|
|
#ifdef CONFIG_SCSC_WLAN_WES_NCHO
|
|
uint slsi_band_to_fw_band_maping(uint band)
|
|
{
|
|
switch (band) {
|
|
case SLSI_FREQ_BAND_AUTO:
|
|
return FAPI_BAND_2_4GHZ_5GHZ;
|
|
case SLSI_FREQ_BAND_5GHZ:
|
|
return FAPI_BAND_5GHZ;
|
|
case SLSI_FREQ_BAND_2GHZ:
|
|
return FAPI_BAND_2_4GHZ;
|
|
case SLSI_FREQ_BAND_2_4GHZ_5GHZ_6GHZ:
|
|
return FAPI_BAND_2_4GHZ_5GHZ_6GHZ;
|
|
case SLSI_FREQ_BAND_6GHZ:
|
|
return FAPI_BAND_6GHZ;
|
|
case SLSI_FREQ_BAND_5GHZ_6GHZ:
|
|
return FAPI_BAND_5GHZ_6GHZ;
|
|
case SLSI_FREQ_BAND_2_4GHZ_6GHZ:
|
|
return FAPI_BAND_2_4GHZ_6GHZ;
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static int slsi_ioctl_set_band(struct net_device *dev, char *command, int cmd_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
uint band = 0;
|
|
uint internal_band = 0; /* used for driver and firmware mapping */
|
|
#ifdef CONFIG_SCSC_WLAN_WES_NCHO
|
|
int ret = 0;
|
|
#endif
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, cmd_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
band = *ioctl_args->args[0] - '0';
|
|
if (band > SLSI_MAX_BAND_VALUE) {
|
|
SLSI_ERR(sdev, "Invalid value for Band %d\n", band);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
#ifdef CONFIG_SCSC_WLAN_WES_NCHO
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (sdev->device_config.supported_band == band) {
|
|
SLSI_DBG1_NODEV(SLSI_MLME, "band is already %d\n", band);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return ret;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
internal_band = slsi_band_to_fw_band_maping(band);
|
|
if (internal_band < 0) {
|
|
SLSI_ERR(sdev, "Invalid value for Band = %d\n", band);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
ret = slsi_mlme_set_band_req(sdev, dev, internal_band, 0);
|
|
if (ret == -EIO) {
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return ret;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
sdev->device_config.supported_band = band;
|
|
slsi_band_cfg_update(sdev, band);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
kfree(ioctl_args);
|
|
return ret;
|
|
#else
|
|
SLSI_ERR(sdev, "NCHO is not supported\n");
|
|
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
#endif
|
|
}
|
|
static int slsi_ioctl_get_roam_band(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int pos = 0;
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
|
|
#ifdef CONFIG_SCSC_WLAN_WES_NCHO
|
|
if (slsi_is_test_mode_enabled() || sdev->device_config.ncho_mode) {
|
|
#else
|
|
if (sdev->device_config.ncho_mode) {
|
|
#endif
|
|
pos = scnprintf(command, buf_len, "%s %d", CMD_GETROAMBAND, sdev->device_config.supported_roam_band);
|
|
} else {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
pos = -EINVAL;
|
|
}
|
|
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return pos;
|
|
}
|
|
|
|
static int slsi_ioctl_get_band(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int pos = 0;
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
|
|
#ifdef CONFIG_SCSC_WLAN_WES_NCHO
|
|
if (slsi_is_test_mode_enabled() || sdev->device_config.ncho_mode) {
|
|
#else
|
|
if (sdev->device_config.ncho_mode) {
|
|
#endif
|
|
pos = scnprintf(command, buf_len, "%s %d", CMD_GETBAND, sdev->device_config.supported_band);
|
|
} else {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
pos = -EINVAL;
|
|
}
|
|
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return pos;
|
|
}
|
|
|
|
static int slsi_factory_freq_band_write(struct net_device *dev, char *command, int cmd_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
uint band = 0;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, cmd_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
band = *ioctl_args->args[0] - '0';
|
|
if (band > 2) {
|
|
SLSI_ERR(sdev, "Invalid value : Band Must be 0/1/2 band %d\n", band);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
slsi_band_update(sdev, band);
|
|
/* Convert to correct Mib value (intra_band:1, all_band:2) */
|
|
kfree(ioctl_args);
|
|
return slsi_set_mib_roam(sdev, NULL, SLSI_PSID_UNIFI_ROAM_SCAN_BAND, (band == SLSI_FREQ_BAND_AUTO) ? 2 : 1);
|
|
}
|
|
|
|
#ifdef CONFIG_SCSC_WLAN_WES_NCHO
|
|
static int slsi_roam_scan_trigger_write(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int mib_value = 0;
|
|
int ret = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &mib_value)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (mib_value > -50 || mib_value < -100) {
|
|
SLSI_ERR(sdev, "Invalid trigger_value: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
ret = slsi_mlme_set_roaming_parameters(sdev, dev, SLSI_PSID_UNIFI_ROAM_NCHO_RSSI_TRIGGER, mib_value, 1);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return ret;
|
|
}
|
|
|
|
static int slsi_roam_scan_trigger_read(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int mib_value = 0;
|
|
int res;
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
res = slsi_get_mib_roam(sdev, SLSI_PSID_UNIFI_ROAM_NCHO_RSSI_TRIGGER, &mib_value);
|
|
if (res)
|
|
return res;
|
|
res = snprintf(command, buf_len, "%s %d", CMD_GETROAMTRIGGER, mib_value);
|
|
return res;
|
|
}
|
|
|
|
static int slsi_roam_delta_trigger_write(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int mib_value = 0;
|
|
int ret = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &mib_value)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (mib_value > 100 || mib_value < 0) {
|
|
SLSI_ERR(sdev, "Invalid delta trigger_value: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
ret = slsi_mlme_set_roaming_parameters(sdev, dev, SLSI_PSID_UNIFI_ROAM_NCHO_RSSI_DELTA, mib_value, 1);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return ret;
|
|
}
|
|
|
|
static int slsi_roam_delta_trigger_read(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int mib_value = 0;
|
|
int res;
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
res = slsi_get_mib_roam(sdev, SLSI_PSID_UNIFI_ROAM_NCHO_RSSI_DELTA, &mib_value);
|
|
if (res)
|
|
return res;
|
|
|
|
res = snprintf(command, buf_len, "%s %d", CMD_GETROAMDELTA, mib_value);
|
|
return res;
|
|
}
|
|
|
|
static int slsi_reassoc_frequency_write(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
u8 bssid[6] = { 0 };
|
|
int freq = 0;
|
|
int r = 0;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 2);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
if (ioctl_args->arg_count != 2) {
|
|
SLSI_ERR(sdev, "Not enough arguments\n");
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (strlen(ioctl_args->args[0]) != 17) {
|
|
SLSI_ERR(sdev, "Invalid MAC address length :%d\n", (int)strlen(ioctl_args->args[0]));
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
slsi_machexstring_to_macarray(ioctl_args->args[0], bssid);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[1], &freq)) {
|
|
SLSI_ERR(sdev, "Invalid freq string: '%s'\n", ioctl_args->args[1]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
|
|
r = slsi_mlme_roam(sdev, dev, bssid, freq);
|
|
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
kfree(ioctl_args);
|
|
return r;
|
|
}
|
|
|
|
static int slsi_reassoc_write(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
u8 bssid[6] = { 0 };
|
|
int channel = 0;
|
|
int freq = 0;
|
|
enum nl80211_band band = NL80211_BAND_2GHZ;
|
|
int r = 0;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 2);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
if (ioctl_args->arg_count != 2) {
|
|
SLSI_ERR(sdev, "Not enough arguments\n");
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (strlen(ioctl_args->args[0]) != 17) {
|
|
SLSI_ERR(sdev, "Invalid MAC address length :%d\n", (int)strlen(ioctl_args->args[0]));
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
slsi_machexstring_to_macarray(ioctl_args->args[0], bssid);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[1], &channel)) {
|
|
SLSI_ERR(sdev, "Invalid channel string: '%s'\n", ioctl_args->args[1]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (channel < 1 || channel > 165) {
|
|
SLSI_ERR(sdev, "Invalid channel : %d\n", channel);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (channel > 14)
|
|
band = NL80211_BAND_5GHZ;
|
|
freq = (u16)ieee80211_channel_to_frequency(channel, band);
|
|
|
|
ndev_vif = netdev_priv(dev);
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
|
|
r = slsi_mlme_roam(sdev, dev, bssid, freq);
|
|
|
|
kfree(ioctl_args);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return r;
|
|
}
|
|
|
|
static int slsi_cached_channel_scan_period_write(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int mib_value = 0;
|
|
int ret = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &mib_value)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (mib_value > 60 || mib_value < 0) {
|
|
SLSI_ERR(sdev, "Invalid roam scan period: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
ret = slsi_mlme_set_roaming_parameters(sdev, dev, SLSI_PSID_UNIFI_ROAM_NCHO_CACHED_SCAN_PERIOD, mib_value * 1000000, 4);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return ret;
|
|
}
|
|
|
|
static int slsi_cached_channel_scan_period_read(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int mib_value = 0;
|
|
int res;
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
res = slsi_get_mib_roam(sdev, SLSI_PSID_UNIFI_ROAM_NCHO_CACHED_SCAN_PERIOD, &mib_value);
|
|
if (res)
|
|
return res;
|
|
|
|
res = snprintf(command, buf_len, "%s %d", CMD_GETROAMSCANPERIOD, mib_value / 1000000);
|
|
|
|
return res;
|
|
}
|
|
|
|
static int slsi_full_roam_scan_period_write(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int mib_value = 0;
|
|
int ret = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &mib_value)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
if (mib_value > 600 || mib_value < 0) {
|
|
SLSI_ERR(sdev, "Invalid full roam scan period: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
ret = slsi_mlme_set_roaming_parameters(sdev, dev, SLSI_PSID_UNIFI_ROAM_NCHO_FULL_SCAN_PERIOD, mib_value * 1000000, 4);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return ret;
|
|
}
|
|
|
|
static int slsi_full_roam_scan_period_read(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int mib_value = 0;
|
|
int res;
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
res = slsi_get_mib_roam(sdev, SLSI_PSID_UNIFI_ROAM_NCHO_FULL_SCAN_PERIOD, &mib_value);
|
|
if (res)
|
|
return res;
|
|
|
|
res = snprintf(command, buf_len, "%s %d", CMD_GETFULLROAMSCANPERIOD, mib_value / 1000000);
|
|
|
|
return res;
|
|
}
|
|
|
|
static int slsi_roam_scan_max_active_channel_time_write(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int mib_value = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &mib_value)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
if (mib_value > 300 || mib_value < 3) {
|
|
SLSI_ERR(sdev, "Invalid scan channel time: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
kfree(ioctl_args);
|
|
return slsi_set_mib_roam(sdev, NULL, SLSI_PSID_UNIFI_ROAM_NCHO_SCAN_MAX_ACTIVE_CHANNEL_TIME, mib_value);
|
|
}
|
|
|
|
static int slsi_roam_scan_max_active_channel_time_read(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int mib_value = 0;
|
|
int res;
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
res = slsi_get_mib_roam(sdev, SLSI_PSID_UNIFI_ROAM_NCHO_SCAN_MAX_ACTIVE_CHANNEL_TIME, &mib_value);
|
|
if (res)
|
|
return res;
|
|
|
|
res = snprintf(command, buf_len, "%s %d", CMD_GETSCANCHANNELTIME, mib_value);
|
|
|
|
return res;
|
|
}
|
|
|
|
static int slsi_roam_scan_probe_interval_write(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int mib_value = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &mib_value)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
if (mib_value > 10 || mib_value < 1) {
|
|
SLSI_ERR(sdev, "Invalid scan probes: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
kfree(ioctl_args);
|
|
return slsi_set_mib_roam(sdev, NULL, SLSI_PSID_UNIFI_ROAM_NCHO_SCAN_NPROBE, mib_value);
|
|
}
|
|
|
|
static int slsi_roam_scan_probe_interval_read(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int mib_value = 0;
|
|
int res;
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
res = slsi_get_mib_roam(sdev, SLSI_PSID_UNIFI_ROAM_NCHO_SCAN_NPROBE, &mib_value);
|
|
if (res)
|
|
return res;
|
|
|
|
res = snprintf(command, buf_len, "%s %d", CMD_GETSCANNPROBES, mib_value);
|
|
|
|
return res;
|
|
}
|
|
|
|
static int slsi_roam_mode_write(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int mib_value = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
if (slsi_is_rf_test_mode_enabled()) {
|
|
SLSI_DBG1_NODEV(SLSI_MLME, "SLSI_PSID_UNIFI_ROAM_MODE is not supported because of rf test mode.\n");
|
|
kfree(ioctl_args);
|
|
return -ENOTSUPP;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &mib_value)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
if (mib_value < 0 || mib_value > 2) {
|
|
SLSI_ERR(sdev, "Invalid roam mode value: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
kfree(ioctl_args);
|
|
return slsi_set_mib_roam(sdev, NULL, SLSI_PSID_UNIFI_ROAM_MODE, mib_value);
|
|
}
|
|
|
|
static int slsi_roam_mode_read(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int mib_value = 0;
|
|
int res;
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
res = slsi_get_mib_roam(sdev, SLSI_PSID_UNIFI_ROAM_MODE, &mib_value);
|
|
if (res)
|
|
return res;
|
|
|
|
res = snprintf(command, buf_len, "%s %d", CMD_GETROAMMODE, mib_value);
|
|
|
|
return res;
|
|
}
|
|
|
|
static int slsi_roam_offload_ap_list(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct cfg80211_acl_data *mac_acl;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int ap_count = 0;
|
|
int i, r;
|
|
int malloc_len;
|
|
|
|
slsi_convert_space_seperation(command, buf_len);
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 101);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
/* command format:
|
|
* x,aa:bb:cc:dd:ee:ff,xx:yy:zz:qq:ww:ee...
|
|
* x = 1 to 100
|
|
* each mac address id 17 bytes and every mac address is separated by ','
|
|
*/
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &ap_count)) {
|
|
SLSI_ERR(sdev, "Invalid ap_count string: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
if (ap_count < ROAMOFFLAPLIST_MIN || ap_count > ROAMOFFLAPLIST_MAX) {
|
|
SLSI_ERR(sdev, "Invalid ap_count: %d\n", ap_count);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
/* each mac address takes 18 bytes(17 for mac address and 1 for ',') except the last one.
|
|
* the last mac address is just 17 bytes(without a coma)
|
|
*/
|
|
if ((ioctl_args->arg_count - 1) < ap_count) {
|
|
SLSI_ERR(sdev, "Buffer doesn't have enough fields ap_count: %d\n", ap_count);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
malloc_len = sizeof(struct cfg80211_acl_data) + sizeof(struct mac_address) * ap_count;
|
|
mac_acl = kmalloc(malloc_len, GFP_KERNEL);
|
|
if (!mac_acl) {
|
|
SLSI_ERR(sdev, "MEM fail for size:%ld\n", sizeof(struct cfg80211_acl_data) + sizeof(struct mac_address) * ap_count);
|
|
kfree(ioctl_args);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
for (i = 1; i <= ap_count; i++) {
|
|
if (strlen(ioctl_args->args[i]) != 17) {
|
|
SLSI_ERR(sdev, "Invalid MAC address length :%d\n", (int)strlen(ioctl_args->args[i]));
|
|
kfree(ioctl_args);
|
|
kfree(mac_acl);
|
|
return -EINVAL;
|
|
}
|
|
slsi_machexstring_to_macarray(ioctl_args->args[i], mac_acl->mac_addrs[i].addr);
|
|
SLSI_DBG3_NODEV(SLSI_MLME, "[%pM]", mac_acl->mac_addrs[i].addr);
|
|
}
|
|
mac_acl->acl_policy = NL80211_ACL_POLICY_DENY_UNLESS_LISTED;
|
|
mac_acl->n_acl_entries = ap_count;
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
r = slsi_mlme_set_acl(sdev, dev, ndev_vif->ifnum, mac_acl->acl_policy, mac_acl->n_acl_entries, mac_acl->mac_addrs);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(mac_acl);
|
|
kfree(ioctl_args);
|
|
return r;
|
|
}
|
|
|
|
static int slsi_roam_scan_band_write(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int mib_value = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &mib_value)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
if (mib_value != 1 && mib_value != 2) {
|
|
SLSI_ERR(sdev, "Invalid roam scan band value: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
kfree(ioctl_args);
|
|
return slsi_set_mib_roam(sdev, NULL, SLSI_PSID_UNIFI_ROAM_SCAN_BAND, mib_value);
|
|
}
|
|
|
|
static int slsi_roam_scan_band_read(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int mib_value = 0;
|
|
int res;
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
res = slsi_get_mib_roam(sdev, SLSI_PSID_UNIFI_ROAM_SCAN_BAND, &mib_value);
|
|
if (res)
|
|
return res;
|
|
|
|
res = snprintf(command, buf_len, "%s %d", CMD_GETROAMINTRABAND, mib_value);
|
|
|
|
return res;
|
|
}
|
|
|
|
static int slsi_roam_scan_control_write(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int mode = 0;
|
|
int res = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
res = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &mode)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
res = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
if (mode == 0 || mode == 1) {
|
|
sdev->device_config.roam_scan_mode = mode;
|
|
} else {
|
|
SLSI_ERR(sdev, "Invalid roam Mode: Must be 0 or, 1 Not '%d'\n", mode);
|
|
res = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
res = slsi_set_mib_roam(sdev, NULL, SLSI_PSID_UNIFI_ROAM_NCHO_SCAN_CONTROL, sdev->device_config.roam_scan_mode);
|
|
if (res)
|
|
goto exit;
|
|
|
|
/* If the mode is 0, Clear the roam cache */
|
|
if (!mode) {
|
|
memset(&sdev->device_config.wes_roam_scan_list, 0, sizeof(struct slsi_roam_scan_channels));
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
res = slsi_mlme_set_cached_channels(sdev, dev, 0, NULL);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return res;
|
|
}
|
|
|
|
exit:
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return res;
|
|
}
|
|
|
|
static int slsi_roam_scan_control_read(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int mib_value = 0;
|
|
int res;
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
res = slsi_get_mib_roam(sdev, SLSI_PSID_UNIFI_ROAM_NCHO_SCAN_CONTROL, &mib_value);
|
|
if (res)
|
|
return res;
|
|
|
|
res = snprintf(command, buf_len, "%s %d", CMD_GETROAMSCANCONTROL, mib_value);
|
|
|
|
return res;
|
|
}
|
|
|
|
static int slsi_roam_scan_home_time_write(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int mib_value = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &mib_value)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
if (mib_value > 300 || mib_value < 3) {
|
|
SLSI_ERR(sdev, "Invalid scan home time: '%d'\n", mib_value);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
kfree(ioctl_args);
|
|
return slsi_set_mib_roam(sdev, NULL, SLSI_PSID_UNIFI_ROAM_NCHO_SCAN_HOME_TIME, mib_value);
|
|
}
|
|
|
|
static int slsi_roam_scan_home_time_read(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int mib_value = 0;
|
|
int res;
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
res = slsi_get_mib_roam(sdev, SLSI_PSID_UNIFI_ROAM_NCHO_SCAN_HOME_TIME, &mib_value);
|
|
if (res)
|
|
return res;
|
|
|
|
res = snprintf(command, buf_len, "%s %d", CMD_GETSCANHOMETIME, mib_value);
|
|
|
|
return res;
|
|
}
|
|
|
|
static int slsi_roam_scan_home_away_time_write(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int mib_value = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &mib_value)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
if (mib_value > 300 || mib_value < 3) {
|
|
SLSI_ERR(sdev, "Invalid scan home away time: '%d'\n", mib_value);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
kfree(ioctl_args);
|
|
return slsi_set_mib_roam(sdev, NULL, SLSI_PSID_UNIFI_ROAM_NCHO_SCAN_HOME_AWAY_TIME, mib_value);
|
|
}
|
|
|
|
static int slsi_roam_scan_home_away_time_read(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int mib_value = 0;
|
|
int res;
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
res = slsi_get_mib_roam(sdev, SLSI_PSID_UNIFI_ROAM_NCHO_SCAN_HOME_AWAY_TIME, &mib_value);
|
|
if (res)
|
|
return res;
|
|
|
|
res = snprintf(command, buf_len, "%s %d", CMD_GETSCANHOMEAWAYTIME, mib_value);
|
|
|
|
return res;
|
|
}
|
|
|
|
static ssize_t slsi_validate_low_latency_params(struct net_device *dev, char *command, int buf_len, int *latency_param)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int ret = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], latency_param)) {
|
|
SLSI_ERR(sdev, "Invalid string latency_param: '%s'\n", ioctl_args->args[0]);
|
|
ret = -EINVAL;
|
|
} else if (*latency_param < 0 || *latency_param > 0xFFFF) {
|
|
SLSI_ERR(sdev, "Invalid latency_param value: '%d'\n", *latency_param);
|
|
ret = -EINVAL;
|
|
}
|
|
|
|
kfree(ioctl_args);
|
|
return ret;
|
|
}
|
|
|
|
static ssize_t slsi_set_low_latency_params(struct net_device *dev, int latency_param)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int ret = 0;
|
|
|
|
if ((sdev->latency_param_mask & LATENCY_ALL_SET_MASK) == LATENCY_ALL_SET_MASK) {
|
|
SLSI_INFO(sdev, "Home Away Time = %d, Home time = %d, Max Channel Time = %d Passive Time = %d\n",
|
|
sdev->home_away_time, sdev->home_time, sdev->max_channel_time,
|
|
sdev->max_channel_passive_time);
|
|
ret = slsi_mlme_set_scan_mode_req(sdev, dev, FAPI_SCANMODE_LOW_LATENCY, sdev->max_channel_time,
|
|
sdev->home_away_time, sdev->home_time, sdev->max_channel_passive_time);
|
|
sdev->latency_param_mask = 0;
|
|
} else if (latency_param == 0) {
|
|
ret = slsi_mlme_set_scan_mode_req(sdev, dev, FAPI_SCANMODE_LEGACY, 0, 0, 0, 0);
|
|
sdev->latency_param_mask = 0;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int slsi_set_home_away_time_legacy(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int home_away_time = 0;
|
|
int ret = 0;
|
|
|
|
ret = slsi_validate_low_latency_params(dev, command, buf_len, &home_away_time);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
sdev->home_away_time = home_away_time;
|
|
if (home_away_time != 0)
|
|
sdev->latency_param_mask |= HOME_AWAY_TIME_BIT;
|
|
ret = slsi_set_low_latency_params(dev, home_away_time);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int slsi_set_home_time_legacy(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int home_time = 0;
|
|
int ret = 0;
|
|
|
|
ret = slsi_validate_low_latency_params(dev, command, buf_len, &home_time);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
sdev->home_time = home_time;
|
|
if (home_time != 0)
|
|
sdev->latency_param_mask |= HOME_TIME_BIT;
|
|
ret = slsi_set_low_latency_params(dev, home_time);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return ret;
|
|
}
|
|
|
|
static int slsi_set_channel_time_legacy(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int max_channel_time = 0;
|
|
int ret = 0;
|
|
|
|
ret = slsi_validate_low_latency_params(dev, command, buf_len, &max_channel_time);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
sdev->max_channel_time = max_channel_time;
|
|
if (max_channel_time != 0)
|
|
sdev->latency_param_mask |= MAX_CHANNEL_TIME_BIT;
|
|
ret = slsi_set_low_latency_params(dev, max_channel_time);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int slsi_set_passive_time_legacy(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int max_channel_passive_time = 0;
|
|
int ret = 0;
|
|
|
|
ret = slsi_validate_low_latency_params(dev, command, buf_len, &max_channel_passive_time);
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
sdev->max_channel_passive_time = max_channel_passive_time;
|
|
if (max_channel_passive_time != 0)
|
|
sdev->latency_param_mask |= MAX_CHANNEL_PASSIVE_TIME_BIT;
|
|
ret = slsi_set_low_latency_params(dev, max_channel_passive_time);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int slsi_set_tid(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int mode = 0, uid = 0, tid = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 3);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &mode)) {
|
|
SLSI_ERR(sdev, "Invalid string mode : '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
if (mode < 0 || mode > 3) {
|
|
SLSI_ERR(sdev, "Invalid mode: '%d'\n", mode);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
if (!slsi_str_to_int(ioctl_args->args[1], &uid)) {
|
|
SLSI_ERR(sdev, "Invalid string uid: '%s'\n", ioctl_args->args[1]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
if (!slsi_str_to_int(ioctl_args->args[2], &tid)) {
|
|
SLSI_ERR(sdev, "Invalid string tid: '%s'\n", ioctl_args->args[2]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
kfree(ioctl_args);
|
|
return slsi_netif_set_tid_config(sdev, dev, mode, uid, tid);
|
|
}
|
|
|
|
static int slsi_roam_scan_frequencies_write(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int result = 0;
|
|
int i = 0;
|
|
int channels[SLSI_NCHO_MAX_CHANNEL_LIST] = { 0 };
|
|
int ret = 0;
|
|
int freq_count = 0;
|
|
int freqs[SLSI_NCHO_MAX_FREQUENCY_LIST] = { 0 };
|
|
const u8 *connected_ssid = NULL;
|
|
u32 network_map_channels_count = 0;
|
|
u8 network_map_channels[SLSI_ROAMING_CHANNELS_MAX];
|
|
u8 merged_channels[SLSI_ROAMING_CHANNELS_MAX * 2];
|
|
u32 merge_chan_count = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 21);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &freq_count)) {
|
|
SLSI_ERR(sdev, "Invalid freq_count string: '%s'\n", ioctl_args->args[0]);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
if (freq_count < 0) {
|
|
SLSI_ERR(sdev, "Invalid frequency count : %d\n", freq_count);
|
|
kfree(ioctl_args);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return -EINVAL;
|
|
}
|
|
if (freq_count > SLSI_NCHO_MAX_FREQUENCY_LIST)
|
|
freq_count = SLSI_NCHO_MAX_FREQUENCY_LIST;
|
|
|
|
if ((ioctl_args->arg_count - 1) < freq_count) {
|
|
SLSI_ERR(sdev, "Buffer doesn't have enough fields freq_count: %d\n", freq_count);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
sdev->device_config.wes_roam_scan_list.n = freq_count;
|
|
|
|
for (i = 0; i < freq_count; i++) {
|
|
if (!slsi_str_to_int(ioctl_args->args[i + 1], &freqs[i])) {
|
|
SLSI_ERR(sdev, "failed to read a numeric value\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
channels[i] = ieee80211_frequency_to_channel(freqs[i]);
|
|
|
|
if (channels[i] < 1 || channels[i] > 165) {
|
|
SLSI_ERR(sdev, "Invalid channel : %d\n", channels[i]);
|
|
kfree(ioctl_args);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return -EINVAL;
|
|
}
|
|
sdev->device_config.wes_roam_scan_list.channels[i] = channels[i];
|
|
}
|
|
|
|
if (!sdev->device_config.roam_scan_mode) {
|
|
ret = slsi_set_mib_roam(sdev, NULL, SLSI_PSID_UNIFI_ROAM_NCHO_SCAN_CONTROL, 1);
|
|
if (ret != SLSI_MIB_STATUS_SUCCESS) {
|
|
kfree(ioctl_args);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return -EINVAL;
|
|
}
|
|
sdev->device_config.roam_scan_mode = 1;
|
|
}
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
connected_ssid = cfg80211_find_ie(WLAN_EID_SSID, ndev_vif->sta.sta_bss->ies->data,
|
|
ndev_vif->sta.sta_bss->ies->len);
|
|
|
|
network_map_channels_count = slsi_roaming_scan_configure_channels(sdev, dev, connected_ssid,
|
|
network_map_channels);
|
|
merge_chan_count = slsi_merge_lists(network_map_channels, network_map_channels_count,
|
|
sdev->device_config.wes_roam_scan_list.channels,
|
|
sdev->device_config.wes_roam_scan_list.n,
|
|
merged_channels);
|
|
|
|
result = slsi_mlme_set_cached_channels(sdev, dev, merge_chan_count, merged_channels);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
kfree(ioctl_args);
|
|
return result;
|
|
}
|
|
|
|
static int slsi_roam_scan_channels_write(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int result = 0;
|
|
int i, channel_count = 0;
|
|
int channels[SLSI_NCHO_MAX_CHANNEL_LIST];
|
|
int ret = 0;
|
|
const u8 *connected_ssid = NULL;
|
|
u32 network_map_channels_count = 0;
|
|
u8 network_map_channels[SLSI_ROAMING_CHANNELS_MAX];
|
|
u8 merged_channels[SLSI_ROAMING_CHANNELS_MAX * 2];
|
|
u32 merge_chan_count = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 21);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &channel_count)) {
|
|
SLSI_ERR(sdev, "Invalid channel_count string: '%s'\n", ioctl_args->args[0]);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
if (channel_count < 0) {
|
|
SLSI_ERR(sdev, "Invalid channel count : %d\n", channel_count);
|
|
kfree(ioctl_args);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return -EINVAL;
|
|
}
|
|
if (channel_count > SLSI_NCHO_MAX_CHANNEL_LIST)
|
|
channel_count = SLSI_NCHO_MAX_CHANNEL_LIST;
|
|
|
|
if ((ioctl_args->arg_count - 1) < channel_count) {
|
|
SLSI_ERR(sdev, "Buffer doesn't have enough fields channel_count: %d\n", channel_count);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
sdev->device_config.wes_roam_scan_list.n = channel_count;
|
|
|
|
for (i = 0; i < channel_count; i++) {
|
|
if (!slsi_str_to_int(ioctl_args->args[i + 1], &channels[i])) {
|
|
SLSI_ERR(sdev, "failed to read a numeric value\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
if (channels[i] < 1 || channels[i] > 165) {
|
|
SLSI_ERR(sdev, "Invalid channel : %d\n", channels[i]);
|
|
kfree(ioctl_args);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return -EINVAL;
|
|
}
|
|
sdev->device_config.wes_roam_scan_list.channels[i] = channels[i];
|
|
}
|
|
|
|
if (!sdev->device_config.roam_scan_mode) {
|
|
ret = slsi_set_mib_roam(sdev, NULL, SLSI_PSID_UNIFI_ROAM_NCHO_SCAN_CONTROL, 1);
|
|
if (ret != SLSI_MIB_STATUS_SUCCESS) {
|
|
kfree(ioctl_args);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return -EINVAL;
|
|
}
|
|
sdev->device_config.roam_scan_mode = 1;
|
|
}
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
connected_ssid = cfg80211_find_ie(WLAN_EID_SSID, ndev_vif->sta.sta_bss->ies->data,
|
|
ndev_vif->sta.sta_bss->ies->len);
|
|
|
|
network_map_channels_count = slsi_roaming_scan_configure_channels(sdev, dev, connected_ssid,
|
|
network_map_channels);
|
|
merge_chan_count = slsi_merge_lists(network_map_channels, network_map_channels_count,
|
|
sdev->device_config.wes_roam_scan_list.channels,
|
|
sdev->device_config.wes_roam_scan_list.n,
|
|
merged_channels);
|
|
|
|
result = slsi_mlme_set_cached_channels(sdev, dev, merge_chan_count, merged_channels);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
kfree(ioctl_args);
|
|
return result;
|
|
}
|
|
|
|
static int slsi_roam_scan_frequencies_read(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct sk_buff *ind = NULL;
|
|
int freq_list[MAX_FREQUENCY_COUNT] = {0};
|
|
int pos = 0;
|
|
int i;
|
|
int freq_count = 0;
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
|
|
if (ndev_vif->sta.vif_status != SLSI_VIF_STATUS_CONNECTED) {
|
|
SLSI_NET_ERR(dev, "STA is not in connected state\n");
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
freq_count = 0;
|
|
goto output;
|
|
}
|
|
|
|
ind = slsi_mlme_roaming_channel_list_req(sdev, dev);
|
|
if (!ind) {
|
|
SLSI_ERR(sdev, "RCL ind is NULL!\n");
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return -EINVAL;
|
|
}
|
|
|
|
freq_count = slsi_get_rcl_freq_list(sdev, ind, freq_list);
|
|
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
if (!freq_count) {
|
|
SLSI_ERR(sdev, "Frequency count is 0!\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
output:
|
|
pos = scnprintf(command, buf_len, "%s %d", CMD_GETROAMSCANFREQUENCIES, freq_count);
|
|
for (i = 0; i < freq_count; i++)
|
|
pos += scnprintf(command + pos, buf_len - pos, " %d", freq_list[i]);
|
|
|
|
return pos;
|
|
}
|
|
|
|
static int slsi_roam_scan_channels_read(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct sk_buff *ind = NULL;
|
|
u16 channel_list[MAX_CHANNEL_COUNT] = {0};
|
|
int pos = 0;
|
|
int i;
|
|
int channel_count = 0;
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
ind = slsi_mlme_roaming_channel_list_req(sdev, dev);
|
|
if (!ind) {
|
|
SLSI_ERR(sdev, "RCL ind is NULL!\n");
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return -EINVAL;
|
|
}
|
|
|
|
channel_count = slsi_get_rcl_channel_list(sdev, ind, channel_list);
|
|
if (!channel_count) {
|
|
SLSI_ERR(sdev, "Channel count is 0!\n");
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return -EINVAL;
|
|
}
|
|
pos = scnprintf(command, buf_len, "%s %d", CMD_GETROAMSCANCHANNELS, channel_count);
|
|
for (i = 0; i < channel_count; i++)
|
|
pos += scnprintf(command + pos, buf_len - pos, " %d", channel_list[i]);
|
|
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return pos;
|
|
}
|
|
|
|
static int slsi_roam_add_scan_frequencies(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int result = 0;
|
|
int i, j;
|
|
int new_channels[SLSI_NCHO_MAX_CHANNEL_LIST] = { 0 };
|
|
int curr_channel_count = 0;
|
|
int found = 0;
|
|
int new_freq_count = 0;
|
|
int new_freqs[SLSI_NCHO_MAX_FREQUENCY_LIST] = { 0 };
|
|
const u8 *connected_ssid = NULL;
|
|
u32 network_map_channels_count = 0;
|
|
u8 network_map_channels[SLSI_ROAMING_CHANNELS_MAX];
|
|
u8 merged_channels[SLSI_ROAMING_CHANNELS_MAX * 2];
|
|
u32 merge_chan_count = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 21);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (sdev->device_config.wes_roam_scan_list.n == SLSI_NCHO_MAX_CHANNEL_LIST) {
|
|
SLSI_ERR(sdev, "Roam scan list is already full\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
if (ndev_vif->vif_type == FAPI_VIFTYPE_STATION && ndev_vif->sta.vif_status ==
|
|
SLSI_VIF_STATUS_CONNECTED && sdev->device_config.wes_roam_scan_list.n == 0) {
|
|
sdev->device_config.wes_roam_scan_list.n = 1;
|
|
sdev->device_config.wes_roam_scan_list.channels[0] = ndev_vif->chan->hw_value;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &new_freq_count)) {
|
|
SLSI_ERR(sdev, "Invalid freq_count string: '%s'\n", ioctl_args->args[0]);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
if (new_freq_count < 0 || new_freq_count > 20 || ((ioctl_args->arg_count - 1) < new_freq_count)) {
|
|
SLSI_ERR(sdev, "Invalid frequency count : %d Range: [0,20]\n", new_freq_count);
|
|
kfree(ioctl_args);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return -EINVAL;
|
|
}
|
|
|
|
curr_channel_count = sdev->device_config.wes_roam_scan_list.n;
|
|
|
|
for (i = 0; i < new_freq_count; i++) {
|
|
if (!slsi_str_to_int(ioctl_args->args[i + 1], &new_freqs[i])) {
|
|
SLSI_ERR(sdev, "failed to read a numeric value\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
new_channels[i] = ieee80211_frequency_to_channel(new_freqs[i]);
|
|
|
|
if (new_channels[i] < 1 || new_channels[i] > 165) {
|
|
SLSI_ERR(sdev, "Invalid channel : %d\n", new_channels[i]);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
for (j = 0; j < curr_channel_count; j++) {
|
|
found = 0;
|
|
if (sdev->device_config.wes_roam_scan_list.channels[j] == new_channels[i]) {
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
sdev->device_config.wes_roam_scan_list.channels[curr_channel_count] = new_channels[i];
|
|
curr_channel_count++;
|
|
}
|
|
if (curr_channel_count >= SLSI_NCHO_MAX_CHANNEL_LIST) {
|
|
curr_channel_count = SLSI_NCHO_MAX_CHANNEL_LIST;
|
|
break;
|
|
}
|
|
}
|
|
|
|
sdev->device_config.wes_roam_scan_list.n = curr_channel_count;
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
connected_ssid = cfg80211_find_ie(WLAN_EID_SSID, ndev_vif->sta.sta_bss->ies->data,
|
|
ndev_vif->sta.sta_bss->ies->len);
|
|
|
|
network_map_channels_count = slsi_roaming_scan_configure_channels(sdev, dev, connected_ssid,
|
|
network_map_channels);
|
|
merge_chan_count = slsi_merge_lists(network_map_channels, network_map_channels_count,
|
|
sdev->device_config.wes_roam_scan_list.channels,
|
|
sdev->device_config.wes_roam_scan_list.n,
|
|
merged_channels);
|
|
|
|
result = slsi_mlme_set_cached_channels(sdev, dev, merge_chan_count, merged_channels);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
kfree(ioctl_args);
|
|
return result;
|
|
}
|
|
|
|
static int slsi_roam_add_scan_channels(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int result = 0;
|
|
int i, j, new_channel_count = 0;
|
|
int new_channels[SLSI_NCHO_MAX_CHANNEL_LIST];
|
|
int curr_channel_count = 0;
|
|
int found = 0;
|
|
const u8 *connected_ssid = NULL;
|
|
u32 network_map_channels_count = 0;
|
|
u8 network_map_channels[SLSI_ROAMING_CHANNELS_MAX];
|
|
u8 merged_channels[SLSI_ROAMING_CHANNELS_MAX * 2];
|
|
u32 merge_chan_count = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 21);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (sdev->device_config.roam_scan_mode) {
|
|
SLSI_ERR(sdev, "ROAM Scan Control must be 0, roam mode = %d\n", sdev->device_config.roam_scan_mode);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (sdev->device_config.wes_roam_scan_list.n == SLSI_NCHO_MAX_CHANNEL_LIST) {
|
|
SLSI_ERR(sdev, "Roam scan list is already full\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Adding Connected channel to wes_roam_scan_list */
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
if (ndev_vif->vif_type == FAPI_VIFTYPE_STATION && ndev_vif->sta.vif_status == SLSI_VIF_STATUS_CONNECTED &&
|
|
sdev->device_config.wes_roam_scan_list.n == 0 && ndev_vif->chan) {
|
|
sdev->device_config.wes_roam_scan_list.n = 1;
|
|
sdev->device_config.wes_roam_scan_list.channels[0] = ndev_vif->chan->hw_value;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &new_channel_count)) {
|
|
SLSI_ERR(sdev, "Invalid channel_count string: '%s'\n", ioctl_args->args[0]);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
if (new_channel_count < 0 || new_channel_count > 20) {
|
|
SLSI_ERR(sdev, "Invalid channel count : %d Range: [0,20]\n", new_channel_count);
|
|
kfree(ioctl_args);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if ((ioctl_args->arg_count - 1) < new_channel_count) {
|
|
SLSI_ERR(sdev, "Buffer doesn't have enough fields channel_count: %d\n", new_channel_count);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
curr_channel_count = sdev->device_config.wes_roam_scan_list.n;
|
|
|
|
for (i = 0; i < new_channel_count; i++) {
|
|
if (!slsi_str_to_int(ioctl_args->args[i + 1], &new_channels[i])) {
|
|
SLSI_ERR(sdev, "failed to read a numeric value\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
if (new_channels[i] < 1 || new_channels[i] > 165) {
|
|
SLSI_ERR(sdev, "Invalid channel : %d\n", new_channels[i]);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
for (j = 0; j < curr_channel_count; j++) {
|
|
found = 0;
|
|
if (sdev->device_config.wes_roam_scan_list.channels[j] == new_channels[i]) {
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
sdev->device_config.wes_roam_scan_list.channels[curr_channel_count] = new_channels[i];
|
|
curr_channel_count++;
|
|
}
|
|
if (curr_channel_count >= SLSI_NCHO_MAX_CHANNEL_LIST) {
|
|
curr_channel_count = SLSI_NCHO_MAX_CHANNEL_LIST;
|
|
break;
|
|
}
|
|
}
|
|
|
|
sdev->device_config.wes_roam_scan_list.n = curr_channel_count;
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
connected_ssid = cfg80211_find_ie(WLAN_EID_SSID, ndev_vif->sta.sta_bss->ies->data,
|
|
ndev_vif->sta.sta_bss->ies->len);
|
|
|
|
network_map_channels_count = slsi_roaming_scan_configure_channels(sdev, dev, connected_ssid,
|
|
network_map_channels);
|
|
merge_chan_count = slsi_merge_lists(network_map_channels, network_map_channels_count,
|
|
sdev->device_config.wes_roam_scan_list.channels,
|
|
sdev->device_config.wes_roam_scan_list.n,
|
|
merged_channels);
|
|
|
|
result = slsi_mlme_set_cached_channels(sdev, dev, merge_chan_count, merged_channels);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
kfree(ioctl_args);
|
|
return result;
|
|
}
|
|
|
|
static int slsi_okc_mode_write(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int mode = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &mode)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (mode == 0 || mode == 1) {
|
|
sdev->device_config.okc_mode = mode;
|
|
} else {
|
|
SLSI_ERR(sdev, "Invalid OKC Mode: Must be 0 or, 1 Not '%d'\n", mode);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
kfree(ioctl_args);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return 0;
|
|
}
|
|
|
|
static int slsi_okc_mode_read(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int okc_mode;
|
|
int res;
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return -EINVAL;
|
|
}
|
|
|
|
okc_mode = sdev->device_config.okc_mode;
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
res = snprintf(command, buf_len, "%s %d", CMD_GETOKCMODE, okc_mode);
|
|
|
|
return res;
|
|
}
|
|
|
|
static int slsi_wes_mode_write(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int result = -EINVAL;
|
|
u32 action_frame_bmap = SLSI_STA_ACTION_FRAME_BITMAP;
|
|
int mode = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
goto exit;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &mode)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
goto exit;
|
|
}
|
|
|
|
if (mode == 0 || mode == 1) {
|
|
sdev->device_config.wes_mode = mode;
|
|
} else {
|
|
SLSI_ERR(sdev, "Invalid WES Mode: Must be 0 or 1 Not '%d'\n", mode);
|
|
goto exit;
|
|
}
|
|
|
|
result = 0;
|
|
if (ndev_vif->activated && ndev_vif->vif_type == FAPI_VIFTYPE_STATION &&
|
|
ndev_vif->sta.vif_status == SLSI_VIF_STATUS_CONNECTED) {
|
|
if (sdev->device_config.wes_mode)
|
|
action_frame_bmap |= SLSI_ACTION_FRAME_VENDOR_SPEC;
|
|
|
|
result = slsi_mlme_register_action_frame(sdev, dev, action_frame_bmap, action_frame_bmap);
|
|
}
|
|
exit:
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return result;
|
|
}
|
|
|
|
static int slsi_wes_mode_read(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int wes_mode;
|
|
int res;
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return -EINVAL;
|
|
}
|
|
|
|
wes_mode = sdev->device_config.wes_mode;
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
res = snprintf(command, buf_len, "%s %d", CMD_GETWESMODE, wes_mode);
|
|
|
|
return res;
|
|
}
|
|
|
|
static int slsi_set_ncho_mode(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
struct sk_buff *req;
|
|
struct sk_buff *cfm;
|
|
int ret = 0;
|
|
int mode = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &mode)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (mode != 0 && mode != 1) {
|
|
SLSI_ERR(sdev, "Invalid NCHO Mode: Must be 0 or 1, mode = %d\n", mode);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
|
|
if (sdev->device_config.ncho_mode == mode) {
|
|
SLSI_INFO(sdev, "ncho_mode is already %d\n", mode);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return ret;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
|
|
if (ndev_vif->sta.vif_status != SLSI_VIF_STATUS_CONNECTED) {
|
|
SLSI_NET_ERR(dev, "sta is not in connected state\n");
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return -EPERM;
|
|
}
|
|
|
|
SLSI_DBG1_NODEV(SLSI_MLME, "mlme_set_roaming_type_req(vif:%u mode:%u)\n", ndev_vif->ifnum, mode);
|
|
|
|
req = fapi_alloc(mlme_set_roaming_type_req, MLME_SET_ROAMING_TYPE_REQ, ndev_vif->ifnum, 0);
|
|
if (!req) {
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return -EIO;
|
|
}
|
|
fapi_set_u16(req, u.mlme_set_roaming_type_req.vif, ndev_vif->ifnum);
|
|
fapi_set_u16(req, u.mlme_set_roaming_type_req.roaming_type, mode);
|
|
cfm = slsi_mlme_req_cfm(sdev, dev, req, MLME_SET_ROAMING_TYPE_CFM);
|
|
if (!cfm) {
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return -EIO;
|
|
}
|
|
|
|
if (fapi_get_u16(cfm, u.mlme_set_roaming_type_cfm.result_code) != FAPI_RESULTCODE_SUCCESS) {
|
|
SLSI_NET_ERR(dev, "mlme_set_roaming_type_cfm(result:0x%04x) ERROR\n",
|
|
fapi_get_u16(cfm, u.mlme_set_roaming_type_cfm.result_code));
|
|
ret = -EINVAL;
|
|
}
|
|
|
|
kfree_skb(cfm);
|
|
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
slsi_conn_log2us_ncho_mode(sdev, dev, mode);
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
sdev->device_config.ncho_mode = mode;
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
kfree(ioctl_args);
|
|
return ret;
|
|
}
|
|
|
|
static int slsi_get_ncho_mode(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int ret;
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
ret = snprintf(command, buf_len, "%s %d", CMD_GETNCHOMODE, sdev->device_config.ncho_mode);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int slsi_set_dfs_scan_mode(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int mode = 0;
|
|
int res;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &mode)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (mode >= 0 && mode <= 2) {
|
|
sdev->device_config.dfs_scan_mode = mode;
|
|
} else {
|
|
SLSI_ERR(sdev, "Invalid dfs scan mode: Must be 0/1 or 2, Not '%d'\n", mode);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
kfree(ioctl_args);
|
|
res = slsi_set_mib_roam(sdev, NULL, SLSI_PSID_UNIFI_ROAM_NCHO_DFS_SCAN_MODE, sdev->device_config.dfs_scan_mode);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return res;
|
|
}
|
|
|
|
static int slsi_get_dfs_scan_mode(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int mib_value = 0;
|
|
int res;
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.ncho_mode) {
|
|
SLSI_INFO(sdev, "Command not allowed, NCHO is disabled\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
res = slsi_get_mib_roam(sdev, SLSI_PSID_UNIFI_ROAM_NCHO_DFS_SCAN_MODE, &mib_value);
|
|
if (res)
|
|
return res;
|
|
|
|
res = snprintf(command, buf_len, "%s %d", CMD_GETDFSSCANMODE, mib_value);
|
|
|
|
return res;
|
|
}
|
|
|
|
#endif
|
|
|
|
static int slsi_set_pmk(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
u8 pmk[33] = {0};
|
|
int result = 0;
|
|
struct key_params params;
|
|
u8 mac_addr[ETH_ALEN] = {0};
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (strlen(ioctl_args->args[0]) < 32) {
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
memcpy((u8 *)pmk, ioctl_args->args[0], 32);
|
|
memset(mac_addr, 0x00, ETH_ALEN);
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
memset(¶ms, 0, sizeof(params));
|
|
params.key = pmk;
|
|
params.key_len = 32;
|
|
params.cipher = WLAN_CIPHER_SUITE_PMK;
|
|
result = slsi_mlme_set_key(sdev, dev, 0, FAPI_KEYTYPE_PMK, mac_addr, ¶ms);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return result;
|
|
}
|
|
|
|
static int slsi_auto_chan_read(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int ap_auto_chan;
|
|
int result = 0;
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
ap_auto_chan = sdev->device_config.ap_auto_chan;
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
result = snprintf(command, buf_len, "%d\n", ap_auto_chan);
|
|
return result;
|
|
}
|
|
|
|
static ssize_t slsi_auto_chan_write(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int n_channels = 0;
|
|
struct ieee80211_channel *channels[SLSI_NO_OF_SCAN_CHANLS_FOR_AUTO_CHAN_MAX] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
|
|
int count_channels;
|
|
int chan;
|
|
#ifdef CONFIG_SCSC_WLAN_WIFI_SHARING
|
|
struct net_device *sta_dev = slsi_get_netdev(sdev, SLSI_NET_INDEX_WLAN);
|
|
struct netdev_vif *ndev_sta_vif = netdev_priv(sta_dev);
|
|
int sta_frequency;
|
|
#endif
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &n_channels)) {
|
|
SLSI_ERR(sdev, "channel count: failed to read a numeric value");
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (n_channels < 1 || n_channels > SLSI_NO_OF_SCAN_CHANLS_FOR_AUTO_CHAN_MAX) {
|
|
SLSI_ERR(sdev, "Invalid channel count:%d", n_channels);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* If "1 6 11" are passed, scan all "1 - 14" channels. If "1 6" are passed, scan "1 - 9" channels */
|
|
if (n_channels == 3)
|
|
n_channels = 14;
|
|
else if (n_channels == 2)
|
|
n_channels = 9;
|
|
count_channels = 0;
|
|
for (chan = 1; chan <= n_channels; chan++) {
|
|
int center_freq;
|
|
|
|
center_freq = ieee80211_channel_to_frequency(chan, NL80211_BAND_2GHZ);
|
|
channels[count_channels] = ieee80211_get_channel(sdev->wiphy, center_freq);
|
|
if (!channels[count_channels])
|
|
SLSI_WARN(sdev, "channel number:%d invalid\n", chan);
|
|
else
|
|
count_channels++;
|
|
}
|
|
|
|
SLSI_DBG3(sdev, SLSI_INIT_DEINIT, "Number of channels for autochannel selection= %d\n", count_channels);
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
sdev->device_config.ap_auto_chan = 0;
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
#ifdef CONFIG_SCSC_WLAN_WIFI_SHARING
|
|
if (ndev_sta_vif->activated && ndev_sta_vif->vif_type == FAPI_VIFTYPE_STATION &&
|
|
(ndev_sta_vif->sta.vif_status == SLSI_VIF_STATUS_CONNECTING ||
|
|
ndev_sta_vif->sta.vif_status == SLSI_VIF_STATUS_CONNECTED)) {
|
|
sta_frequency = ndev_sta_vif->chan->center_freq;
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if ((sta_frequency / 1000) == 2)
|
|
sdev->device_config.ap_auto_chan = ieee80211_frequency_to_channel(sta_frequency);
|
|
else
|
|
sdev->device_config.ap_auto_chan = 1;
|
|
SLSI_INFO(sdev, "Channel selected = %d", sdev->device_config.ap_auto_chan);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return 0;
|
|
}
|
|
#endif /*wifi sharing*/
|
|
kfree(ioctl_args);
|
|
return slsi_auto_chan_select_scan(sdev, count_channels, channels);
|
|
}
|
|
|
|
static int slsi_send_action_frame(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
char *temp;
|
|
u8 bssid[6] = { 0 };
|
|
int channel = 0;
|
|
int freq = 0;
|
|
enum nl80211_band band = NL80211_BAND_2GHZ;
|
|
int r = 0;
|
|
u16 host_tag = slsi_tx_mgmt_host_tag(sdev);
|
|
u32 dwell_time;
|
|
struct ieee80211_hdr *hdr;
|
|
u8 *buf = NULL;
|
|
u8 *final_buf = NULL;
|
|
u8 temp_byte;
|
|
int len = 0;
|
|
int final_length = 0;
|
|
int i = 0, j = 0;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
if (!ndev_vif->activated || ndev_vif->vif_type != FAPI_VIFTYPE_STATION ||
|
|
ndev_vif->sta.vif_status != SLSI_VIF_STATUS_CONNECTED) {
|
|
SLSI_ERR(sdev, "Not a STA vif or status is not CONNECTED\n");
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 5);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (ioctl_args->arg_count < 5) {
|
|
SLSI_ERR(sdev, "Invalid argument count = %d\n", ioctl_args->arg_count);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (strlen(ioctl_args->args[0]) != 17) {
|
|
SLSI_ERR(sdev, "Invalid mac address: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
slsi_machexstring_to_macarray(ioctl_args->args[0], bssid);
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
if (!SLSI_ETHER_EQUAL(bssid, ndev_vif->sta.bssid)) {
|
|
SLSI_ERR(sdev, "Wrong Bssid = " MACSTR " Connected Bssid = " MACSTR "\n", MAC2STR(bssid), MAC2STR(ndev_vif->sta.bssid));
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[1], &channel)) {
|
|
SLSI_ERR(sdev, "Invalid channel string: '%s'\n", ioctl_args->args[1]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (channel < 1 || channel > 165) {
|
|
SLSI_ERR(sdev, "Invalid channel : %d\n", channel);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (channel > 14)
|
|
band = NL80211_BAND_5GHZ;
|
|
freq = (u16)ieee80211_channel_to_frequency(channel, band);
|
|
if (!freq) {
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[2], &dwell_time)) {
|
|
SLSI_ERR(sdev, "Invalid dwell time string: '%s'\n", ioctl_args->args[2]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[3], &len)) {
|
|
SLSI_ERR(sdev, "Invalid length string: '%s'\n", ioctl_args->args[3]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* if length is less than 512 or greater than 1024 driver will ignore the command */
|
|
if (len < 512 || len > 1024) {
|
|
if (len < 0 || len > 1024) {
|
|
SLSI_ERR(sdev, "Invalid buffer length:%d\n", len);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_INFO(sdev, "Frame Body of Vendor Specific buffer length = %d so ignoring the command\n", len);
|
|
kfree(ioctl_args);
|
|
return 0;
|
|
}
|
|
|
|
buf = kmalloc((len + 1) / 2, GFP_KERNEL);
|
|
|
|
if (!buf) {
|
|
SLSI_ERR(sdev, "Malloc failed\n");
|
|
kfree(ioctl_args);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/*We receive a char buffer, convert to hex*/
|
|
temp = ioctl_args->args[4];
|
|
for (i = 0, j = 0; j < len; j += 2) {
|
|
if (j + 1 == len)
|
|
temp_byte = slsi_parse_hex(temp[j]);
|
|
else
|
|
temp_byte = slsi_parse_hex(temp[j]) << 4 | slsi_parse_hex(temp[j + 1]);
|
|
buf[i++] = temp_byte;
|
|
}
|
|
len = i;
|
|
|
|
final_length = len + IEEE80211_HEADER_SIZE;
|
|
final_buf = kmalloc(final_length, GFP_KERNEL);
|
|
if (!final_buf) {
|
|
SLSI_ERR(sdev, "Malloc failed\n");
|
|
kfree(ioctl_args);
|
|
kfree(buf);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
hdr = (struct ieee80211_hdr *)final_buf;
|
|
hdr->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, IEEE80211_STYPE_ACTION);
|
|
SLSI_ETHER_COPY(hdr->addr1, bssid);
|
|
SLSI_ETHER_COPY(hdr->addr2, dev->dev_addr);
|
|
SLSI_ETHER_COPY(hdr->addr3, bssid);
|
|
memcpy(final_buf + IEEE80211_HEADER_SIZE, buf, len);
|
|
|
|
kfree(buf);
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
|
|
r = slsi_mlme_send_frame_mgmt(sdev, dev, final_buf, final_length, FAPI_DATAUNITDESCRIPTOR_IEEE802_11_FRAME, FAPI_MESSAGETYPE_IEEE80211_ACTION, host_tag, SLSI_FREQ_HOST_TO_FW(freq), dwell_time * 1000, 0);
|
|
|
|
kfree(final_buf);
|
|
kfree(ioctl_args);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return r;
|
|
}
|
|
|
|
static int slsi_send_action_frame_cert(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
char *temp;
|
|
int r = 0;
|
|
u16 host_tag = slsi_tx_mgmt_host_tag(sdev);
|
|
struct ieee80211_hdr *hdr;
|
|
u8 *buf = NULL;
|
|
u8 *final_buf = NULL;
|
|
u8 temp_byte;
|
|
int len = 0;
|
|
int final_length = 0;
|
|
int i = 0, j = 0;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
if (!ndev_vif->activated || ndev_vif->vif_type != FAPI_VIFTYPE_STATION ||
|
|
ndev_vif->sta.vif_status != SLSI_VIF_STATUS_CONNECTED) {
|
|
SLSI_ERR(sdev, "Not a STA vif or status is not CONNECTED\n");
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 2);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (ioctl_args->arg_count < 2) {
|
|
SLSI_ERR(sdev, "Invalid argument count = %d\n", ioctl_args->arg_count);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &len)) {
|
|
SLSI_ERR(sdev, "Invalid length string: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
buf = kmalloc((len + 1) / 2, GFP_KERNEL);
|
|
|
|
if (!buf) {
|
|
SLSI_ERR(sdev, "Malloc failed\n");
|
|
kfree(ioctl_args);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/*We receive a char buffer, convert to hex*/
|
|
temp = ioctl_args->args[1];
|
|
for (i = 0, j = 0; j < len; j += 2) {
|
|
if (j + 1 == len)
|
|
temp_byte = slsi_parse_hex(temp[j]);
|
|
else
|
|
temp_byte = slsi_parse_hex(temp[j]) << 4 | slsi_parse_hex(temp[j + 1]);
|
|
buf[i++] = temp_byte;
|
|
}
|
|
len = i;
|
|
|
|
final_length = len + IEEE80211_HEADER_SIZE;
|
|
final_buf = kmalloc(final_length, GFP_KERNEL);
|
|
if (!final_buf) {
|
|
SLSI_ERR(sdev, "Malloc failed\n");
|
|
kfree(ioctl_args);
|
|
kfree(buf);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
hdr = (struct ieee80211_hdr *)final_buf;
|
|
hdr->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, IEEE80211_STYPE_ACTION);
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
SLSI_ETHER_COPY(hdr->addr1, ndev_vif->sta.bssid);
|
|
SLSI_ETHER_COPY(hdr->addr3, ndev_vif->sta.bssid);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
SLSI_ETHER_COPY(hdr->addr2, sdev->hw_addr);
|
|
memcpy(final_buf + IEEE80211_HEADER_SIZE, buf, len);
|
|
|
|
kfree(buf);
|
|
|
|
r = slsi_mlme_send_frame_mgmt(sdev, dev, final_buf, final_length, FAPI_DATAUNITDESCRIPTOR_IEEE802_11_FRAME, FAPI_MESSAGETYPE_IEEE80211_ACTION, host_tag, 0, 0, 0);
|
|
|
|
kfree(final_buf);
|
|
kfree(ioctl_args);
|
|
return r;
|
|
}
|
|
|
|
#ifdef SLSI_TEST_DEV
|
|
static int slsi_send_action_frame_ut(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
char *hex_str;
|
|
u8 bssid[6] = { 0 };
|
|
u8 transmitteraddr[6] = { 0 };
|
|
int channel = 0;
|
|
int r = 0;
|
|
u32 dwell_time;
|
|
struct ieee80211_mgmt *hdr;
|
|
u8 *buf = NULL;
|
|
u8 temp_byte;
|
|
int len = 0;
|
|
int i = 0, j = 0;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
struct ieee80211_channel chan;
|
|
u64 cookie = 1;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 6);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (ioctl_args->arg_count < 6) {
|
|
SLSI_ERR(sdev, "Invalid argument count = %d\n", ioctl_args->arg_count);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (strlen(ioctl_args->args[0]) != 17) {
|
|
SLSI_ERR(sdev, "Invalid mac address: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
slsi_machexstring_to_macarray(ioctl_args->args[0], transmitteraddr);
|
|
|
|
if (strlen(ioctl_args->args[1]) != 17) {
|
|
SLSI_ERR(sdev, "Invalid mac address: '%s'\n", ioctl_args->args[1]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
slsi_machexstring_to_macarray(ioctl_args->args[1], bssid);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[2], &channel)) {
|
|
SLSI_ERR(sdev, "Invalid channel string: '%s'\n", ioctl_args->args[2]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (channel < 1 || channel > 165) {
|
|
SLSI_ERR(sdev, "Invalid channel : %d\n", channel);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_INFO(sdev, "channel: '%d'\n", channel);
|
|
|
|
if (channel > 14)
|
|
chan.band = NL80211_BAND_5GHZ;
|
|
else
|
|
chan.band = NL80211_BAND_2GHZ;
|
|
|
|
SLSI_ERR(sdev, "channel: '%d'\n", chan.band);
|
|
|
|
chan.center_freq = (u16)ieee80211_channel_to_frequency(channel, chan.band);
|
|
if (!chan.center_freq) {
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[3], &dwell_time)) {
|
|
SLSI_ERR(sdev, "Invalid dwell time string: '%s'\n", ioctl_args->args[3]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[4], &len)) {
|
|
SLSI_ERR(sdev, "Invalid length string: '%s'\n", ioctl_args->args[4]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* if length is less than 0 or greater than 1024 driver will ignore the command */
|
|
if (len < 0 || len > 1024) {
|
|
SLSI_ERR(sdev, "Invalid buffer length:%d\n", len);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
buf = kmalloc((IEEE80211_HEADER_SIZE + ((len + 1) / 2)), GFP_KERNEL);
|
|
|
|
if (!buf) {
|
|
SLSI_ERR(sdev, "Malloc failed\n");
|
|
kfree(ioctl_args);
|
|
return -ENOMEM;
|
|
}
|
|
hdr = (struct ieee80211_mgmt *)buf;
|
|
hdr->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, IEEE80211_STYPE_ACTION);
|
|
SLSI_ETHER_COPY(hdr->da, bssid);
|
|
SLSI_ETHER_COPY(hdr->sa, transmitteraddr);
|
|
SLSI_ETHER_COPY(hdr->bssid, bssid);
|
|
|
|
/*We receive a char buffer, convert to hex*/
|
|
hex_str = ioctl_args->args[5];
|
|
for (i = IEEE80211_HEADER_SIZE, j = 0; j < len; j += 2) {
|
|
if (j + 1 == len)
|
|
temp_byte = slsi_parse_hex(hex_str[j]);
|
|
else
|
|
temp_byte = slsi_parse_hex(hex_str[j]) << 4 | slsi_parse_hex(hex_str[j + 1]);
|
|
buf[i++] = temp_byte;
|
|
}
|
|
len = i;
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
r = slsi_wlan_mgmt_tx(sdev, dev, &chan, dwell_time, buf, len, 1, &cookie);
|
|
|
|
kfree(buf);
|
|
kfree(ioctl_args);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return r;
|
|
}
|
|
#endif
|
|
|
|
static int slsi_setting_max_sta_write(struct net_device *dev, char *command, int cmd_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_mib_data mib_data = { 0, NULL };
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int sta_number = 0;
|
|
int result = 0;
|
|
|
|
slsi_convert_space_seperation(command, cmd_len);
|
|
ioctl_args = slsi_get_private_command_args(command, cmd_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &sta_number)) {
|
|
SLSI_ERR(sdev, "Invalid max num sta sting: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (sta_number > 10 || sta_number < 1) {
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
result = slsi_mib_encode_uint(&mib_data, SLSI_PSID_UNIFI_MAX_CLIENT, sta_number, 0);
|
|
if (result != SLSI_MIB_STATUS_SUCCESS || mib_data.dataLength == 0) {
|
|
kfree(ioctl_args);
|
|
return -ENOMEM;
|
|
}
|
|
result = slsi_mlme_set(sdev, dev, mib_data.data, mib_data.dataLength);
|
|
if (result != 0)
|
|
SLSI_ERR(sdev, "max_sta: mlme_set_req failed: Result code: %d\n", result);
|
|
kfree(ioctl_args);
|
|
kfree(mib_data.data);
|
|
|
|
return result;
|
|
}
|
|
|
|
static int slsi_country_write(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *netdev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = netdev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
char alpha2_code[SLSI_COUNTRY_CODE_LEN];
|
|
int status;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (strlen(ioctl_args->args[0]) < 2) {
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
memcpy(alpha2_code, ioctl_args->args[0], 2);
|
|
alpha2_code[2] = ' '; /* set 3rd byte of countrycode to ASCII space */
|
|
|
|
status = slsi_set_country_update_regd(sdev, alpha2_code, SLSI_COUNTRY_CODE_LEN);
|
|
|
|
kfree(ioctl_args);
|
|
return status;
|
|
}
|
|
|
|
#if defined(CONFIG_SLSI_WLAN_STA_FWD_BEACON) && (defined(SCSC_SEP_VERSION) && SCSC_SEP_VERSION >= 10)
|
|
static int slsi_forward_beacon(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *netdev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = netdev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int intended_action = 0;
|
|
int ret = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (strlen(ioctl_args->args[0]) == 4 && strncasecmp(ioctl_args->args[0], "stop", 4) == 0) {
|
|
intended_action = FAPI_ACTION_STOP;
|
|
} else if (strlen(ioctl_args->args[0]) == 5 && strncasecmp(ioctl_args->args[0], "start", 5) == 0) {
|
|
intended_action = FAPI_ACTION_START;
|
|
} else {
|
|
SLSI_NET_ERR(dev, "BEACON_RECV should be used with start or stop\n");
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
SLSI_NET_DBG2(dev, SLSI_MLME, "BEACON_RECV %s!!\n", intended_action ? "START" : "STOP");
|
|
SLSI_MUTEX_LOCK(netdev_vif->vif_mutex);
|
|
|
|
if (!netdev_vif->activated || netdev_vif->vif_type != FAPI_VIFTYPE_STATION ||
|
|
netdev_vif->sta.vif_status != SLSI_VIF_STATUS_CONNECTED) {
|
|
SLSI_ERR(sdev, "Not a STA vif or status is not CONNECTED\n");
|
|
ret = -EINVAL;
|
|
goto exit_vif_mutex;
|
|
}
|
|
|
|
if ((intended_action == FAPI_ACTION_START && netdev_vif->is_wips_running) ||
|
|
(intended_action == FAPI_ACTION_STOP && !netdev_vif->is_wips_running)) {
|
|
SLSI_NET_INFO(dev, "Forwarding beacon is already %s!!\n",
|
|
netdev_vif->is_wips_running ? "running" : "stopped");
|
|
ret = 0;
|
|
goto exit_vif_mutex;
|
|
}
|
|
|
|
SLSI_MUTEX_LOCK(netdev_vif->scan_mutex);
|
|
if (intended_action == FAPI_ACTION_START &&
|
|
(netdev_vif->scan[SLSI_SCAN_HW_ID].scan_req || netdev_vif->sta.roam_in_progress)) {
|
|
SLSI_NET_ERR(dev, "Rejecting BEACON_RECV start as scan/roam is running\n");
|
|
ret = -EBUSY;
|
|
goto exit_scan_mutex;
|
|
}
|
|
|
|
ret = slsi_mlme_set_forward_beacon(sdev, dev, intended_action);
|
|
exit_scan_mutex:
|
|
SLSI_MUTEX_UNLOCK(netdev_vif->scan_mutex);
|
|
exit_vif_mutex:
|
|
kfree(ioctl_args);
|
|
SLSI_MUTEX_UNLOCK(netdev_vif->vif_mutex);
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
static int slsi_update_rssi_boost(struct net_device *dev, char *buffer, int buf_len)
|
|
{
|
|
struct netdev_vif *netdev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = netdev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int digit1, digit2, band, lendigit1, lendigit2;
|
|
int boost = 0, length = 0, i = 0;
|
|
char *rssi_boost_string = NULL;
|
|
|
|
ioctl_args = slsi_get_private_command_args(buffer, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
rssi_boost_string = ioctl_args->args[0];
|
|
if (strlen(rssi_boost_string) < 8) {
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
for (i = 0; i < (strlen(rssi_boost_string) - 4);) {
|
|
if (rssi_boost_string[i] == '0' &&
|
|
rssi_boost_string[i + 1] == '4') {
|
|
if (rssi_boost_string[i + 2] == '0' &&
|
|
rssi_boost_string[i + 3] == '2' &&
|
|
((i + 7) < strlen(rssi_boost_string))) {
|
|
i = i + 4;
|
|
} else {
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
digit1 = slsi_parse_hex(rssi_boost_string[i]);
|
|
digit2 = slsi_parse_hex(rssi_boost_string[i + 1]);
|
|
boost = (digit1 * 16) + digit2;
|
|
band = rssi_boost_string[i + 3] - '0';
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (band == 0) {
|
|
sdev->device_config.rssi_boost_2g = 0;
|
|
sdev->device_config.rssi_boost_5g = 0;
|
|
} else if (band == 1) {
|
|
sdev->device_config.rssi_boost_2g = 0;
|
|
sdev->device_config.rssi_boost_5g = boost;
|
|
} else if (band == 2) {
|
|
sdev->device_config.rssi_boost_2g = boost;
|
|
sdev->device_config.rssi_boost_5g = 0;
|
|
} else {
|
|
SLSI_ERR(sdev, "Invalid band value %d\n", band);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
if (netdev_vif->activated &&
|
|
netdev_vif->vif_type == FAPI_VIFTYPE_STATION) {
|
|
kfree(ioctl_args);
|
|
return slsi_set_boost(sdev, dev);
|
|
}
|
|
kfree(ioctl_args);
|
|
return 0;
|
|
}
|
|
i = i + 2;
|
|
lendigit1 = slsi_parse_hex(rssi_boost_string[i]);
|
|
lendigit2 = slsi_parse_hex(rssi_boost_string[i + 1]);
|
|
length = (lendigit1 * 16) + lendigit2;
|
|
i = i + (length * 2) + 2;
|
|
}
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
int slsi_set_tx_power_calling(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int mode = 0;
|
|
int error = 0;
|
|
u16 host_state;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &mode)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
host_state = sdev->device_config.host_state;
|
|
|
|
switch (mode) {
|
|
case HEAD_SAR_BACKOFF_DISABLED:
|
|
host_state &= ~SLSI_HOSTSTATE_HEAD_SAR_ACTIVE;
|
|
break;
|
|
case HEAD_SAR_BACKOFF_ENABLED:
|
|
host_state |= SLSI_HOSTSTATE_HEAD_SAR_ACTIVE;
|
|
break;
|
|
case BODY_SAR_BACKOFF_DISABLED:
|
|
host_state &= ~SLSI_HOSTSTATE_GRIP_SAR_ACTIVE;
|
|
break;
|
|
case BODY_SAR_BACKOFF_ENABLED:
|
|
host_state |= SLSI_HOSTSTATE_GRIP_SAR_ACTIVE;
|
|
break;
|
|
case NR_MMWAVE_SAR_BACKOFF_DISABLED:
|
|
host_state &= ~(SLSI_HOSTSTATE_BASE_MMW << SLSI_HOSTSTATE_BASE_POS);
|
|
break;
|
|
case NR_MMWAVE_SAR_BACKOFF_ENABLED:
|
|
host_state &= ~SLSI_HOSTSTATE_BASE_MASK;
|
|
host_state |= SLSI_HOSTSTATE_BASE_MMW << SLSI_HOSTSTATE_BASE_POS;
|
|
break;
|
|
case NR_SUB6_SAR_BACKOFF_DISABLED:
|
|
sdev->device_config.host_state_sub6_band = false;
|
|
host_state &= ~(SLSI_HOSTSTATE_SUB6_BAND_MASK | SLSI_HOSTSTATE_BASE_MASK);
|
|
break;
|
|
case NR_SUB6_SAR_BACKOFF_ENABLED:
|
|
sdev->device_config.host_state_sub6_band = true;
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return error;
|
|
case SAR_BACKOFF_DISABLE_ALL:
|
|
host_state &= SLSI_HOSTSTATE_SAR_INIT_MASK;
|
|
break;
|
|
case MHS_SAR_BACKOFF_DISABLED:
|
|
host_state &= ~SLSI_HOSTSTATE_MHS_SAR_ACTIVE;
|
|
break;
|
|
case MHS_SAR_BACKOFF_ENABLED:
|
|
host_state |= SLSI_HOSTSTATE_MHS_SAR_ACTIVE;
|
|
break;
|
|
default:
|
|
SLSI_ERR(sdev, "Invalid mode: '%s'\n", ioctl_args->args[0]);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
error = slsi_mlme_set_host_state(sdev, dev, host_state);
|
|
if (!error)
|
|
sdev->device_config.host_state = host_state;
|
|
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return error;
|
|
}
|
|
|
|
int slsi_set_tx_power_sub6_band(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int mode = 0;
|
|
int error = 0;
|
|
u16 host_state;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (!sdev->device_config.host_state_sub6_band) {
|
|
SLSI_ERR(sdev, "'SET_TX_POWER_CALLING 6' must be called first.\n");
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &mode)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
host_state = sdev->device_config.host_state;
|
|
|
|
host_state &= ~(SLSI_HOSTSTATE_SUB6_BAND_MASK | SLSI_HOSTSTATE_BASE_MASK);
|
|
host_state |= SLSI_HOSTSTATE_BASE_SUB6 << SLSI_HOSTSTATE_BASE_POS;
|
|
|
|
switch (mode) {
|
|
case SUB6_SAR_1_BAND:
|
|
host_state |= (SUB6_SAR_1 << SLSI_HOSTSTATE_SUB6_BAND_POS);
|
|
break;
|
|
case SUB6_SAR_2_BAND:
|
|
host_state |= (SUB6_SAR_2 << SLSI_HOSTSTATE_SUB6_BAND_POS);
|
|
break;
|
|
case SUB6_SAR_3_BAND:
|
|
host_state |= (SUB6_SAR_3 << SLSI_HOSTSTATE_SUB6_BAND_POS);
|
|
break;
|
|
case SUB6_SAR_4_BAND:
|
|
host_state |= (SUB6_SAR_4 << SLSI_HOSTSTATE_SUB6_BAND_POS);
|
|
break;
|
|
case SUB6_SAR_5_BAND:
|
|
host_state |= (SUB6_SAR_5 << SLSI_HOSTSTATE_SUB6_BAND_POS);
|
|
break;
|
|
case SUB6_SAR_6_BAND:
|
|
host_state |= (SUB6_SAR_6 << SLSI_HOSTSTATE_SUB6_BAND_POS);
|
|
break;
|
|
default:
|
|
SLSI_ERR(sdev, "Invalid mode: '%s'\n", ioctl_args->args[0]);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
error = slsi_mlme_set_host_state(sdev, dev, host_state);
|
|
if (!error)
|
|
sdev->device_config.host_state = host_state;
|
|
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
kfree(ioctl_args);
|
|
return error;
|
|
}
|
|
|
|
static int slsi_print_regulatory(struct slsi_802_11d_reg_domain *domain_info, char *buf, int buf_len, struct slsi_supported_channels *supported_channels, int supp_chan_length)
|
|
{
|
|
int cur_pos = 0;
|
|
int i, j, k;
|
|
char *dfs_region_str[] = {"unknown", "FCC", "ETSI", "JAPAN", "GLOBAL", "CHINA"};
|
|
u8 dfs_region_index;
|
|
struct ieee80211_reg_rule *reg_rule;
|
|
int channel_start_freq = 0;
|
|
int channel_end_freq = 0;
|
|
int channel_start_num = 0;
|
|
int channel_end_num = 0;
|
|
int channel_count = 0;
|
|
int channel_increment = 0;
|
|
int channel_band = 0;
|
|
bool display_pattern = false;
|
|
|
|
cur_pos = snprintf(buf, buf_len, "country %c%c:", domain_info->regdomain->alpha2[0],
|
|
domain_info->regdomain->alpha2[1]);
|
|
dfs_region_index = domain_info->regdomain->dfs_region <= 5 ? domain_info->regdomain->dfs_region : 0;
|
|
cur_pos += snprintf(buf + cur_pos, buf_len - cur_pos, "DFS-%s\n", dfs_region_str[dfs_region_index]);
|
|
for (i = 0; i < domain_info->regdomain->n_reg_rules; i++) {
|
|
reg_rule = &domain_info->regdomain->reg_rules[i];
|
|
if (reg_rule->freq_range.start_freq_khz / 1000 >= 57000)
|
|
continue;
|
|
cur_pos += snprintf(buf + cur_pos, buf_len - cur_pos, "\t(%d-%d @ %d), (N/A, %d)",
|
|
reg_rule->freq_range.start_freq_khz / 1000,
|
|
reg_rule->freq_range.end_freq_khz / 1000,
|
|
reg_rule->freq_range.max_bandwidth_khz / 1000,
|
|
MBM_TO_DBM(reg_rule->power_rule.max_eirp));
|
|
if (reg_rule->flags) {
|
|
if (reg_rule->flags & NL80211_RRF_DFS)
|
|
cur_pos += snprintf(buf + cur_pos, buf_len - cur_pos, ", DFS");
|
|
if (reg_rule->flags & NL80211_RRF_NO_OFDM)
|
|
cur_pos += snprintf(buf + cur_pos, buf_len - cur_pos, ", NO_OFDM");
|
|
if (reg_rule->flags & (NL80211_RRF_NO_IR))
|
|
cur_pos += snprintf(buf + cur_pos, buf_len - cur_pos, ", NO_IR");
|
|
if (reg_rule->flags & NL80211_RRF_NO_INDOOR)
|
|
cur_pos += snprintf(buf + cur_pos, buf_len - cur_pos, ", NO_INDOOR");
|
|
if (reg_rule->flags & NL80211_RRF_NO_OUTDOOR)
|
|
cur_pos += snprintf(buf + cur_pos, buf_len - cur_pos, ", NO_OUTDOOR");
|
|
}
|
|
cur_pos += snprintf(buf + cur_pos, buf_len - cur_pos, "\n");
|
|
}
|
|
|
|
/* Display of Supported Channels for 2.4GHz and 5GHz */
|
|
cur_pos += snprintf(buf + cur_pos, buf_len - cur_pos, "Channels:");
|
|
|
|
for (i = 0; i < supp_chan_length; i++) {
|
|
channel_start_num = supported_channels[i].start_chan_num;
|
|
channel_count = supported_channels[i].channel_count;
|
|
channel_increment = supported_channels[i].increment;
|
|
channel_band = supported_channels[i].band;
|
|
channel_end_num = channel_start_num + ((channel_count - 1) * channel_increment);
|
|
for (j = channel_start_num; j <= channel_end_num; j += channel_increment) {
|
|
channel_start_freq = (ieee80211_channel_to_frequency(j, channel_band) * 1000) - 10000;
|
|
channel_end_freq = (ieee80211_channel_to_frequency(j, channel_band) * 1000) + 10000;
|
|
for (k = 0; k < domain_info->regdomain->n_reg_rules; k++) {
|
|
reg_rule = &domain_info->regdomain->reg_rules[k];
|
|
if (reg_rule->freq_range.start_freq_khz <= channel_start_freq &&
|
|
reg_rule->freq_range.end_freq_khz >= channel_end_freq) {
|
|
if (display_pattern)
|
|
cur_pos += snprintf(buf + cur_pos, buf_len - cur_pos, ", %d", j);
|
|
else
|
|
cur_pos += snprintf(buf + cur_pos, buf_len - cur_pos, " %d", j);
|
|
display_pattern = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
cur_pos += snprintf(buf + cur_pos, buf_len - cur_pos, "\n");
|
|
return cur_pos;
|
|
}
|
|
|
|
static int slsi_get_supported_channels(struct slsi_dev *sdev, struct net_device *dev, struct slsi_supported_channels *supported_channels)
|
|
{
|
|
struct slsi_mib_data mibrsp = { 0, NULL };
|
|
struct slsi_mib_data supported_chan_mib;
|
|
struct slsi_mib_value *values = NULL;
|
|
struct slsi_mib_get_entry get_values[] = {{SLSI_PSID_UNIFI_SUPPORTED_CHANNELS, { 0, 0 } } };
|
|
int i, chan_count, chan_start;
|
|
int supp_chan_length = 0;
|
|
|
|
/* Expect each mib length in response is <= 16. So assume 16 bytes for each MIB */
|
|
mibrsp.dataLength = 16;
|
|
mibrsp.data = kmalloc(mibrsp.dataLength, GFP_KERNEL);
|
|
if (!mibrsp.data) {
|
|
SLSI_ERR(sdev, "Cannot kmalloc %d bytes\n", mibrsp.dataLength);
|
|
return 0;
|
|
}
|
|
values = slsi_read_mibs(sdev, dev, get_values, 1, &mibrsp);
|
|
if (!values)
|
|
goto exit_with_mibrsp;
|
|
|
|
if (values[0].type != SLSI_MIB_TYPE_OCTET) {
|
|
SLSI_ERR(sdev, "Supported_Chan invalid type.");
|
|
goto exit_with_values;
|
|
}
|
|
|
|
supported_chan_mib = values[0].u.octetValue;
|
|
for (i = 0; i < supported_chan_mib.dataLength / 2; i++) {
|
|
chan_start = supported_chan_mib.data[i * 2];
|
|
chan_count = supported_chan_mib.data[i * 2 + 1];
|
|
if (chan_start == 1) { /* for 2.4GHz */
|
|
supported_channels[supp_chan_length].start_chan_num = 1;
|
|
if (!(sdev->device_config.host_state & SLSI_HOSTSTATE_CELLULAR_ACTIVE) &&
|
|
chan_count > 11 && sdev->device_config.disable_ch12_ch13) {
|
|
chan_count = 11;
|
|
SLSI_DBG1(sdev, SLSI_CFG80211, "Channels 12 and 13 have been disabled");
|
|
}
|
|
supported_channels[supp_chan_length].channel_count = chan_count;
|
|
supported_channels[supp_chan_length].increment = 1;
|
|
supported_channels[supp_chan_length].band = NL80211_BAND_2GHZ;
|
|
supp_chan_length = supp_chan_length + 1;
|
|
} else { /* for 5GHz */
|
|
supported_channels[supp_chan_length].start_chan_num = chan_start;
|
|
supported_channels[supp_chan_length].channel_count = chan_count;
|
|
supported_channels[supp_chan_length].increment = 4;
|
|
supported_channels[supp_chan_length].band = NL80211_BAND_5GHZ;
|
|
supp_chan_length = supp_chan_length + 1;
|
|
}
|
|
}
|
|
exit_with_values:
|
|
kfree(values);
|
|
exit_with_mibrsp:
|
|
kfree(mibrsp.data);
|
|
return supp_chan_length;
|
|
}
|
|
|
|
static int slsi_get_regulatory(struct net_device *dev, char *buf, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int mode = 0;
|
|
int cur_pos = 0;
|
|
int status;
|
|
u8 alpha2[3];
|
|
struct slsi_supported_channels supported_channels[5];
|
|
int supp_chan_length;
|
|
|
|
ioctl_args = slsi_get_private_command_args(buf, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &mode)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (mode != 0 && mode != 1) {
|
|
SLSI_ERR(sdev, "Invalid mode: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (mode == 1) {
|
|
struct slsi_802_11d_reg_domain domain_info;
|
|
|
|
memset(&domain_info, 0, sizeof(struct slsi_802_11d_reg_domain));
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
if (!ndev_vif->activated || ndev_vif->vif_type != FAPI_VIFTYPE_STATION || !ndev_vif->sta.sta_bss) {
|
|
snprintf(buf, buf_len, "Station not connected");
|
|
SLSI_ERR(sdev, "station not connected. vif.activated:%d, vif.type:%d, vif.bss:%s\n",
|
|
ndev_vif->activated, ndev_vif->vif_type, ndev_vif->sta.sta_bss ? "yes" : "no");
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
/* read vif specific country code, index = vifid+1 */
|
|
status = slsi_read_default_country(sdev, alpha2, ndev_vif->ifnum + 1);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
if (status) {
|
|
kfree(ioctl_args);
|
|
return status;
|
|
}
|
|
|
|
/* max 20 rules */
|
|
domain_info.regdomain = kmalloc(sizeof(*domain_info.regdomain) + sizeof(struct ieee80211_reg_rule) * 20, GFP_KERNEL);
|
|
if (!domain_info.regdomain) {
|
|
SLSI_ERR(sdev, "no memory size:%lu\n",
|
|
sizeof(struct ieee80211_regdomain) + sizeof(struct ieee80211_reg_rule) * 20);
|
|
kfree(ioctl_args);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/* get regulatory rules based on country code */
|
|
domain_info.countrylist = sdev->device_config.domain_info.countrylist;
|
|
domain_info.country_len = sdev->device_config.domain_info.country_len;
|
|
status = slsi_read_regulatory_rules(sdev, &domain_info, alpha2);
|
|
if (status) {
|
|
kfree(domain_info.regdomain);
|
|
kfree(ioctl_args);
|
|
return status;
|
|
}
|
|
/* get supported channels based on country code */
|
|
supp_chan_length = slsi_get_supported_channels(sdev, dev, &supported_channels[0]);
|
|
cur_pos += slsi_print_regulatory(&domain_info, buf + cur_pos, buf_len - cur_pos, &supported_channels[0], supp_chan_length);
|
|
kfree(domain_info.regdomain);
|
|
} else if (mode == 0) {
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
supp_chan_length = slsi_get_supported_channels(sdev, dev, &supported_channels[0]);
|
|
cur_pos += slsi_print_regulatory(&sdev->device_config.domain_info, buf + cur_pos, buf_len - cur_pos, &supported_channels[0], supp_chan_length);
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
}
|
|
/* Buf is somewhere close to 4Kbytes. so expect some spare space. If there is no spare
|
|
* space we might have missed printing some text in buf.
|
|
*/
|
|
kfree(ioctl_args);
|
|
if (buf_len - cur_pos)
|
|
return cur_pos;
|
|
else
|
|
return -ENOMEM;
|
|
}
|
|
|
|
void slsi_disable_ch12_13(struct slsi_dev *sdev)
|
|
{
|
|
struct wiphy *wiphy = sdev->wiphy;
|
|
struct ieee80211_channel *chan;
|
|
|
|
if (wiphy->bands[0]) {
|
|
chan = &wiphy->bands[0]->channels[11];
|
|
chan->flags |= IEEE80211_CHAN_DISABLED;
|
|
chan = &wiphy->bands[0]->channels[12];
|
|
chan->flags |= IEEE80211_CHAN_DISABLED;
|
|
}
|
|
|
|
SLSI_DBG1(sdev, SLSI_CFG80211, "Channels 12 and 13 have been disabled");
|
|
}
|
|
|
|
int slsi_set_fcc_channel(struct net_device *dev, char *cmd, int cmd_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int status;
|
|
int fcc_channel_value;
|
|
u16 host_state;
|
|
|
|
ioctl_args = slsi_get_private_command_args(cmd, cmd_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &fcc_channel_value)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (fcc_channel_value != 0 && fcc_channel_value != -1) {
|
|
SLSI_ERR(sdev, "Invalid value of flight_mode_ena: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
host_state = sdev->device_config.host_state;
|
|
|
|
/* SET_FCC_CHANNEL 0 indicates flight mode is enabled */
|
|
/* SET_FCC_CHANNEL -1 indicates flight mode is disabled */
|
|
if (fcc_channel_value == 0)
|
|
host_state = host_state & ~SLSI_HOSTSTATE_CELLULAR_ACTIVE;
|
|
else
|
|
host_state = host_state | SLSI_HOSTSTATE_CELLULAR_ACTIVE;
|
|
sdev->device_config.host_state = host_state;
|
|
|
|
status = slsi_mlme_set_host_state(sdev, dev, host_state);
|
|
if (status) {
|
|
SLSI_ERR(sdev, "Err setting MMaxPowerEna. error = %d\n", status);
|
|
} else {
|
|
if (fcc_channel_value == 0 && sdev->device_config.disable_ch12_ch13)
|
|
slsi_disable_ch12_13(sdev);
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
kfree(ioctl_args);
|
|
return status;
|
|
}
|
|
|
|
int slsi_fake_mac_write(struct net_device *dev, char *cmd, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_mib_data mib_data = { 0, NULL };
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int status;
|
|
bool enable;
|
|
|
|
ioctl_args = slsi_get_private_command_args(cmd, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (strlen(ioctl_args->args[0]) == 2 && strncmp(ioctl_args->args[0], "ON", strlen("ON")) == 0) {
|
|
enable = 1;
|
|
} else if (strlen(ioctl_args->args[0]) == 3 && strncmp(ioctl_args->args[0], "OFF", strlen("OFF")) == 0) {
|
|
enable = 0;
|
|
} else {
|
|
SLSI_ERR(sdev, "Invalid parameter: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
status = slsi_mib_encode_bool(&mib_data, SLSI_PSID_UNIFI_MAC_ADDRESS_RANDOMISATION, enable, 0);
|
|
if (status != SLSI_MIB_STATUS_SUCCESS) {
|
|
SLSI_ERR(sdev, "FAKE MAC FAIL: no mem for MIB\n");
|
|
kfree(ioctl_args);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
status = slsi_mlme_set(sdev, NULL, mib_data.data, mib_data.dataLength);
|
|
|
|
kfree(mib_data.data);
|
|
|
|
if (status)
|
|
SLSI_ERR(sdev, "Err setting unifiMacAddrRandomistaion MIB. error = %d\n", status);
|
|
|
|
kfree(ioctl_args);
|
|
return status;
|
|
}
|
|
|
|
static char *slsi_get_assoc_status(u16 fw_result_code)
|
|
{
|
|
char *assoc_status_label = "unspecified_failure";
|
|
|
|
switch (fw_result_code) {
|
|
case FAPI_RESULTCODE_SUCCESS:
|
|
assoc_status_label = "success";
|
|
break;
|
|
case FAPI_RESULTCODE_TRANSMISSION_FAILURE:
|
|
assoc_status_label = "transmission_failure";
|
|
break;
|
|
case FAPI_RESULTCODE_HOST_REQUEST_SUCCESS:
|
|
assoc_status_label = "host_request_success";
|
|
break;
|
|
case FAPI_RESULTCODE_HOST_REQUEST_FAILED:
|
|
assoc_status_label = "host_request_failed";
|
|
break;
|
|
case FAPI_RESULTCODE_PROBE_TIMEOUT:
|
|
assoc_status_label = "probe_timeout";
|
|
break;
|
|
case FAPI_RESULTCODE_AUTH_TIMEOUT:
|
|
assoc_status_label = "auth_timeout";
|
|
break;
|
|
case FAPI_RESULTCODE_ASSOC_TIMEOUT:
|
|
assoc_status_label = "assoc_timeout";
|
|
break;
|
|
case FAPI_RESULTCODE_ASSOC_ABORT:
|
|
assoc_status_label = "assoc_abort";
|
|
break;
|
|
}
|
|
return assoc_status_label;
|
|
}
|
|
|
|
int slsi_get_sta_info(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int len;
|
|
#ifdef CONFIG_SCSC_WLAN_WIFI_SHARING
|
|
struct net_device *ap_dev;
|
|
struct netdev_vif *ndev_ap_vif;
|
|
|
|
ap_dev = slsi_get_netdev(sdev, SLSI_NET_INDEX_P2PX_SWLAN);
|
|
|
|
if (ap_dev) {
|
|
ndev_ap_vif = netdev_priv(ap_dev);
|
|
SLSI_MUTEX_LOCK(ndev_ap_vif->vif_mutex);
|
|
if (SLSI_IS_VIF_INDEX_MHS(sdev, ndev_ap_vif))
|
|
ndev_vif = ndev_ap_vif;
|
|
SLSI_MUTEX_UNLOCK(ndev_ap_vif->vif_mutex);
|
|
}
|
|
#endif
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
|
|
if (!ndev_vif->activated || ndev_vif->vif_type != FAPI_VIFTYPE_AP) {
|
|
SLSI_ERR(sdev, "slsi_get_sta_info: AP is not up.Command not allowed vif.activated:%d, vif.type:%d\n",
|
|
ndev_vif->activated, ndev_vif->vif_type);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return -EINVAL;
|
|
}
|
|
|
|
#if defined(SCSC_SEP_VERSION) && (SCSC_SEP_VERSION >= 9)
|
|
len = snprintf(command, buf_len, "GETSTAINFO %pM Rx_Retry_Pkts=%d Rx_BcMc_Pkts=%d CAP=%04x %02x:%02x:%02x ",
|
|
ndev_vif->ap.last_disconnected_sta.address,
|
|
ndev_vif->ap.last_disconnected_sta.rx_retry_packets,
|
|
ndev_vif->ap.last_disconnected_sta.rx_bc_mc_packets,
|
|
ndev_vif->ap.last_disconnected_sta.capabilities,
|
|
ndev_vif->ap.last_disconnected_sta.address[0],
|
|
ndev_vif->ap.last_disconnected_sta.address[1],
|
|
ndev_vif->ap.last_disconnected_sta.address[2]);
|
|
|
|
len += snprintf(&command[len], (buf_len - len), "%d %d %d %d %d %d %d %u %d",
|
|
ieee80211_frequency_to_channel(ndev_vif->ap.channel_freq),
|
|
ndev_vif->ap.last_disconnected_sta.bandwidth, ndev_vif->ap.last_disconnected_sta.rssi,
|
|
ndev_vif->ap.last_disconnected_sta.tx_data_rate, ndev_vif->ap.last_disconnected_sta.support_mode,
|
|
ndev_vif->ap.last_disconnected_sta.antenna_mode,
|
|
ndev_vif->ap.last_disconnected_sta.mimo_used, ndev_vif->ap.last_disconnected_sta.reason,
|
|
ndev_vif->ap.last_disconnected_sta.supported_band);
|
|
#else
|
|
len = snprintf(command, buf_len, "wl_get_sta_info : %02x%02x%02x %u %d %d %d %d %d %d %u ",
|
|
ndev_vif->ap.last_disconnected_sta.address[0], ndev_vif->ap.last_disconnected_sta.address[1],
|
|
ndev_vif->ap.last_disconnected_sta.address[2], ndev_vif->ap.channel_freq,
|
|
ndev_vif->ap.last_disconnected_sta.bandwidth, ndev_vif->ap.last_disconnected_sta.rssi,
|
|
ndev_vif->ap.last_disconnected_sta.tx_data_rate, ndev_vif->ap.last_disconnected_sta.mode,
|
|
ndev_vif->ap.last_disconnected_sta.antenna_mode,
|
|
ndev_vif->ap.last_disconnected_sta.mimo_used, ndev_vif->ap.last_disconnected_sta.reason);
|
|
#endif
|
|
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
return len;
|
|
}
|
|
|
|
static int slsi_get_bss_rssi(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
int len = 0;
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
len = snprintf(command, buf_len, "%d", ndev_vif->sta.last_connected_bss.rssi);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
return len;
|
|
}
|
|
|
|
static int slsi_get_bss_info(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
int len = 0;
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
|
|
len = snprintf(command, buf_len, "%02x:%02x:%02x %u %u %d %u %u %u %u %u %d %d %u %u %u %u",
|
|
ndev_vif->sta.last_connected_bss.address[0], ndev_vif->sta.last_connected_bss.address[1],
|
|
ndev_vif->sta.last_connected_bss.address[2],
|
|
ndev_vif->sta.last_connected_bss.channel_freq, ndev_vif->sta.last_connected_bss.bandwidth,
|
|
ndev_vif->sta.last_connected_bss.rssi, ndev_vif->sta.last_connected_bss.tx_data_rate,
|
|
ndev_vif->sta.last_connected_bss.mode, ndev_vif->sta.last_connected_bss.antenna_mode,
|
|
ndev_vif->sta.last_connected_bss.mimo_used,
|
|
ndev_vif->sta.last_connected_bss.passpoint_version, ndev_vif->sta.last_connected_bss.snr,
|
|
ndev_vif->sta.last_connected_bss.noise_level, ndev_vif->sta.last_connected_bss.roaming_akm,
|
|
ndev_vif->sta.last_connected_bss.roaming_count, ndev_vif->sta.last_connected_bss.kv,
|
|
ndev_vif->sta.last_connected_bss.kvie);
|
|
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
return len;
|
|
}
|
|
|
|
static int slsi_get_cu(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int mib_value = 0;
|
|
int res = 0;
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
if (!ndev_vif->activated || ndev_vif->iftype != NL80211_IFTYPE_STATION ||
|
|
(ndev_vif->iftype == NL80211_IFTYPE_STATION && ndev_vif->sta.vif_status != SLSI_VIF_STATUS_CONNECTED)) {
|
|
SLSI_NET_ERR(dev, "Not Activated or Not STA mode or STA is not in Connected state\n");
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
res = snprintf(command, buf_len, "-1\n");
|
|
return res;
|
|
}
|
|
|
|
res = slsi_get_beacon_cu(sdev, dev, &mib_value);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
if (res)
|
|
return res;
|
|
|
|
res = snprintf(command, buf_len, "%d\n", mib_value);
|
|
return res;
|
|
}
|
|
|
|
#ifdef CONFIG_SCSC_WLAN_MAX_LINK_SPEED
|
|
static int slsi_get_linkspeed(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int len = 0;
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
if (!ndev_vif->activated) {
|
|
SLSI_ERR(sdev, "Not Activated, Command not allowed vif.activated:%d, vif.type:%d\n",
|
|
ndev_vif->activated, ndev_vif->vif_type);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (ndev_vif->vif_type != FAPI_VIFTYPE_STATION && ndev_vif->sta.vif_status != SLSI_VIF_STATUS_CONNECTED) {
|
|
SLSI_NET_ERR(dev, "sta is not in connected state\n");
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return -EPERM;
|
|
}
|
|
|
|
len = snprintf(command, buf_len, "MAX_SPEED %u CURRENT_LINK_SPEED %u",
|
|
ndev_vif->sta.max_rate_mbps, ndev_vif->sta.data_rate_mbps);
|
|
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
return len;
|
|
}
|
|
#endif
|
|
|
|
static int slsi_get_assoc_reject_info(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int len = 0;
|
|
|
|
len = snprintf(command, buf_len, "assoc_reject.status : %d %s", sdev->assoc_result_code,
|
|
slsi_get_assoc_status(sdev->assoc_result_code));
|
|
|
|
return len;
|
|
}
|
|
|
|
#ifdef CONFIG_SCSC_WLAN_LOW_LATENCY_MODE
|
|
static int slsi_set_power_mode(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int status;
|
|
u16 power_mode;
|
|
int mode;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &mode)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (mode != 0 && mode != 1) {
|
|
SLSI_ERR(sdev, "Invalid power_mode: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
SLSI_NET_INFO(dev, "PS MODE mode:%d, vif_type:%d, vif_index:%d\n", mode, ndev_vif->vif_type,
|
|
ndev_vif->ifnum);
|
|
|
|
power_mode = (mode == 0) ? FAPI_POWERMANAGEMENTMODE_ACTIVE_MODE : FAPI_POWERMANAGEMENTMODE_POWER_SAVE;
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
if (!ndev_vif->activated || ndev_vif->vif_type != FAPI_VIFTYPE_STATION ||
|
|
!(ndev_vif->sta.vif_status == SLSI_VIF_STATUS_CONNECTED)) {
|
|
SLSI_ERR(sdev, "Command not allowed vif.activated:%d, vif.type:%d, ndev_vif->sta.vif_status:%d\n",
|
|
ndev_vif->activated, ndev_vif->vif_type, ndev_vif->sta.vif_status);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
status = slsi_mlme_powermgt(sdev, dev, power_mode);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
kfree(ioctl_args);
|
|
return status;
|
|
}
|
|
#endif
|
|
|
|
int slsi_set_bandwidth(struct net_device *dev, char *command, int cmd_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int bandwidth = 0;
|
|
int ret = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, cmd_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &bandwidth)) {
|
|
SLSI_ERR(sdev, "Invalid bandwidth string: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_DBG1(sdev, SLSI_CFG80211, "Bandwidth = %d\n", bandwidth);
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (bandwidth == 20 || bandwidth == 40 || bandwidth == 80 || bandwidth == 160) {
|
|
sdev->forced_bandwidth = bandwidth;
|
|
} else {
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = slsi_mlme_set_country(sdev, sdev->device_config.domain_info.regdomain->alpha2);
|
|
sdev->forced_bandwidth = 0;
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
if (ret != 0)
|
|
SLSI_NET_ERR(dev, "Error in setting the Country, ret=%d", ret);
|
|
|
|
kfree(ioctl_args);
|
|
return ret;
|
|
}
|
|
|
|
int slsi_set_bss_bandwidth(struct net_device *dev, char *command, int cmd_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
struct sk_buff *req;
|
|
struct sk_buff *cfm;
|
|
int bandwidth = 0;
|
|
int protection_scope = 0;
|
|
int ret = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, cmd_len, 2);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (!slsi_is_bw_valid(ioctl_args->args[0])) {
|
|
SLSI_ERR(sdev, "Unexpected string: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &bandwidth)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[1], &protection_scope)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[1]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (protection_scope != 0 && protection_scope != 1) {
|
|
SLSI_ERR(sdev, "Invalid value of protection_scope: '%d'\n", protection_scope);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
if (ndev_vif->iftype != NL80211_IFTYPE_STATION ||
|
|
(ndev_vif->iftype == NL80211_IFTYPE_STATION && ndev_vif->sta.vif_status != SLSI_VIF_STATUS_CONNECTED)) {
|
|
SLSI_NET_ERR(dev, "Must be STA interface and connected, iftype = %d\n", ndev_vif->iftype);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return -EPERM;
|
|
}
|
|
|
|
SLSI_NET_DBG1(dev, SLSI_MLME, "mlme_set_bss_max_channel_width_req(vif:%u, bw:%d, protection_scope:%x)\n",
|
|
ndev_vif->ifnum, bandwidth, protection_scope);
|
|
|
|
req = fapi_alloc(mlme_set_bss_max_channel_width_req, MLME_SET_BSS_MAX_CHANNEL_WIDTH_REQ, ndev_vif->ifnum, 0);
|
|
if (!req) {
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return -EIO;
|
|
}
|
|
|
|
fapi_set_u16(req, u.mlme_set_bss_max_channel_width_req.protection_scope, protection_scope);
|
|
fapi_set_u16(req, u.mlme_set_bss_max_channel_width_req.channel_information, bandwidth);
|
|
|
|
cfm = slsi_mlme_req_cfm(sdev, dev, req, MLME_SET_BSS_MAX_CHANNEL_WIDTH_CFM);
|
|
if (!cfm) {
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return -EIO;
|
|
}
|
|
|
|
if (fapi_get_u16(cfm, u.mlme_set_bss_max_channel_width_cfm.result_code) != FAPI_RESULTCODE_SUCCESS) {
|
|
SLSI_NET_ERR(dev, "mlme_set_bss_max_channel_width_cfm(result:0x%04x) ERROR\n",
|
|
fapi_get_u16(cfm, u.mlme_set_bss_max_channel_width_cfm.result_code));
|
|
ret = -EINVAL;
|
|
}
|
|
|
|
kfree_skb(cfm);
|
|
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
kfree(ioctl_args);
|
|
return ret;
|
|
}
|
|
|
|
int slsi_set_disconnect_ies(struct net_device *dev, char *cmd, int cmd_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
char *disconnect_ies = cmd + strlen(CMD_SET_DISCONNECT_IES) + 1;
|
|
int ie_len = 0;
|
|
u8 *disconnect_ies_bin;
|
|
u8 temp_byte;
|
|
int i;
|
|
int j;
|
|
int len;
|
|
|
|
SLSI_DBG1(sdev, SLSI_CFG80211, "Setting disconnect IE's\n");
|
|
ioctl_args = slsi_get_private_command_args(cmd, cmd_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
disconnect_ies = ioctl_args->args[0];
|
|
ie_len = strlen(ioctl_args->args[0]);
|
|
|
|
/* ie_len has been trimmed to even, as odd length would mean that ie is invalid */
|
|
ie_len &= (~0x01);
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
ndev_vif->sta.vendor_disconnect_ies_len = (ie_len / 2);
|
|
disconnect_ies_bin = kmalloc(ndev_vif->sta.vendor_disconnect_ies_len, GFP_KERNEL);
|
|
if (!disconnect_ies_bin) {
|
|
SLSI_ERR(sdev, "Malloc failed\n");
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
for (i = 0, j = 0; j < ie_len; j += 2) {
|
|
temp_byte = slsi_parse_hex(disconnect_ies[j]) << 4 | slsi_parse_hex(disconnect_ies[j + 1]);
|
|
disconnect_ies_bin[i++] = temp_byte;
|
|
}
|
|
|
|
/* check if the IE is valid */
|
|
for (i = 0; i < ndev_vif->sta.vendor_disconnect_ies_len;) {
|
|
if (disconnect_ies_bin[i] == 0xdd) {
|
|
len = disconnect_ies_bin[i + 1];
|
|
if ((ndev_vif->sta.vendor_disconnect_ies_len - (i + 2)) < len) {
|
|
SLSI_WARN(sdev, "The length of disconnect IE's is not proper\n");
|
|
ndev_vif->sta.vendor_disconnect_ies_len = 0;
|
|
kfree(disconnect_ies_bin);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
i = i + 2 + len;
|
|
} else {
|
|
SLSI_WARN(sdev, "The tag of disconnect IE's is not proper\n");
|
|
ndev_vif->sta.vendor_disconnect_ies_len = 0;
|
|
kfree(disconnect_ies_bin);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
ndev_vif->sta.vendor_disconnect_ies = disconnect_ies_bin;
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
kfree(ioctl_args);
|
|
return 0;
|
|
}
|
|
|
|
static int slsi_start_power_measurement_detection(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
u8 device_address[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
|
int r = 0;
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
|
|
if (sdev->detect_vif_active) {
|
|
SLSI_DBG1(sdev, SLSI_CFG80211, "Detect vif already active\n");
|
|
r = -EINVAL;
|
|
goto exit_with_vif_mutex;
|
|
}
|
|
|
|
if (slsi_mlme_add_detect_vif(sdev, dev, dev->dev_addr, device_address) != 0) {
|
|
SLSI_NET_ERR(dev, "slsi_mlme_add_vif for detect vif failed\n");
|
|
r = -EINVAL;
|
|
goto exit_with_vif_mutex;
|
|
}
|
|
|
|
sdev->detect_vif_active = true;
|
|
SLSI_DBG1(sdev, SLSI_CFG80211, "Starting Power Measurement Detection\n");
|
|
r = slsi_mlme_start_detect_request(sdev, dev);
|
|
if (r) {
|
|
r = -EINVAL;
|
|
if (slsi_mlme_del_detect_vif(sdev, dev) != 0)
|
|
SLSI_NET_ERR(dev, "slsi_mlme_del_vif failed for detect vif\n");
|
|
sdev->detect_vif_active = false;
|
|
}
|
|
|
|
exit_with_vif_mutex:
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return r;
|
|
}
|
|
|
|
#ifdef CONFIG_SCSC_WLAN_STA_ENHANCED_ARP_DETECT
|
|
static int slsi_enhanced_arp_start_stop(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int result = 0;
|
|
int readbyte = 0;
|
|
int readvalue = 0;
|
|
int i = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &readvalue)) {
|
|
SLSI_ERR(sdev, "Invalid start/stop string: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
SLSI_MUTEX_LOCK(sdev->device_config_mutex);
|
|
if (!sdev->device_config.fw_enhanced_arp_detect_supported) {
|
|
SLSI_ERR(sdev, "Enhanced ARP Detect Feature is not supported.\n");
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
kfree(ioctl_args);
|
|
return -ENOTSUPP;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(sdev->device_config_mutex);
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
if (ndev_vif->vif_type != FAPI_VIFTYPE_STATION) {
|
|
SLSI_ERR(sdev, "Not in STA mode\n");
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return -EPERM;
|
|
}
|
|
|
|
SLSI_DBG1(sdev, SLSI_CFG80211, "Enhanced ARP Start/Stop\n");
|
|
|
|
memset(ndev_vif->target_ip_addr, 0, sizeof(ndev_vif->target_ip_addr));
|
|
if (readvalue != 0) { /* parse IP address */
|
|
for (i = 0; i < 4 ; i++) {
|
|
readbyte = slsi_str_to_int(ioctl_args->args[0], &readvalue);
|
|
if (!readbyte) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
memset(ndev_vif->target_ip_addr, 0, sizeof(ndev_vif->target_ip_addr));
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
if (readvalue < 0 || readvalue > 255) {
|
|
SLSI_ERR(sdev, "Invalid value of IP address byte\n");
|
|
memset(ndev_vif->target_ip_addr, 0, sizeof(ndev_vif->target_ip_addr));
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
ndev_vif->target_ip_addr[i] = readvalue;
|
|
if (i == 3)
|
|
break;
|
|
if (strlen(ioctl_args->args[0]) - readbyte - 1 <= 0) {
|
|
SLSI_ERR(sdev, "Invalid IP address\n");
|
|
memset(ndev_vif->target_ip_addr, 0, sizeof(ndev_vif->target_ip_addr));
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
ioctl_args->args[0] = ioctl_args->args[0] + readbyte + 1;
|
|
}
|
|
}
|
|
|
|
if (ndev_vif->target_ip_addr[0] != 0) { /* start enhanced arp detect */
|
|
/* reset all the counters in host and firmware */
|
|
slsi_read_enhanced_arp_rx_count_by_lower_mac(sdev, dev, SLSI_PSID_UNIFI_ARP_DETECT_RESPONSE_COUNTER);
|
|
memset(&ndev_vif->enhanced_arp_stats, 0, sizeof(ndev_vif->enhanced_arp_stats));
|
|
memset(ndev_vif->enhanced_arp_host_tag, 0, sizeof(ndev_vif->enhanced_arp_host_tag));
|
|
ndev_vif->enhanced_arp_detect_enabled = true;
|
|
result = slsi_mlme_arp_detect_request(sdev, dev, FAPI_ACTION_START, ndev_vif->target_ip_addr);
|
|
} else { /* stop enhanced arp detect */
|
|
ndev_vif->enhanced_arp_detect_enabled = false;
|
|
result = slsi_mlme_arp_detect_request(sdev, dev, FAPI_ACTION_STOP, ndev_vif->target_ip_addr);
|
|
}
|
|
|
|
kfree(ioctl_args);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return result;
|
|
}
|
|
|
|
static int slsi_enhanced_arp_get_stats(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int r = 0;
|
|
int len = 0;
|
|
|
|
r = slsi_read_enhanced_arp_rx_count_by_lower_mac(sdev, dev, SLSI_PSID_UNIFI_ARP_DETECT_RESPONSE_COUNTER);
|
|
|
|
if (r == 0) {
|
|
len = snprintf(command, buf_len, "%d %d %d %d %d %d %d %d %d %d",
|
|
ndev_vif->enhanced_arp_stats.arp_req_count_from_netdev,
|
|
ndev_vif->enhanced_arp_stats.arp_req_count_to_lower_mac,
|
|
ndev_vif->enhanced_arp_stats.arp_req_rx_count_by_lower_mac,
|
|
ndev_vif->enhanced_arp_stats.arp_req_count_tx_success,
|
|
ndev_vif->enhanced_arp_stats.arp_rsp_rx_count_by_lower_mac,
|
|
ndev_vif->enhanced_arp_stats.arp_rsp_rx_count_by_upper_mac,
|
|
ndev_vif->enhanced_arp_stats.arp_rsp_count_to_netdev,
|
|
ndev_vif->enhanced_arp_stats.arp_rsp_count_out_of_order_drop,
|
|
0, /*ap_link_active not supported, set as 0*/
|
|
ndev_vif->enhanced_arp_stats.is_duplicate_addr_detected);
|
|
SLSI_DBG2(sdev, SLSI_CFG80211, "Enhanced ARP Stats: %s\n", command);
|
|
}
|
|
|
|
/*clear all the counters*/
|
|
memset(&ndev_vif->enhanced_arp_stats, 0, sizeof(ndev_vif->enhanced_arp_stats));
|
|
|
|
return len;
|
|
}
|
|
#endif
|
|
|
|
static int slsi_ioctl_auto_chan_write(struct net_device *dev, char *command, int cmd_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
int ret = 0;
|
|
|
|
ret = slsi_auto_chan_write(dev, command, cmd_len);
|
|
ndev_vif->acs = true;
|
|
return ret;
|
|
}
|
|
|
|
#ifdef CONFIG_SCSC_WLAN_HANG_TEST
|
|
static int slsi_ioctl_test_force_hang(struct net_device *dev, char *command, int cmd_len)
|
|
{
|
|
return slsi_test_send_hanged_vendor_event(dev);
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_SCSC_WLAN_LOW_LATENCY_MODE
|
|
static int slsi_ioctl_set_latency_mode(struct net_device *dev, char *command, int cmd_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int latency_mode = 0;
|
|
int ret = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, cmd_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &latency_mode)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
ret = -EINVAL;
|
|
} else {
|
|
if (latency_mode < 0 || latency_mode > 2) {
|
|
SLSI_ERR(sdev, "Invalid latency_mode: '%s'\n", ioctl_args->args[0]);
|
|
ret = -EINVAL;
|
|
} else {
|
|
ret = slsi_set_latency_mode(dev, latency_mode, cmd_len);
|
|
}
|
|
}
|
|
kfree(ioctl_args);
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
static int slsi_ioctl_set_latency_crt_data(struct net_device *dev, char *command, int cmd_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int latency_mode = 0;
|
|
int ret = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, cmd_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &latency_mode)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
ret = -EINVAL;
|
|
} else {
|
|
if (latency_mode < 0 || latency_mode > 3) {
|
|
SLSI_ERR(sdev, "Invalid latency_crt_data: '%s'\n", ioctl_args->args[0]);
|
|
ret = -EINVAL;
|
|
} else {
|
|
ret = slsi_set_latency_crt_data(dev, latency_mode);
|
|
}
|
|
}
|
|
kfree(ioctl_args);
|
|
return ret;
|
|
}
|
|
|
|
#ifndef SLSI_TEST_DEV
|
|
static int slsi_ioctl_driver_bug_dump(struct net_device *dev, char *command, int cmd_len)
|
|
{
|
|
int ret = 0;
|
|
|
|
slsi_dump_stats(dev);
|
|
#ifdef CONFIG_SCSC_LOG_COLLECTION
|
|
scsc_log_collector_schedule_collection(SCSC_LOG_DUMPSTATE, SCSC_LOG_DUMPSTATE_REASON_DRIVERDEBUGDUMP);
|
|
#else
|
|
#ifndef SLSI_TEST_DEV
|
|
#if IS_ENABLED(CONFIG_SCSC_INDEPENDENT_SUBSYSTEM)
|
|
SLSI_NET_INFO(dev, "SCSC_LOG_COLLECTION not enabled. Sable will not be triggered\n");
|
|
#else
|
|
ret = mx140_log_dump();
|
|
#endif
|
|
#endif
|
|
#endif
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_SCSC_WLAN_NUM_ANTENNAS
|
|
static int slsi_ioctl_get_num_antennas(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int num_antennas = 0;
|
|
int res = 0;
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
res = slsi_mlme_get_num_antennas(sdev, dev, &num_antennas);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
if (res)
|
|
return res;
|
|
|
|
res = snprintf(command, buf_len, "%d\n", num_antennas);
|
|
return res;
|
|
}
|
|
|
|
static int slsi_ioctl_set_num_antennas(struct net_device *dev, char *command, int cmd_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int num_of_antennas;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int ret = 0;
|
|
int frame_type = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, cmd_len, 2);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &num_of_antennas)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
ret = -EINVAL;
|
|
} else {
|
|
/* We cannot lock in slsi_set_num_antennas as
|
|
* this is also called in slsi_start_ap with netdev_vif lock.
|
|
*/
|
|
if (ioctl_args->arg_count == 2) {
|
|
if (!slsi_str_to_int(ioctl_args->args[1], &frame_type)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[1]);
|
|
ret = -EINVAL;
|
|
goto exit;
|
|
}
|
|
frame_type += 1;
|
|
}
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
ret = slsi_mlme_set_num_antennas(dev, num_of_antennas, frame_type);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
}
|
|
exit:
|
|
kfree(ioctl_args);
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
static int slsi_elna_bypass(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int mib_value = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &mib_value)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
kfree(ioctl_args);
|
|
if (mib_value != 0 && mib_value != 1) {
|
|
SLSI_ERR(sdev, "Invalid LNA control: '%d'\n", mib_value);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
if (ndev_vif->iftype == NL80211_IFTYPE_STATION && ndev_vif->sta.vif_status != SLSI_VIF_STATUS_CONNECTED) {
|
|
SLSI_NET_ERR(dev, "sta is not in connected state\n");
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return -EPERM;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
return slsi_set_uint_mib(sdev, NULL, SLSI_PSID_UNIFI_LNA_CONTROL_ENABLED, mib_value);
|
|
}
|
|
|
|
static int slsi_elna_bypass_int(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int mib_value = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &mib_value)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
kfree(ioctl_args);
|
|
if (mib_value < 0 || mib_value > 65535) {
|
|
SLSI_ERR(sdev, "Invalid LNA Eval Intervel: '%d'\n", mib_value);
|
|
return -EINVAL;
|
|
}
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
if (ndev_vif->iftype == NL80211_IFTYPE_STATION && ndev_vif->sta.vif_status != SLSI_VIF_STATUS_CONNECTED) {
|
|
SLSI_NET_ERR(dev, "sta is not in connected state\n");
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return -EPERM;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
return slsi_set_uint_mib(sdev, NULL, SLSI_PSID_UNIFI_LNA_CONTROL_EVALUATION_INTERVAL, mib_value);
|
|
}
|
|
|
|
static int slsi_set_dwell_time(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
int passive_time = 0;
|
|
int home_time = 0;
|
|
int scan_channel_time = 0;
|
|
int home_away_time = 0;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int ret = 0;
|
|
int reset = 1;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 4);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &passive_time)) {
|
|
SLSI_ERR(sdev, "Invalid string passive_time: '%s'\n", ioctl_args->args[0]);
|
|
ret = -EINVAL;
|
|
} else if (passive_time < 0 || passive_time > 0xFFFF) {
|
|
SLSI_ERR(sdev, "Invalid passive_time value: '%d'\n", passive_time);
|
|
ret = -EINVAL;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[1], &home_time)) {
|
|
SLSI_ERR(sdev, "Invalid string home_time: '%s'\n", ioctl_args->args[1]);
|
|
ret = -EINVAL;
|
|
} else if (home_time < 0 || home_time > 0xFFFF) {
|
|
SLSI_ERR(sdev, "Invalid home_time value: '%d'\n", home_time);
|
|
ret = -EINVAL;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[2], &scan_channel_time)) {
|
|
SLSI_ERR(sdev, "Invalid string scan_channel_time: '%s'\n", ioctl_args->args[2]);
|
|
ret = -EINVAL;
|
|
} else if (scan_channel_time < 0 || scan_channel_time > 0xFFFF) {
|
|
SLSI_ERR(sdev, "Invalid scan_channel_time value: '%d'\n", scan_channel_time);
|
|
ret = -EINVAL;
|
|
}
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[3], &home_away_time)) {
|
|
SLSI_ERR(sdev, "Invalid string scan_channel_time: '%s'\n", ioctl_args->args[3]);
|
|
ret = -EINVAL;
|
|
} else if (home_away_time < 0 || home_away_time > 0xFFFF) {
|
|
SLSI_ERR(sdev, "Invalid scan_channel_time value: '%d'\n", home_away_time);
|
|
ret = -EINVAL;
|
|
}
|
|
|
|
if (ret != 0)
|
|
goto exit;
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
sdev->home_away_time = home_away_time;
|
|
sdev->home_time = home_time;
|
|
sdev->max_channel_time = scan_channel_time;
|
|
sdev->max_channel_passive_time = passive_time;
|
|
/* Set all 4 bits*/
|
|
if (home_away_time != 0 && home_time != 0 && scan_channel_time != 0 && passive_time != 0)
|
|
sdev->latency_param_mask = LATENCY_ALL_SET_MASK;
|
|
else
|
|
reset = 0;
|
|
ret = slsi_set_low_latency_params(dev, reset);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
exit:
|
|
kfree(ioctl_args);
|
|
return ret;
|
|
}
|
|
|
|
static int slsi_max_dtim_suspend(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int mib_value = 0;
|
|
int ret = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &mib_value)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
kfree(ioctl_args);
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
if (ndev_vif->iftype == NL80211_IFTYPE_STATION && ndev_vif->sta.vif_status != SLSI_VIF_STATUS_CONNECTED) {
|
|
SLSI_NET_ERR(dev, "sta is not in connected state\n");
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return -EPERM;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
if (mib_value < 0 || mib_value > 1) {
|
|
SLSI_ERR(sdev, "Invalid Max DTIM Suspend: '%d'\n", mib_value);
|
|
return -EINVAL;
|
|
}
|
|
if (mib_value == 0) {
|
|
sdev->max_dtim_recv = true;
|
|
} else if (mib_value == 1) {
|
|
sdev->max_dtim_recv = false;
|
|
ret = slsi_set_uint_mib(sdev, NULL, SLSI_PSID_UNIFI_USE_HOST_LISTEN_INTERVAL, 0);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int slsi_set_dtim_suspend(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
int mib_value = 0;
|
|
int ret = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (!slsi_str_to_int(ioctl_args->args[0], &mib_value)) {
|
|
SLSI_ERR(sdev, "Invalid string: '%s'\n", ioctl_args->args[0]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
kfree(ioctl_args);
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
if (ndev_vif->iftype == NL80211_IFTYPE_STATION && ndev_vif->sta.vif_status != SLSI_VIF_STATUS_CONNECTED) {
|
|
SLSI_NET_ERR(dev, "sta is not in connected state\n");
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return -EPERM;
|
|
}
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
|
|
if (!sdev->max_dtim_recv) {
|
|
SLSI_ERR(sdev, "Max DTIM Suspend = 0 not received\n");
|
|
return -EPERM;
|
|
}
|
|
|
|
sdev->max_dtim_recv = false;
|
|
|
|
if (mib_value < 0) {
|
|
SLSI_ERR(sdev, "Invalid Set DTIM Suspend val: '%d'\n", mib_value);
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = slsi_set_uint_mib(sdev, NULL, SLSI_PSID_UNIFI_USE_HOST_LISTEN_INTERVAL, mib_value);
|
|
return ret;
|
|
}
|
|
|
|
static int slsi_force_roaming_bssid(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
u8 bssid[6] = { 0 };
|
|
int channel;
|
|
int freq;
|
|
enum nl80211_band band = NL80211_BAND_2GHZ;
|
|
int ret = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 2);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (strlen(ioctl_args->args[0]) != 17) {
|
|
SLSI_ERR(sdev, "Invalid MAC address length :%d\n", (int)strlen(ioctl_args->args[0]));
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
slsi_machexstring_to_macarray(ioctl_args->args[0], bssid);
|
|
if (!slsi_str_to_int(ioctl_args->args[1], &channel)) {
|
|
SLSI_ERR(sdev, "Invalid channel string: '%s'\n", ioctl_args->args[1]);
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
kfree(ioctl_args);
|
|
SLSI_NET_DBG1(dev, SLSI_NETDEV, "Force Roam: " MACSTR " Chan: %d\n",
|
|
MAC2STR(bssid), channel);
|
|
|
|
/* Check in 4 blacklists */
|
|
if (slsi_is_bssid_in_blacklist(sdev, dev, bssid) ||
|
|
slsi_is_bssid_in_hal_blacklist(dev, bssid) ||
|
|
slsi_is_bssid_in_ioctl_blacklist(dev, bssid)) {
|
|
SLSI_ERR(sdev, "Requested BSSID is in blacklist\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (channel < 1 || channel > 165) {
|
|
SLSI_ERR(sdev, "Invalid channel : %d\n", channel);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (channel > 14)
|
|
band = NL80211_BAND_5GHZ;
|
|
freq = (u16)ieee80211_channel_to_frequency(channel, band);
|
|
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
ret = slsi_mlme_roam(sdev, dev, bssid, freq);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return ret;
|
|
}
|
|
|
|
static int slsi_roaming_blacklist_add(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
u8 bssid[6] = { 0 };
|
|
int ret = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (strlen(ioctl_args->args[0]) != 17) {
|
|
SLSI_ERR(sdev, "Invalid MAC address length :%d\n", (int)strlen(ioctl_args->args[0]));
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
slsi_machexstring_to_macarray(ioctl_args->args[0], bssid);
|
|
kfree(ioctl_args);
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
/* Check if BSSID is already present in list */
|
|
if (slsi_is_bssid_in_ioctl_blacklist(dev, bssid)) {
|
|
SLSI_ERR(sdev, "Requested BSSID already in blacklist\n");
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return ret;
|
|
}
|
|
ret = slsi_add_ioctl_blacklist(sdev, dev, bssid);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return ret;
|
|
}
|
|
|
|
static int slsi_roaming_blacklist_remove(struct net_device *dev, char *command, int buf_len)
|
|
{
|
|
struct netdev_vif *ndev_vif = netdev_priv(dev);
|
|
struct slsi_dev *sdev = ndev_vif->sdev;
|
|
struct slsi_ioctl_args *ioctl_args = NULL;
|
|
u8 bssid[6] = { 0 };
|
|
int ret = 0;
|
|
|
|
ioctl_args = slsi_get_private_command_args(command, buf_len, 1);
|
|
SLSI_VERIFY_IOCTL_ARGS(sdev, ioctl_args);
|
|
|
|
if (strlen(ioctl_args->args[0]) != 17) {
|
|
SLSI_ERR(sdev, "Invalid MAC address length :%d\n", (int)strlen(ioctl_args->args[0]));
|
|
kfree(ioctl_args);
|
|
return -EINVAL;
|
|
}
|
|
|
|
slsi_machexstring_to_macarray(ioctl_args->args[0], bssid);
|
|
kfree(ioctl_args);
|
|
SLSI_MUTEX_LOCK(ndev_vif->vif_mutex);
|
|
ret = slsi_remove_bssid_blacklist(sdev, dev, bssid);
|
|
SLSI_MUTEX_UNLOCK(ndev_vif->vif_mutex);
|
|
return ret;
|
|
}
|
|
|
|
static int slsi_ioctl_cmd_success(struct net_device *dev, char *command, int cmd_len)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
struct slsi_ioctl_fn {
|
|
char *name;
|
|
int (*fn)(struct net_device *dev, char *command, int cmd_len);
|
|
};
|
|
|
|
static const struct slsi_ioctl_fn slsi_ioctl_fn_table[] = {
|
|
{ CMD_SETSUSPENDMODE, slsi_set_suspend_mode },
|
|
{ CMD_SETJOINPREFER, slsi_update_rssi_boost },
|
|
{ CMD_RXFILTERADD, slsi_rx_filter_add },
|
|
{ CMD_RXFILTERREMOVE, slsi_rx_filter_remove },
|
|
{ CMD_SETBANDWIDTH, slsi_set_bandwidth }, /* Changing the BW in regulatory database*/
|
|
{ CMD_SETSCANHOMEAWAYTIME_LEGACY, slsi_set_home_away_time_legacy },
|
|
{ CMD_SETSCANHOMETIME_LEGACY, slsi_set_home_time_legacy },
|
|
{ CMD_SETSCANCHANNELTIME_LEGACY, slsi_set_channel_time_legacy },
|
|
{ CMD_SETSCANPASSIVETIME_LEGACY, slsi_set_passive_time_legacy },
|
|
{ CMD_SET_TID, slsi_set_tid },
|
|
{ CMD_SET_BSS_CHANNEL_WIDTH, slsi_set_bss_bandwidth }, /* Changing the Tx BW only, without notifying the AP */
|
|
#ifdef CONFIG_SCSC_WLAN_WIFI_SHARING
|
|
#if !defined(CONFIG_SCSC_WLAN_MHS_STATIC_INTERFACE) || (defined(SCSC_SEP_VERSION) && SCSC_SEP_VERSION < 9)
|
|
{ CMD_INTERFACE_CREATE, slsi_create_interface },
|
|
{ CMD_INTERFACE_DELETE, slsi_delete_interface },
|
|
#endif
|
|
{ CMD_SET_INDOOR_CHANNELS, slsi_set_wifisharing_permitted_channels },
|
|
{ CMD_GET_INDOOR_CHANNELS, slsi_get_indoor_channels },
|
|
#endif
|
|
{ CMD_SETCOUNTRYREV, slsi_set_country_rev },
|
|
{ CMD_GETCOUNTRYREV, slsi_get_country_rev },
|
|
{ CMD_SETROAMBAND, slsi_ioctl_set_roam_band },
|
|
{ CMD_SETBAND, slsi_ioctl_set_band },
|
|
{ CMD_GETROAMBAND, slsi_ioctl_get_roam_band },
|
|
{ CMD_GETBAND, slsi_ioctl_get_band },
|
|
{ CMD_FACTORY_SETBAND, slsi_factory_freq_band_write },
|
|
{ CMD_SETROAMTRIGGER_LEGACY, slsi_legacy_roam_trigger_write },
|
|
{ CMD_GETROAMTRIGGER_LEGACY, slsi_legacy_roam_scan_trigger_read },
|
|
{ CMD_REASSOC_LEGACY, slsi_reassoc_write_legacy },
|
|
{ CMD_REASSOC_FREQUENCY_LEGACY, slsi_reassoc_frequency_write_legacy },
|
|
{ CMD_ADDROAMSCANCHANNELS_LEGACY, slsi_roam_add_scan_channels_legacy },
|
|
{ CMD_ADDROAMSCANFREQUENCIES_LEGACY, slsi_roam_add_scan_frequencies_legacy },
|
|
{ CMD_GETROAMSCANFREQUENCIES_LEGACY, slsi_roam_scan_frequencies_read_legacy },
|
|
{ CMD_GETROAMSCANCHANNELS_LEGACY, slsi_roam_scan_channels_read_legacy },
|
|
#ifdef CONFIG_SCSC_WLAN_WES_NCHO
|
|
{ CMD_SETROAMTRIGGER, slsi_roam_scan_trigger_write },
|
|
{ CMD_GETROAMTRIGGER, slsi_roam_scan_trigger_read },
|
|
{ CMD_SETROAMDELTA, slsi_roam_delta_trigger_write },
|
|
{ CMD_GETROAMDELTA, slsi_roam_delta_trigger_read },
|
|
{ CMD_SETROAMSCANPERIOD, slsi_cached_channel_scan_period_write },
|
|
{ CMD_GETROAMSCANPERIOD, slsi_cached_channel_scan_period_read },
|
|
{ CMD_SETFULLROAMSCANPERIOD, slsi_full_roam_scan_period_write },
|
|
{ CMD_GETFULLROAMSCANPERIOD, slsi_full_roam_scan_period_read },
|
|
{ CMD_SETSCANCHANNELTIME, slsi_roam_scan_max_active_channel_time_write },
|
|
{ CMD_GETSCANCHANNELTIME, slsi_roam_scan_max_active_channel_time_read },
|
|
{ CMD_SETSCANNPROBES, slsi_roam_scan_probe_interval_write },
|
|
{ CMD_GETSCANNPROBES, slsi_roam_scan_probe_interval_read },
|
|
{ CMD_SETROAMMODE, slsi_roam_mode_write },
|
|
{ CMD_GETROAMMODE, slsi_roam_mode_read },
|
|
{ CMD_SETROAMINTRABAND, slsi_roam_scan_band_write },
|
|
{ CMD_GETROAMINTRABAND, slsi_roam_scan_band_read },
|
|
{ CMD_SETROAMSCANCONTROL, slsi_roam_scan_control_write },
|
|
{ CMD_GETROAMSCANCONTROL, slsi_roam_scan_control_read },
|
|
{ CMD_SETSCANHOMETIME, slsi_roam_scan_home_time_write },
|
|
{ CMD_GETSCANHOMETIME, slsi_roam_scan_home_time_read },
|
|
{ CMD_SETSCANHOMEAWAYTIME, slsi_roam_scan_home_away_time_write },
|
|
{ CMD_GETSCANHOMEAWAYTIME, slsi_roam_scan_home_away_time_read },
|
|
{ CMD_SETOKCMODE, slsi_okc_mode_write },
|
|
{ CMD_GETOKCMODE, slsi_okc_mode_read },
|
|
{ CMD_SETWESMODE, slsi_wes_mode_write },
|
|
{ CMD_GETWESMODE, slsi_wes_mode_read },
|
|
{ CMD_SETROAMSCANCHANNELS, slsi_roam_scan_channels_write },
|
|
{ CMD_SETROAMSCANFREQUENCIES, slsi_roam_scan_frequencies_write },
|
|
{ CMD_GETROAMSCANCHANNELS, slsi_roam_scan_channels_read },
|
|
{ CMD_GETROAMSCANFREQUENCIES, slsi_roam_scan_frequencies_read },
|
|
{ CMD_ADDROAMSCANCHANNELS, slsi_roam_add_scan_channels },
|
|
{ CMD_ADDROAMSCANFREQUENCIES, slsi_roam_add_scan_frequencies },
|
|
{ CMD_GETNCHOMODE, slsi_get_ncho_mode },
|
|
{ CMD_SETNCHOMODE, slsi_set_ncho_mode },
|
|
{ CMD_SETDFSSCANMODE, slsi_set_dfs_scan_mode },
|
|
{ CMD_GETDFSSCANMODE, slsi_get_dfs_scan_mode },
|
|
{ CMD_REASSOC_FREQUENCY, slsi_reassoc_frequency_write },
|
|
{ CMD_REASSOC, slsi_reassoc_write },
|
|
{ CMD_SETROAMOFFLOAD, slsi_roam_mode_write },
|
|
{ CMD_SETROAMOFFLAPLIST, slsi_roam_offload_ap_list },
|
|
#endif
|
|
{ CMD_SET_PMK, slsi_set_pmk },
|
|
{ CMD_HAPD_GET_CHANNEL, slsi_auto_chan_read },
|
|
{ CMD_SET_SAP_CHANNEL_LIST, slsi_ioctl_auto_chan_write },
|
|
{ CMD_SENDACTIONFRAME, slsi_send_action_frame },
|
|
{ CMD_CERTSENDACTIONFRAME, slsi_send_action_frame_cert },
|
|
#ifdef SLSI_TEST_DEV
|
|
{ CMD_GASSENDACTIONFRAME, slsi_send_action_frame_ut },
|
|
#endif
|
|
{ CMD_HAPD_MAX_NUM_STA, slsi_setting_max_sta_write },
|
|
{ CMD_COUNTRY, slsi_country_write },
|
|
#if defined(CONFIG_SLSI_WLAN_STA_FWD_BEACON) && (defined(SCSC_SEP_VERSION) && SCSC_SEP_VERSION >= 10)
|
|
{ CMD_BEACON_RECV, slsi_forward_beacon },
|
|
#endif
|
|
{ CMD_SETAPP2PWPSIE, slsi_set_ap_p2p_wps_ie },
|
|
{ CMD_P2PSETPS, slsi_set_p2p_oppps },
|
|
{ CMD_P2PSETNOA, slsi_p2p_set_noa_params },
|
|
{ CMD_P2PECSA, slsi_p2p_ecsa },
|
|
{ CMD_P2PLOSTART, slsi_p2p_lo_start },
|
|
{ CMD_P2PLOSTOP, slsi_p2p_lo_stop },
|
|
{ CMD_SET_TX_POWER_CALLING, slsi_set_tx_power_calling },
|
|
{ CMD_SET_TX_POWER_SUB6_BAND, slsi_set_tx_power_sub6_band },
|
|
{ CMD_POWER_MEASUREMENT_START, slsi_start_power_measurement_detection },
|
|
{ CMD_GETREGULATORY, slsi_get_regulatory },
|
|
#ifdef CONFIG_SCSC_WLAN_HANG_TEST
|
|
{ CMD_TESTFORCEHANG, slsi_ioctl_test_force_hang },
|
|
#endif
|
|
{ CMD_SET_FCC_CHANNEL, slsi_set_fcc_channel },
|
|
{ CMD_FAKEMAC, slsi_fake_mac_write },
|
|
{ CMD_GETBSSRSSI, slsi_get_bss_rssi },
|
|
{ CMD_GETBSSINFO, slsi_get_bss_info },
|
|
{ CMD_GETSTAINFO, slsi_get_sta_info },
|
|
{ CMD_GETASSOCREJECTINFO, slsi_get_assoc_reject_info },
|
|
#ifdef CONFIG_SCSC_WLAN_LOW_LATENCY_MODE
|
|
{ CMD_SET_LATENCY_MODE, slsi_ioctl_set_latency_mode },
|
|
{ CMD_SET_POWER_MGMT, slsi_set_power_mode },
|
|
#endif
|
|
{ CMD_SET_LATENCY_CRT_DATA, slsi_ioctl_set_latency_crt_data },
|
|
{ CMD_SET_DISCONNECT_IES, slsi_set_disconnect_ies },
|
|
#ifdef CONFIG_SCSC_WLAN_STA_ENHANCED_ARP_DETECT
|
|
{ CMD_SET_ENHANCED_ARP_TARGET, slsi_enhanced_arp_start_stop },
|
|
{ CMD_GET_ENHANCED_ARP_COUNTS, slsi_enhanced_arp_get_stats },
|
|
#endif
|
|
{ CMD_RXFILTERSTART, slsi_ioctl_cmd_success },
|
|
{ CMD_RXFILTERSTOP, slsi_ioctl_cmd_success },
|
|
{ CMD_BTCOEXMODE, slsi_ioctl_cmd_success },
|
|
{ CMD_BTCOEXSCAN_START, slsi_ioctl_cmd_success },
|
|
{ CMD_BTCOEXSCAN_STOP, slsi_ioctl_cmd_success },
|
|
{ CMD_MIRACAST, slsi_ioctl_cmd_success },
|
|
#ifndef SLSI_TEST_DEV
|
|
{ CMD_DRIVERDEBUGDUMP, slsi_ioctl_driver_bug_dump },
|
|
{ CMD_DRIVERDEBUGCOMMAND, slsi_ioctl_driver_bug_dump },
|
|
#endif
|
|
#ifdef CONFIG_SCSC_WLAN_ENHANCED_PKT_FILTER
|
|
{ CMD_ENHANCED_PKT_FILTER, slsi_set_enhanced_pkt_filter },
|
|
#endif
|
|
#ifdef CONFIG_SCSC_WLAN_NUM_ANTENNAS
|
|
{ CMD_SET_NUM_ANTENNAS, slsi_ioctl_set_num_antennas },
|
|
{ CMD_GET_NUM_ANTENNAS, slsi_ioctl_get_num_antennas },
|
|
#endif
|
|
#ifdef CONFIG_SCSC_WLAN_MAX_LINK_SPEED
|
|
{ CMD_GET_MAX_LINK_SPEED, slsi_get_linkspeed },
|
|
#endif
|
|
|
|
#ifdef CONFIG_SCSC_WLAN_DYNAMIC_ITO
|
|
{ CMD_SET_ITO, slsi_set_ito },
|
|
{ CMD_ENABLE_ITO, slsi_enable_ito },
|
|
#endif
|
|
{ CMD_GET_CU, slsi_get_cu },
|
|
{ CMD_ELNA_BYPASS_INT, slsi_elna_bypass_int },
|
|
{ CMD_ELNA_BYPASS, slsi_elna_bypass },
|
|
{ CMD_SET_DWELL_TIME, slsi_set_dwell_time },
|
|
{ CMD_SET_DTIM_IN_SUSPEND, slsi_set_dtim_suspend },
|
|
{ CMD_MAX_DTIM_IN_SUSPEND, slsi_max_dtim_suspend },
|
|
{ CMD_FORCE_ROAMING_BSSID, slsi_force_roaming_bssid },
|
|
{ CMD_ROAMING_BLACKLIST_ADD, slsi_roaming_blacklist_add },
|
|
{ CMD_ROAMING_BLACKLIST_REMOVE, slsi_roaming_blacklist_remove }
|
|
};
|
|
|
|
static int slsi_ioctl_fn_lookup(char *command, int len)
|
|
{
|
|
int i = 0;
|
|
const struct slsi_ioctl_fn *p = NULL;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(slsi_ioctl_fn_table); i++) {
|
|
p = &slsi_ioctl_fn_table[i];
|
|
if (p->name) {
|
|
if (strlen(p->name) < len) {
|
|
if (!strncasecmp(command, p->name, len))
|
|
return i;
|
|
} else {
|
|
if (!strncasecmp(command, p->name, strlen(p->name)))
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int slsi_do_ioctl(struct net_device *dev, char *command, int cmd_len)
|
|
{
|
|
int ret = 0;
|
|
int index;
|
|
int len = 0;
|
|
char *pos = command;
|
|
|
|
pos = strchr(pos, ' ');
|
|
if (!pos) {
|
|
pos = command;
|
|
pos = strchr(pos, '\0');
|
|
if (!pos)
|
|
return -ENOTSUPP;
|
|
}
|
|
|
|
len = pos - command;
|
|
index = slsi_ioctl_fn_lookup(command, len);
|
|
|
|
if (index < 0)
|
|
return -ENOTSUPP;
|
|
|
|
if (slsi_ioctl_fn_table[index].fn)
|
|
ret = slsi_ioctl_fn_table[index].fn(dev, command, cmd_len);
|
|
else
|
|
ret = -ENOTSUPP;
|
|
|
|
return ret;
|
|
}
|
|
|
|
int slsi_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
|
|
{
|
|
#define MAX_LEN_PRIV_COMMAND 4096 /*This value is the max reply size set in supplicant*/
|
|
struct android_wifi_priv_cmd priv_cmd;
|
|
int ret = 0;
|
|
u8 *command = NULL;
|
|
|
|
if (!dev) {
|
|
ret = -ENODEV;
|
|
goto exit;
|
|
}
|
|
|
|
if (!rq->ifr_data) {
|
|
ret = -EINVAL;
|
|
goto exit;
|
|
}
|
|
if (copy_from_user((void *)&priv_cmd, (void *)rq->ifr_data, sizeof(struct android_wifi_priv_cmd))) {
|
|
ret = -EFAULT;
|
|
SLSI_NET_ERR(dev, "ifr data failed\n");
|
|
goto exit;
|
|
}
|
|
|
|
if (priv_cmd.total_len > MAX_LEN_PRIV_COMMAND || priv_cmd.total_len < 0) {
|
|
ret = -EINVAL;
|
|
SLSI_NET_ERR(dev, "Length mismatch total_len = %d\n", priv_cmd.total_len);
|
|
goto exit;
|
|
}
|
|
command = kmalloc((priv_cmd.total_len + 1), GFP_KERNEL);
|
|
if (!command) {
|
|
ret = -ENOMEM;
|
|
SLSI_NET_ERR(dev, "No memory\n");
|
|
goto exit;
|
|
}
|
|
if (copy_from_user(command, priv_cmd.buf, priv_cmd.total_len)) {
|
|
ret = -EFAULT;
|
|
SLSI_NET_ERR(dev, "Buffer copy fail\n");
|
|
goto exit;
|
|
}
|
|
command[priv_cmd.total_len] = '\0';
|
|
|
|
if (strncasecmp(command, CMD_SET_PMK, strlen(CMD_SET_PMK)) == 0)
|
|
SLSI_INFO_NODEV("command: SET_PMK\n");
|
|
else
|
|
SLSI_INFO_NODEV("command: %.*s\n", priv_cmd.total_len, command);
|
|
|
|
ret = slsi_do_ioctl(dev, command, priv_cmd.total_len);
|
|
|
|
if (strncasecmp(command, CMD_SETROAMBAND, strlen(CMD_SETROAMBAND)) != 0 && strncasecmp(command, CMD_FACTORY_SETBAND, strlen(CMD_FACTORY_SETBAND)) != 0 && strncasecmp(command, CMD_SETBAND, strlen(CMD_SETBAND)) != 0 && copy_to_user(priv_cmd.buf, command, priv_cmd.total_len)) {
|
|
ret = -EFAULT;
|
|
SLSI_NET_ERR(dev, "Buffer copy fail\n");
|
|
}
|
|
|
|
exit:
|
|
kfree(command);
|
|
return ret;
|
|
}
|