blob: 750edef8b2c569f51a9563053093f4a26e8c3461 [file] [log] [blame]
/*
* Copyright (c) 2012-2018 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all
* copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/**========================================================================
\file wlan_hdd_hostapd.c
\brief WLAN Host Device Driver implementation
========================================================================*/
/**=========================================================================
EDIT HISTORY FOR FILE
This section contains comments describing changes made to the module.
Notice that changes are listed in reverse chronological order.
$Header:$ $DateTime: $ $Author: $
when who what, where, why
-------- --- --------------------------------------------------------
04/5/09 Shailender Created module.
06/03/10 js - Added support to hostapd driven deauth/disassoc/mic failure
==========================================================================*/
/*--------------------------------------------------------------------------
Include Files
------------------------------------------------------------------------*/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/wireless.h>
#include <linux/semaphore.h>
#include <linux/compat.h>
#include <linux/rtnetlink.h>
#include <vos_api.h>
#include <vos_sched.h>
#include <linux/etherdevice.h>
#include <wlan_hdd_includes.h>
#include <qc_sap_ioctl.h>
#include <wlan_hdd_hostapd.h>
#include <sapApi.h>
#include <sapInternal.h>
#include <wlan_qct_tl.h>
#include <wlan_hdd_softap_tx_rx.h>
#include <wlan_hdd_main.h>
#include <linux/netdevice.h>
#include <linux/mmc/sdio_func.h>
#include "wlan_nlink_common.h"
#include "wlan_btc_svc.h"
#include <bap_hdd_main.h>
#include "wlan_hdd_tdls.h"
#include "wlan_hdd_p2p.h"
#include "cfgApi.h"
#include "wniCfg.h"
#include <wlan_hdd_wowl.h>
#include "wlan_hdd_hostapd.h"
#include "wlan_hdd_request_manager.h"
#ifdef FEATURE_WLAN_CH_AVOID
#include "wcnss_wlan.h"
#endif /* FEATURE_WLAN_CH_AVOID */
#include "wlan_hdd_trace.h"
#include "vos_types.h"
#include "vos_trace.h"
#define IS_UP(_dev) \
(((_dev)->flags & (IFF_RUNNING|IFF_UP)) == (IFF_RUNNING|IFF_UP))
#define IS_UP_AUTO(_ic) \
(IS_UP((_ic)->ic_dev) && (_ic)->ic_roaming == IEEE80211_ROAMING_AUTO)
#define WE_WLAN_VERSION 1
#define WE_GET_STA_INFO_SIZE 30
/* WEXT limition: MAX allowed buf len for any *
* IW_PRIV_TYPE_CHAR is 2Kbytes *
*/
#define WE_SAP_MAX_STA_INFO 0x7FF
#define SAP_24GHZ_CH_COUNT (14)
#ifdef FEATURE_WLAN_CH_AVOID
/* Channle/Freqency table */
extern const tRfChannelProps rfChannels[NUM_RF_CHANNELS];
safeChannelType safeChannels[NUM_20MHZ_RF_CHANNELS] =
{
/*CH , SAFE, default safe */
{1 , VOS_TRUE}, //RF_CHAN_1,
{2 , VOS_TRUE}, //RF_CHAN_2,
{3 , VOS_TRUE}, //RF_CHAN_3,
{4 , VOS_TRUE}, //RF_CHAN_4,
{5 , VOS_TRUE}, //RF_CHAN_5,
{6 , VOS_TRUE}, //RF_CHAN_6,
{7 , VOS_TRUE}, //RF_CHAN_7,
{8 , VOS_TRUE}, //RF_CHAN_8,
{9 , VOS_TRUE}, //RF_CHAN_9,
{10 , VOS_TRUE}, //RF_CHAN_10,
{11 , VOS_TRUE}, //RF_CHAN_11,
{12 , VOS_TRUE}, //RF_CHAN_12,
{13 , VOS_TRUE}, //RF_CHAN_13,
{14 , VOS_TRUE}, //RF_CHAN_14,
{240, VOS_TRUE}, //RF_CHAN_240,
{244, VOS_TRUE}, //RF_CHAN_244,
{248, VOS_TRUE}, //RF_CHAN_248,
{252, VOS_TRUE}, //RF_CHAN_252,
{208, VOS_TRUE}, //RF_CHAN_208,
{212, VOS_TRUE}, //RF_CHAN_212,
{216, VOS_TRUE}, //RF_CHAN_216,
{36 , VOS_TRUE}, //RF_CHAN_36,
{40 , VOS_TRUE}, //RF_CHAN_40,
{44 , VOS_TRUE}, //RF_CHAN_44,
{48 , VOS_TRUE}, //RF_CHAN_48,
{52 , VOS_TRUE}, //RF_CHAN_52,
{56 , VOS_TRUE}, //RF_CHAN_56,
{60 , VOS_TRUE}, //RF_CHAN_60,
{64 , VOS_TRUE}, //RF_CHAN_64,
{100, VOS_TRUE}, //RF_CHAN_100,
{104, VOS_TRUE}, //RF_CHAN_104,
{108, VOS_TRUE}, //RF_CHAN_108,
{112, VOS_TRUE}, //RF_CHAN_112,
{116, VOS_TRUE}, //RF_CHAN_116,
{120, VOS_TRUE}, //RF_CHAN_120,
{124, VOS_TRUE}, //RF_CHAN_124,
{128, VOS_TRUE}, //RF_CHAN_128,
{132, VOS_TRUE}, //RF_CHAN_132,
{136, VOS_TRUE}, //RF_CHAN_136,
{140, VOS_TRUE}, //RF_CHAN_140,
{149, VOS_TRUE}, //RF_CHAN_149,
{153, VOS_TRUE}, //RF_CHAN_153,
{157, VOS_TRUE}, //RF_CHAN_157,
{161, VOS_TRUE}, //RF_CHAN_161,
{165, VOS_TRUE}, //RF_CHAN_165,
};
#endif /* FEATURE_WLAN_CH_AVOID */
/*---------------------------------------------------------------------------
* Function definitions
*-------------------------------------------------------------------------*/
/**---------------------------------------------------------------------------
\brief __hdd_hostapd_open() - HDD Open function for hostapd interface
This is called in response to ifconfig up
\param - dev Pointer to net_device structure
\return - 0 for success non-zero for failure
--------------------------------------------------------------------------*/
int __hdd_hostapd_open (struct net_device *dev)
{
hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
hdd_context_t *pHddCtx;
VOS_STATUS status;
v_BOOL_t in_standby = TRUE;
hdd_adapter_list_node_t *pAdapterNode = NULL, *pNext = NULL;
ENTER();
if (test_bit(DEVICE_IFACE_OPENED, &pAdapter->event_flags)) {
hddLog(VOS_TRACE_LEVEL_DEBUG, "%s: session already opened for the adapter",
__func__);
return 0;
}
pHddCtx = (hdd_context_t*)pAdapter->pHddCtx;
MTRACE(vos_trace(VOS_MODULE_ID_HDD, TRACE_CODE_HDD_OPEN_REQUEST,
pAdapter->sessionId, pAdapter->device_mode));
if (NULL == pHddCtx)
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
"%s: HDD context is Null", __func__);
return -ENODEV;
}
status = hdd_get_front_adapter ( pHddCtx, &pAdapterNode );
while ( (NULL != pAdapterNode) && (VOS_STATUS_SUCCESS == status) )
{
if (test_bit(DEVICE_IFACE_OPENED, &pAdapterNode->pAdapter->event_flags))
{
hddLog(VOS_TRACE_LEVEL_INFO, "%s: chip already out of standby",
__func__);
in_standby = FALSE;
break;
}
else
{
status = hdd_get_next_adapter ( pHddCtx, pAdapterNode, &pNext );
pAdapterNode = pNext;
}
}
if (TRUE == in_standby)
{
if (VOS_STATUS_SUCCESS != wlan_hdd_exit_lowpower(pHddCtx, pAdapter))
{
hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Failed to bring "
"wlan out of power save", __func__);
return -EINVAL;
}
}
status = hdd_init_ap_mode( pAdapter, false);
if( VOS_STATUS_SUCCESS != status ) {
hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Failed to create session for station mode",
__func__);
return -EINVAL;
}
set_bit(DEVICE_IFACE_OPENED, &pAdapter->event_flags);
//Turn ON carrier state
netif_carrier_on(dev);
//Enable all Tx queues
hddLog(VOS_TRACE_LEVEL_INFO, FL("Enabling queues"));
netif_tx_start_all_queues(dev);
EXIT();
return 0;
}
int hdd_hostapd_open (struct net_device *dev)
{
int ret;
vos_ssr_protect(__func__);
ret = __hdd_hostapd_open(dev);
vos_ssr_unprotect(__func__);
return ret;
}
/**---------------------------------------------------------------------------
\brief __hdd_hostapd_stop() - HDD stop function for hostapd interface
This is called in response to ifconfig down
\param - dev Pointer to net_device structure
\return - 0 for success non-zero for failure
--------------------------------------------------------------------------*/
int __hdd_hostapd_stop (struct net_device *dev)
{
hdd_adapter_t *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
int ret;
ENTER();
ret = wlan_hdd_validate_context(hdd_ctx);
if (0 != ret)
return ret;
hddLog(VOS_TRACE_LEVEL_INFO, FL("Disabling queues"));
//Stop all tx queues
netif_tx_disable(dev);
//Turn OFF carrier state
netif_carrier_off(dev);
if (test_bit(SME_SESSION_OPENED, &adapter->event_flags)) {
hdd_stop_adapter(hdd_ctx, adapter, VOS_TRUE);
hdd_deinit_adapter(hdd_ctx, adapter, TRUE);
}
clear_bit(DEVICE_IFACE_OPENED, &adapter->event_flags);
adapter->dev->wireless_handlers = NULL;
if (!hdd_is_cli_iface_up(hdd_ctx))
sme_ScanFlushResult(hdd_ctx->hHal, 0);
EXIT();
return 0;
}
int hdd_hostapd_stop (struct net_device *dev)
{
int ret;
vos_ssr_protect(__func__);
ret = __hdd_hostapd_stop(dev);
vos_ssr_unprotect(__func__);
return ret;
}
/**---------------------------------------------------------------------------
\brief __hdd_hostapd_uninit() - HDD uninit function
This is called during the netdev unregister to uninitialize all data
associated with the device
\param - dev Pointer to net_device structure
\return - void
--------------------------------------------------------------------------*/
static void __hdd_hostapd_uninit (struct net_device *dev)
{
hdd_adapter_t *pHostapdAdapter = netdev_priv(dev);
hdd_context_t *pHddCtx;
ENTER();
if (WLAN_HDD_ADAPTER_MAGIC != pHostapdAdapter->magic)
{
hddLog(VOS_TRACE_LEVEL_ERROR,
FL("Invalid magic"));
return;
}
pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter);
if (NULL == pHddCtx)
{
hddLog(VOS_TRACE_LEVEL_ERROR,
FL("NULL pHddCtx"));
return;
}
hdd_deinit_adapter(pHostapdAdapter->pHddCtx, pHostapdAdapter, TRUE);
/* after uninit our adapter structure will no longer be valid */
pHostapdAdapter->dev = NULL;
pHostapdAdapter->magic = 0;
EXIT();
}
static void hdd_hostapd_uninit (struct net_device *dev)
{
vos_ssr_protect(__func__);
__hdd_hostapd_uninit(dev);
vos_ssr_unprotect(__func__);
return;
}
/**============================================================================
@brief hdd_hostapd_hard_start_xmit() - Function registered with the Linux OS for
transmitting packets. There are 2 versions of this function. One that uses
locked queue and other that uses lockless queues. Both have been retained to
do some performance testing
@param skb : [in] pointer to OS packet (sk_buff)
@param dev : [in] pointer to Libra network device
@return : NET_XMIT_DROP if packets are dropped
: NET_XMIT_SUCCESS if packet is enqueued succesfully
===========================================================================*/
int hdd_hostapd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
return 0;
}
int __hdd_hostapd_change_mtu(struct net_device *dev, int new_mtu)
{
return 0;
}
int hdd_hostapd_change_mtu(struct net_device *dev, int new_mtu)
{
int ret;
vos_ssr_protect(__func__);
ret = __hdd_hostapd_change_mtu(dev, new_mtu);
vos_ssr_unprotect(__func__);
return ret;
}
static int hdd_hostapd_driver_command(hdd_adapter_t *pAdapter,
hdd_priv_data_t *priv_data)
{
tANI_U8 *command = NULL;
hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
hdd_scaninfo_t *pScanInfo = NULL;
int ret = 0;
int status;
/*
* Note that valid pointers are provided by caller
*/
ENTER();
if (priv_data->total_len <= 0 ||
priv_data->total_len > HOSTAPD_IOCTL_COMMAND_STRLEN_MAX)
{
/* below we allocate one more byte for command buffer.
* To avoid addition overflow total_len should be
* smaller than INT_MAX. */
hddLog(VOS_TRACE_LEVEL_ERROR, "%s: integer out of range len %d",
__func__, priv_data->total_len);
ret = -EFAULT;
goto exit;
}
status = wlan_hdd_validate_context(pHddCtx);
if (0 != status)
{
return status;
}
/* Allocate +1 for '\0' */
command = kmalloc((priv_data->total_len + 1), GFP_KERNEL);
if (!command)
{
hddLog(VOS_TRACE_LEVEL_ERROR, "%s: failed to allocate memory", __func__);
ret = -ENOMEM;
goto exit;
}
if (copy_from_user(command, priv_data->buf, priv_data->total_len))
{
ret = -EFAULT;
goto exit;
}
/* Make sure the command is NUL-terminated */
command[priv_data->total_len] = '\0';
hddLog(VOS_TRACE_LEVEL_INFO,
"***HOSTAPD*** : Received %s cmd from Wi-Fi GUI***", command);
if (strncmp(command, "P2P_SET_NOA", 11) == 0)
{
hdd_setP2pNoa(pAdapter->dev, command);
}
else if (strncmp(command, "P2P_SET_PS", 10) == 0)
{
hdd_setP2pOpps(pAdapter->dev, command);
}
#ifdef FEATURE_WLAN_BATCH_SCAN
else if (strncmp(command, "WLS_BATCHING", 12) == 0)
{
ret = hdd_handle_batch_scan_ioctl(pAdapter, priv_data, command);
}
#endif
else if (strncmp(command, "SET_SAP_CHANNEL_LIST", 20) == 0)
{
/*
* command should be a string having format
* SET_SAP_CHANNEL_LIST <num channels> <channels seperated by spaces>
*/
hddLog(VOS_TRACE_LEVEL_INFO,
"%s: Received Command to Set Preferred Channels for SAP",
__func__);
ret = sapSetPreferredChannel(command);
}
else if ( strncasecmp(command, "MIRACAST", 8) == 0 )
{
hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
tANI_U8 filterType = 0;
tANI_U8 *value;
ret = hdd_drv_cmd_validate(command, 8);
if (ret)
goto exit;
value = command + 9;
/* Convert the value from ascii to integer */
ret = kstrtou8(value, 10, &filterType);
if (ret < 0)
{
/* If the input value is greater than max value of datatype,
* then also kstrtou8 fails
*/
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: kstrtou8 failed range ", __func__);
ret = -EINVAL;
goto exit;
}
if ((filterType < WLAN_HDD_DRIVER_MIRACAST_CFG_MIN_VAL ) ||
(filterType > WLAN_HDD_DRIVER_MIRACAST_CFG_MAX_VAL))
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Accepted Values are 0 to 2. 0-Disabled, 1-Source,"
" 2-Sink ", __func__);
ret = -EINVAL;
goto exit;
}
//Filtertype value should be either 0-Disabled, 1-Source, 2-sink
pHddCtx->drvr_miracast = filterType;
pScanInfo = &pHddCtx->scan_info;
if (filterType && pScanInfo != NULL &&
pHddCtx->scan_info.mScanPending)
{
/*Miracast Session started. Abort Scan */
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"%s, Aborting Scan For Miracast",__func__);
hdd_abort_mac_scan(pHddCtx, pScanInfo->sessionId,
eCSR_SCAN_ABORT_DEFAULT);
}
hdd_tx_rx_pkt_cnt_stat_timer_handler(pHddCtx);
sme_SetMiracastMode(pHddCtx->hHal, pHddCtx->drvr_miracast);
}
else if (strncasecmp(command, "DISABLE_CA_EVENT", 16) == 0)
{
ret = hdd_drv_cmd_validate(command, 16);
if (ret)
goto exit;
ret = hdd_enable_disable_ca_event(pHddCtx, command, 16);
}
/*
* command should be a string having format
* SET_DISABLE_CHANNEL_LIST <num of channels>
* <channels separated by spaces>
*/
else if (strncmp(command, "SET_DISABLE_CHANNEL_LIST", 24) == 0) {
tANI_U8 *ptr = command;
ret = hdd_drv_cmd_validate(command, 24);
if (ret)
goto exit;
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
" Received Command to disable Channels for in %s",
__func__);
ret = hdd_parse_disable_chan_cmd(pAdapter, ptr);
}
else if (strncmp(command, "GET_DISABLE_CHANNEL_LIST", 24) == 0) {
char extra[128] = {0};
int len;
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
" Received Command to get disable Channels list %s",
__func__);
len = hdd_get_disable_ch_list(pHddCtx, extra, sizeof(extra));
if (len == 0) {
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
FL("disable channel list are not yet programed"));
ret = -EINVAL;
goto exit;
}
len = VOS_MIN(priv_data->total_len, len + 1);
if (copy_to_user(priv_data->buf, &extra, len)) {
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: failed to copy data to user buffer", __func__);
ret = -EFAULT;
goto exit;
}
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
FL("data:%s"), extra);
}
else {
MTRACE(vos_trace(VOS_MODULE_ID_HDD,
TRACE_CODE_HDD_UNSUPPORTED_IOCTL,
pAdapter->sessionId, 0));
hddLog(VOS_TRACE_LEVEL_WARN, FL("Unsupported GUI command %s"),
command);
}
exit:
if (command)
{
kfree(command);
}
EXIT();
return ret;
}
#ifdef CONFIG_COMPAT
static int hdd_hostapd_driver_compat_ioctl(hdd_adapter_t *pAdapter,
struct ifreq *ifr)
{
struct {
compat_uptr_t buf;
int used_len;
int total_len;
} compat_priv_data;
hdd_priv_data_t priv_data;
int ret = 0;
/*
* Note that pAdapter and ifr have already been verified by caller,
* and HDD context has also been validated
*/
if (copy_from_user(&compat_priv_data, ifr->ifr_data,
sizeof(compat_priv_data))) {
ret = -EFAULT;
goto exit;
}
priv_data.buf = compat_ptr(compat_priv_data.buf);
priv_data.used_len = compat_priv_data.used_len;
priv_data.total_len = compat_priv_data.total_len;
ret = hdd_hostapd_driver_command(pAdapter, &priv_data);
exit:
return ret;
}
#else /* CONFIG_COMPAT */
static int hdd_hostapd_driver_compat_ioctl(hdd_adapter_t *pAdapter,
struct ifreq *ifr)
{
/* will never be invoked */
return 0;
}
#endif /* CONFIG_COMPAT */
static int hdd_hostapd_driver_ioctl(hdd_adapter_t *pAdapter, struct ifreq *ifr)
{
hdd_priv_data_t priv_data;
int ret = 0;
/*
* Note that pAdapter and ifr have already been verified by caller,
* and HDD context has also been validated
*/
if (copy_from_user(&priv_data, ifr->ifr_data, sizeof(priv_data))) {
ret = -EFAULT;
} else {
ret = hdd_hostapd_driver_command(pAdapter, &priv_data);
}
return ret;
}
static int __hdd_hostapd_ioctl(struct net_device *dev,
struct ifreq *ifr, int cmd)
{
hdd_adapter_t *pAdapter;
hdd_context_t *pHddCtx;
int ret;
ENTER();
pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
if (NULL == pAdapter) {
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: HDD adapter context is Null", __func__);
ret = -ENODEV;
goto exit;
}
if (dev != pAdapter->dev) {
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: HDD adapter/dev inconsistency", __func__);
ret = -ENODEV;
goto exit;
}
if ((!ifr) || (!ifr->ifr_data)) {
ret = -EINVAL;
goto exit;
}
pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
ret = wlan_hdd_validate_context(pHddCtx);
if (ret) {
ret = -EBUSY;
goto exit;
}
switch (cmd) {
case (SIOCDEVPRIVATE + 1):
if (is_compat_task())
ret = hdd_hostapd_driver_compat_ioctl(pAdapter, ifr);
else
ret = hdd_hostapd_driver_ioctl(pAdapter, ifr);
break;
default:
hddLog(VOS_TRACE_LEVEL_ERROR, "%s: unknown ioctl %d",
__func__, cmd);
ret = -EINVAL;
break;
}
exit:
EXIT();
return ret;
}
static int hdd_hostapd_ioctl(struct net_device *dev,
struct ifreq *ifr, int cmd)
{
int ret;
vos_ssr_protect(__func__);
ret = __hdd_hostapd_ioctl(dev, ifr, cmd);
vos_ssr_unprotect(__func__);
return ret;
}
/**---------------------------------------------------------------------------
\brief __hdd_hostapd_set_mac_address() -
This function sets the user specified mac address using
the command ifconfig wlanX hw ether <mac adress>.
\param - dev - Pointer to the net device.
- addr - Pointer to the sockaddr.
\return - 0 for success, non zero for failure
--------------------------------------------------------------------------*/
static int __hdd_hostapd_set_mac_address(struct net_device *dev, void *addr)
{
struct sockaddr *psta_mac_addr = addr;
hdd_adapter_t *pAdapter, *adapter_temp;
hdd_context_t *pHddCtx;
int ret = 0, i;
v_MACADDR_t mac_addr;
ENTER();
pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
if (NULL == pAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL",__func__);
return -EINVAL;
}
pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
ret = wlan_hdd_validate_context(pHddCtx);
if (0 != ret)
return ret;
memcpy(&mac_addr, psta_mac_addr->sa_data, sizeof(mac_addr));
if(vos_is_macaddr_zero(&mac_addr)) {
hddLog(VOS_TRACE_LEVEL_ERROR, "Zero Mac address");
return -EINVAL;
}
if (vos_is_macaddr_broadcast(&mac_addr)) {
hddLog(VOS_TRACE_LEVEL_ERROR,"MAC is Broadcast");
return -EINVAL;
}
if (vos_is_macaddr_multicast(&mac_addr)) {
hddLog(VOS_TRACE_LEVEL_ERROR, "Multicast Mac address");
return -EINVAL;
}
adapter_temp = hdd_get_adapter_by_macaddr(pHddCtx, mac_addr.bytes);
if (adapter_temp) {
if (!strcmp(adapter_temp->dev->name, dev->name))
return 0;
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: WLAN Mac Addr: "
MAC_ADDRESS_STR, __func__,
MAC_ADDR_ARRAY(mac_addr.bytes));
return -EINVAL;
}
for (i = 0; i < VOS_MAX_CONCURRENCY_PERSONA; i++) {
if (!vos_mem_compare(&pAdapter->macAddressCurrent.bytes,
&pHddCtx->cfg_ini->intfMacAddr[i].bytes[0], VOS_MAC_ADDR_SIZE)) {
memcpy(&pHddCtx->cfg_ini->intfMacAddr[i].bytes[0], mac_addr.bytes,
VOS_MAC_ADDR_SIZE);
break;
}
}
memcpy(&pAdapter->macAddressCurrent, psta_mac_addr->sa_data, ETH_ALEN);
memcpy(dev->dev_addr, psta_mac_addr->sa_data, ETH_ALEN);
EXIT();
return 0;
}
static int hdd_hostapd_set_mac_address(struct net_device *dev, void *addr)
{
int ret;
vos_ssr_protect(__func__);
ret = __hdd_hostapd_set_mac_address(dev, addr);
vos_ssr_unprotect(__func__);
return ret;
}
void hdd_hostapd_inactivity_timer_cb(v_PVOID_t usrDataForCallback)
{
struct net_device *dev = (struct net_device *)usrDataForCallback;
v_BYTE_t we_custom_event[64];
union iwreq_data wrqu;
hdd_adapter_t *pHostapdAdapter;
hdd_context_t *pHddCtx;
#ifdef DISABLE_CONCURRENCY_AUTOSAVE
VOS_STATUS vos_status;
hdd_ap_ctx_t *pHddApCtx;
#endif /*DISABLE_CONCURRENCY_AUTOSAVE */
/* event_name space-delimiter driver_module_name */
/* Format of the event is "AUTO-SHUT.indication" " " "module_name" */
char * autoShutEvent = "AUTO-SHUT.indication" " " KBUILD_MODNAME;
int event_len = strlen(autoShutEvent) + 1; /* For the NULL at the end */
ENTER();
pHostapdAdapter = netdev_priv(dev);
if ((NULL == pHostapdAdapter) ||
(WLAN_HDD_ADAPTER_MAGIC != pHostapdAdapter->magic))
{
hddLog(LOGE, FL("invalid adapter: %pK"), pHostapdAdapter);
return;
}
pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter);
if (0 != (wlan_hdd_validate_context(pHddCtx)))
{
return;
}
#ifdef DISABLE_CONCURRENCY_AUTOSAVE
if (vos_concurrent_open_sessions_running())
{
/*
This timer routine is going to be called only when AP
persona is up.
If there are concurrent sessions running we do not want
to shut down the Bss.Instead we run the timer again so
that if Autosave is enabled next time and other session
was down only then we bring down AP
*/
pHddApCtx = WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter);
vos_status = vos_timer_start(
&pHddApCtx->hdd_ap_inactivity_timer,
(WLAN_HDD_GET_CTX(pHostapdAdapter))->cfg_ini->nAPAutoShutOff
* 1000);
if (!VOS_IS_STATUS_SUCCESS(vos_status))
{
hddLog(LOGE, FL("Failed to init AP inactivity timer"));
}
EXIT();
return;
}
#endif /*DISABLE_CONCURRENCY_AUTOSAVE */
memset(&we_custom_event, '\0', sizeof(we_custom_event));
memcpy(&we_custom_event, autoShutEvent, event_len);
memset(&wrqu, 0, sizeof(wrqu));
wrqu.data.length = event_len;
hddLog(LOG1, FL("Shutting down AP interface due to inactivity"));
wireless_send_event(dev, IWEVCUSTOM, &wrqu, (char *)we_custom_event);
EXIT();
}
VOS_STATUS hdd_change_mcc_go_beacon_interval(hdd_adapter_t *pHostapdAdapter)
{
v_CONTEXT_t pVosContext = (WLAN_HDD_GET_CTX(pHostapdAdapter))->pvosContext;
ptSapContext pSapCtx = NULL;
eHalStatus halStatus = eHAL_STATUS_FAILURE;
v_PVOID_t hHal = NULL;
VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_INFO_HIGH,
"%s: UPDATE Beacon Params", __func__);
if(VOS_STA_SAP_MODE == vos_get_conparam ( )){
pSapCtx = VOS_GET_SAP_CB(pVosContext);
if ( NULL == pSapCtx )
{
VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR,
"%s: Invalid SAP pointer from pvosGCtx", __func__);
return VOS_STATUS_E_FAULT;
}
hHal = VOS_GET_HAL_CB(pSapCtx->pvosGCtx);
if ( NULL == hHal ){
VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR,
"%s: Invalid HAL pointer from pvosGCtx", __func__);
return VOS_STATUS_E_FAULT;
}
halStatus = sme_ChangeMCCBeaconInterval(hHal, pSapCtx->sessionId);
if(halStatus == eHAL_STATUS_FAILURE ){
VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR,
"%s: Failed to update Beacon Params", __func__);
return VOS_STATUS_E_FAILURE;
}
}
return VOS_STATUS_SUCCESS;
}
void hdd_clear_all_sta(hdd_adapter_t *pHostapdAdapter, v_PVOID_t usrDataForCallback)
{
v_U8_t staId = 0;
struct net_device *dev;
v_CONTEXT_t pVosContext = ( WLAN_HDD_GET_CTX(pHostapdAdapter))->pvosContext;
ptSapContext pSapCtx = NULL;
dev = (struct net_device *)usrDataForCallback;
pSapCtx = VOS_GET_SAP_CB(pVosContext);
if(pSapCtx == NULL){
VOS_TRACE(VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR,
FL("psapCtx is NULL"));
return;
}
hddLog(LOGE, FL("Clearing all the STA entry...."));
for (staId = 0; staId < WLAN_MAX_STA_COUNT; staId++)
{
if ( pSapCtx->aStaInfo[staId].isUsed &&
( staId != (WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter))->uBCStaId))
{
//Disconnect all the stations
hdd_softap_sta_disassoc(pHostapdAdapter, &pSapCtx->aStaInfo[staId].macAddrSTA.bytes[0]);
}
}
}
static int hdd_stop_bss_link(hdd_adapter_t *pHostapdAdapter,v_PVOID_t usrDataForCallback)
{
struct net_device *dev;
hdd_context_t *pHddCtx = NULL;
VOS_STATUS status = VOS_STATUS_SUCCESS;
dev = (struct net_device *)usrDataForCallback;
ENTER();
pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter);
status = wlan_hdd_validate_context(pHddCtx);
if (0 != status) {
return status;
}
if(test_bit(SOFTAP_BSS_STARTED, &pHostapdAdapter->event_flags))
{
if ( VOS_STATUS_SUCCESS == (status = WLANSAP_StopBss((WLAN_HDD_GET_CTX(pHostapdAdapter))->pvosContext) ) )
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, FL("Deleting SAP/P2P link!!!!!!"));
}
clear_bit(SOFTAP_BSS_STARTED, &pHostapdAdapter->event_flags);
wlan_hdd_decr_active_session(pHddCtx, pHostapdAdapter->device_mode);
}
EXIT();
return (status == VOS_STATUS_SUCCESS) ? 0 : -EBUSY;
}
#ifdef SAP_AUTH_OFFLOAD
bool hdd_set_sap_auth_offload(hdd_adapter_t *pHostapdAdapter,
bool enabled)
{
hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter);
struct tSirSapOffloadInfo sap_offload_info;
vos_mem_copy( &sap_offload_info.macAddr,
pHostapdAdapter->macAddressCurrent.bytes, VOS_MAC_ADDR_SIZE);
sap_offload_info.sap_auth_offload_enable = enabled;
sap_offload_info.sap_auth_offload_sec_type =
pHddCtx->cfg_ini->sap_auth_offload_sec_type;
sap_offload_info.key_len =
strlen(pHddCtx->cfg_ini->sap_auth_offload_key);
if (sap_offload_info.sap_auth_offload_enable &&
sap_offload_info.sap_auth_offload_sec_type)
{
if (sap_offload_info.key_len < 8 ||
sap_offload_info.key_len > WLAN_PSK_STRING_LENGTH)
{
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: invalid key length(%d) of WPA security!", __func__,
sap_offload_info.key_len);
return false;
}
}
if (sap_offload_info.key_len)
{
vos_mem_copy(sap_offload_info.key,
pHddCtx->cfg_ini->sap_auth_offload_key,
sap_offload_info.key_len);
}
if (eHAL_STATUS_SUCCESS !=
sme_set_sap_auth_offload(pHddCtx->hHal, &sap_offload_info))
{
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: sme_set_sap_auth_offload fail!", __func__);
return false;
}
hddLog(VOS_TRACE_LEVEL_INFO_HIGH,
"%s: sme_set_sap_auth_offload successfully!", __func__);
return true;
}
#endif
/**
* wlansap_get_phymode() - get SAP phymode.
* @pctx: Pointer to the global vos context; a handle to SAP's control block
* can be extracted from its context. When MBSSID feature is enabled,
* SAP context is directly passed to SAP APIs.
*
* This function provides current phymode of SAP interface.
*
* Return: phymode with eCsrPhyMode type.
*/
static eCsrPhyMode
wlansap_get_phymode(v_PVOID_t pctx)
{
ptSapContext psapctx = VOS_GET_SAP_CB(pctx);
if (!psapctx) {
VOS_TRACE(VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR,
"%s: Invalid SAP pointer from pCtx", __func__);
return eCSR_DOT11_MODE_AUTO;
}
return psapctx->csrRoamProfile.phyMode;
}
/**
* hdd_update_chandef() - Function to update channel width and center freq
* @chandef: cfg80211 chan def
* @cb_mode: chan offset
*
* This function will be called to update channel width and center freq
*
* Return: None
*/
static void
hdd_update_chandef(struct cfg80211_chan_def *chandef,
ePhyChanBondState cb_mode)
{
uint8_t center_chan, chan;
if (cb_mode <= PHY_DOUBLE_CHANNEL_HIGH_PRIMARY)
return;
chan = vos_freq_to_chan(chandef->chan->center_freq);
chandef->width = NL80211_CHAN_WIDTH_80;
switch (cb_mode) {
case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED:
case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW:
center_chan = chan + 2;
break;
case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW:
center_chan = chan + 6;
break;
case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH:
case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED:
center_chan = chan - 2;
break;
case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH:
center_chan = chan - 6;
break;
default:
center_chan = chan;
break;
}
chandef->center_freq1 = vos_chan_to_freq(center_chan);
}
/**
* hdd_chan_change_notify() - Function to notify hostapd about channel change
* @hostapd_adapter: hostapd adapter
* @dev: Net device structure
* @oper_chan: New operating channel
*
* This function is used to notify hostapd about the channel change
*
* Return: Success on intimating userspace
*
*/
static VOS_STATUS hdd_chan_change_notify(hdd_adapter_t *hostapd_adapter,
struct net_device *dev, uint8_t oper_chan)
{
struct ieee80211_channel *chan;
struct cfg80211_chan_def chandef;
enum nl80211_channel_type channel_type;
eCsrPhyMode phy_mode;
ePhyChanBondState cb_mode;
uint32_t freq;
tHalHandle hal = WLAN_HDD_GET_HAL_CTX(hostapd_adapter);
tSmeConfigParams sme_config;
if (!hal) {
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: hal is NULL", __func__);
return VOS_STATUS_E_FAILURE;
}
freq = vos_chan_to_freq(oper_chan);
chan = __ieee80211_get_channel(hostapd_adapter->wdev.wiphy, freq);
if (!chan) {
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Invalid input frequency for channel conversion", __func__);
return VOS_STATUS_E_FAILURE;
}
phy_mode = wlansap_get_phymode(
(WLAN_HDD_GET_CTX(hostapd_adapter))->pvosContext);
sme_GetConfigParam(hal, &sme_config);
if (oper_chan <= 14)
cb_mode = sme_get_cb_phy_mode_from_cb_ini_mode(
sme_config.csrConfig.channelBondingMode24GHz);
else
cb_mode = sme_get_cb_phy_mode_from_cb_ini_mode(
sme_config.csrConfig.channelBondingMode5GHz);
switch (phy_mode) {
case eCSR_DOT11_MODE_11n:
case eCSR_DOT11_MODE_11n_ONLY:
case eCSR_DOT11_MODE_11ac:
case eCSR_DOT11_MODE_11ac_ONLY:
switch (cb_mode) {
case PHY_SINGLE_CHANNEL_CENTERED:
channel_type = NL80211_CHAN_HT20;
break;
case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW:
case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED:
case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH:
case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY:
channel_type = NL80211_CHAN_HT40MINUS;
break;
case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW:
case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED:
case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH:
case PHY_DOUBLE_CHANNEL_LOW_PRIMARY:
channel_type = NL80211_CHAN_HT40PLUS;
break;
default:
channel_type = NL80211_CHAN_HT20;
break;
}
break;
default:
channel_type = NL80211_CHAN_NO_HT;
break;
}
cfg80211_chandef_create(&chandef, chan, channel_type);
if ((phy_mode == eCSR_DOT11_MODE_11ac) ||
(phy_mode == eCSR_DOT11_MODE_11ac_ONLY))
hdd_update_chandef(&chandef, cb_mode);
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"%s: phy_mode %d cb_mode %d chann_type %d oper_chan %d width %d freq_1 %d",
__func__, phy_mode, cb_mode, channel_type, oper_chan,
chandef.width, chandef.center_freq1);
cfg80211_ch_switch_notify(dev, &chandef);
return VOS_STATUS_SUCCESS;
}
/**
* hdd_convert_dot11mode_from_phymode() - get dot11mode to phymode
* @phymode: phy mode
*
* This function is used to get dot11mode to phymode
*
* Return: dot11mode
*/
static int hdd_convert_dot11mode_from_phymode(int phymode)
{
switch (phymode) {
case VOS_MODE_11A:
return QCA_WLAN_802_11_MODE_11A;
case VOS_MODE_11B:
return QCA_WLAN_802_11_MODE_11B;
case VOS_MODE_11G:
case VOS_MODE_11GONLY:
return QCA_WLAN_802_11_MODE_11G;
case VOS_MODE_11NA_HT20:
case VOS_MODE_11NG_HT20:
case VOS_MODE_11NA_HT40:
case VOS_MODE_11NG_HT40:
return QCA_WLAN_802_11_MODE_11N;
case VOS_MODE_11AC_VHT20:
case VOS_MODE_11AC_VHT40:
case VOS_MODE_11AC_VHT80:
case VOS_MODE_11AC_VHT20_2G:
case VOS_MODE_11AC_VHT40_2G:
case VOS_MODE_11AC_VHT80_2G:
#ifdef CONFIG_160MHZ_SUPPORT
case VOS_MODE_11AC_VHT80_80:
case VOS_MODE_11AC_VHT160:
#endif
return QCA_WLAN_802_11_MODE_11AC;
default:
return QCA_WLAN_802_11_MODE_INVALID;
}
}
/**
* hdd_fill_station_info() - fill station information
* @sap_ctx: sap context
* @event: assoc event
* This function updates sta information from assoc event
*
* Return: none
*/
static void hdd_fill_station_info(ptSapContext sap_ctx,
tSap_StationAssocReassocCompleteEvent *event)
{
struct hdd_cache_sta_info *sta_info = sap_ctx->cache_sta_info;
int i=0;
/* check if there is any dup entry */
while (i < WLAN_MAX_STA_COUNT) {
if (vos_mem_compare(sta_info[i].macAddrSTA.bytes,
event->staMac.bytes,
VOS_MAC_ADDR_SIZE)) {
vos_mem_zero(&sta_info[i], sizeof(*sta_info));
break;
}
i++;
}
if (i >= WLAN_MAX_STA_COUNT) {
i = 0;
while (i < WLAN_MAX_STA_COUNT) {
if (sta_info[i].isUsed != TRUE)
break;
i++;
}
}
if (i < WLAN_MAX_STA_COUNT) {
sta_info[i].isUsed = TRUE;
sta_info[i].ucSTAId = event->staId;
vos_mem_copy(sta_info[i].macAddrSTA.bytes,
event->staMac.bytes,
VOS_MAC_ADDR_SIZE);
sta_info[i].freq = vos_chan_to_freq(event->chan_info.chan_id);
sta_info[i].ch_width = event->ch_width;
sta_info[i].nss = 1;
sta_info[i].dot11_mode = hdd_convert_dot11mode_from_phymode(
event->chan_info.info);
if (event->HTCaps.present) {
sta_info[i].ht_present = TRUE;
hdd_copy_ht_caps(&sta_info[i].ht_caps, &event->HTCaps);
}
if (event->VHTCaps.present) {
sta_info[i].vht_present = TRUE;
hdd_copy_vht_caps(&sta_info[i].vht_caps,
&event->VHTCaps);
}
}
else
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "reached max staid, stainfo can't be cached");
}
VOS_STATUS hdd_hostapd_SAPEventCB( tpSap_Event pSapEvent, v_PVOID_t usrDataForCallback)
{
hdd_adapter_t *pHostapdAdapter;
hdd_ap_ctx_t *pHddApCtx;
hdd_hostapd_state_t *pHostapdState;
struct net_device *dev;
eSapHddEvent sapEvent;
union iwreq_data wrqu;
v_BYTE_t *we_custom_event_generic = NULL;
int we_event = 0;
int i = 0;
v_U8_t staId;
VOS_STATUS vos_status;
v_BOOL_t bWPSState;
v_BOOL_t bApActive = FALSE;
v_BOOL_t bAuthRequired = TRUE;
tpSap_AssocMacAddr pAssocStasArray = NULL;
char unknownSTAEvent[IW_CUSTOM_MAX+1];
char maxAssocExceededEvent[IW_CUSTOM_MAX+1];
v_BYTE_t we_custom_start_event[64];
char *startBssEvent;
hdd_context_t *pHddCtx;
hdd_scaninfo_t *pScanInfo = NULL;
struct iw_michaelmicfailure msg;
v_CONTEXT_t pVosContext = NULL;
ptSapContext pSapCtx = NULL;
hdd_config_t *cfg_param;
dev = (struct net_device *)usrDataForCallback;
pHostapdAdapter = netdev_priv(dev);
if ((NULL == pHostapdAdapter) ||
(WLAN_HDD_ADAPTER_MAGIC != pHostapdAdapter->magic))
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,
"invalid adapter or adapter has invalid magic");
return eHAL_STATUS_FAILURE;
}
pVosContext = ( WLAN_HDD_GET_CTX(pHostapdAdapter))->pvosContext;
pSapCtx = VOS_GET_SAP_CB(pVosContext);
if(pSapCtx == NULL){
VOS_TRACE(VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR,
FL("psapCtx is NULL"));
return eHAL_STATUS_FAILURE;
}
pHostapdState = WLAN_HDD_GET_HOSTAP_STATE_PTR(pHostapdAdapter);
pHddApCtx = WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter);
sapEvent = pSapEvent->sapHddEventCode;
memset(&wrqu, '\0', sizeof(wrqu));
pHddCtx = (hdd_context_t*)(pHostapdAdapter->pHddCtx);
cfg_param = pHddCtx->cfg_ini;
switch(sapEvent)
{
case eSAP_START_BSS_EVENT :
hddLog(LOG1, FL("BSS configured status = %s, channel = %u, bc sta Id = %d"),
pSapEvent->sapevt.sapStartBssCompleteEvent.status ? "eSAP_STATUS_FAILURE" : "eSAP_STATUS_SUCCESS",
pSapEvent->sapevt.sapStartBssCompleteEvent.operatingChannel,
pSapEvent->sapevt.sapStartBssCompleteEvent.staId);
pHostapdState->vosStatus = pSapEvent->sapevt.sapStartBssCompleteEvent.status;
vos_status = vos_event_set(&pHostapdState->vosEvent);
if (!VOS_IS_STATUS_SUCCESS(vos_status) || pHostapdState->vosStatus)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, ("ERROR: startbss event failed!!"));
goto stopbss;
}
else
{
if (pHostapdAdapter->device_mode == WLAN_HDD_P2P_GO)
{
if ((cfg_param->dynSplitscan) &&
(!pHddCtx->issplitscan_enabled))
{
pHddCtx->issplitscan_enabled = TRUE;
sme_enable_disable_split_scan(
WLAN_HDD_GET_HAL_CTX(pHostapdAdapter),
cfg_param->nNumStaChanCombinedConc,
cfg_param->nNumP2PChanCombinedConc);
}
}
pHddApCtx->uBCStaId = pSapEvent->sapevt.sapStartBssCompleteEvent.staId;
//@@@ need wep logic here to set privacy bit
vos_status = hdd_softap_Register_BC_STA(pHostapdAdapter, pHddApCtx->uPrivacy);
if (!VOS_IS_STATUS_SUCCESS(vos_status))
{
hddLog(LOGW, FL("Failed to register BC STA %d"), vos_status);
hdd_stop_bss_link(pHostapdAdapter, usrDataForCallback);
}
}
if (0 != (WLAN_HDD_GET_CTX(pHostapdAdapter))->cfg_ini->nAPAutoShutOff)
{
// AP Inactivity timer init and start
vos_status = vos_timer_init( &pHddApCtx->hdd_ap_inactivity_timer, VOS_TIMER_TYPE_SW,
hdd_hostapd_inactivity_timer_cb, (v_PVOID_t)dev );
if (!VOS_IS_STATUS_SUCCESS(vos_status))
hddLog(LOGE, FL("Failed to init AP inactivity timer"));
vos_status = vos_timer_start( &pHddApCtx->hdd_ap_inactivity_timer, (WLAN_HDD_GET_CTX(pHostapdAdapter))->cfg_ini->nAPAutoShutOff * 1000);
if (!VOS_IS_STATUS_SUCCESS(vos_status))
hddLog(LOGE, FL("Failed to init AP inactivity timer"));
}
pHddApCtx->operatingChannel = pSapEvent->sapevt.sapStartBssCompleteEvent.operatingChannel;
pHostapdState->bssState = BSS_START;
// Send current operating channel of SoftAP to BTC-ES
send_btc_nlink_msg(WLAN_BTC_SOFTAP_BSS_START, 0);
//Check if there is any group key pending to set.
if( pHddApCtx->groupKey.keyLength )
{
if( VOS_STATUS_SUCCESS != WLANSAP_SetKeySta(
(WLAN_HDD_GET_CTX(pHostapdAdapter))->pvosContext,
&pHddApCtx->groupKey ) )
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: WLANSAP_SetKeySta failed", __func__);
}
pHddApCtx->groupKey.keyLength = 0;
}
else if ( pHddApCtx->wepKey[0].keyLength )
{
int i=0;
for ( i = 0; i < CSR_MAX_NUM_KEY; i++ )
{
if( VOS_STATUS_SUCCESS != WLANSAP_SetKeySta(
(WLAN_HDD_GET_CTX(pHostapdAdapter))->pvosContext,
&pHddApCtx->wepKey[i] ) )
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: WLANSAP_SetKeySta failed idx %d", __func__, i);
}
}
}
//Fill the params for sending IWEVCUSTOM Event with SOFTAP.enabled
startBssEvent = "SOFTAP.enabled";
memset(&we_custom_start_event, '\0', sizeof(we_custom_start_event));
memcpy(&we_custom_start_event, startBssEvent, strlen(startBssEvent));
memset(&wrqu, 0, sizeof(wrqu));
wrqu.data.length = strlen(startBssEvent);
we_event = IWEVCUSTOM;
we_custom_event_generic = we_custom_start_event;
hdd_dump_concurrency_info(pHddCtx);
break; //Event will be sent after Switch-Case stmt
case eSAP_STOP_BSS_EVENT:
hddLog(LOG1, FL("BSS stop status = %s"),pSapEvent->sapevt.sapStopBssCompleteEvent.status ?
"eSAP_STATUS_FAILURE" : "eSAP_STATUS_SUCCESS");
//Free up Channel List incase if it is set
sapCleanupChannelList();
pHddApCtx->operatingChannel = 0; //Invalidate the channel info.
goto stopbss;
case eSAP_STA_SET_KEY_EVENT:
//TODO: forward the message to hostapd once implementtation is done for now just print
hddLog(LOG1, FL("SET Key: configured status = %s"),pSapEvent->sapevt.sapStationSetKeyCompleteEvent.status ?
"eSAP_STATUS_FAILURE" : "eSAP_STATUS_SUCCESS");
return VOS_STATUS_SUCCESS;
case eSAP_STA_DEL_KEY_EVENT:
//TODO: forward the message to hostapd once implementtation is done for now just print
hddLog(LOG1, FL("Event received %s"),"eSAP_STA_DEL_KEY_EVENT");
return VOS_STATUS_SUCCESS;
case eSAP_STA_MIC_FAILURE_EVENT:
{
memset(&msg, '\0', sizeof(msg));
msg.src_addr.sa_family = ARPHRD_ETHER;
memcpy(msg.src_addr.sa_data, &pSapEvent->sapevt.sapStationMICFailureEvent.staMac, sizeof(v_MACADDR_t));
hddLog(LOG1, "MIC MAC "MAC_ADDRESS_STR, MAC_ADDR_ARRAY(msg.src_addr.sa_data));
if(pSapEvent->sapevt.sapStationMICFailureEvent.multicast == eSAP_TRUE)
msg.flags = IW_MICFAILURE_GROUP;
else
msg.flags = IW_MICFAILURE_PAIRWISE;
memset(&wrqu, 0, sizeof(wrqu));
wrqu.data.length = sizeof(msg);
we_event = IWEVMICHAELMICFAILURE;
we_custom_event_generic = (v_BYTE_t *)&msg;
}
/* inform mic failure to nl80211 */
cfg80211_michael_mic_failure(dev,
pSapEvent->sapevt.
sapStationMICFailureEvent.staMac.bytes,
((pSapEvent->sapevt.sapStationMICFailureEvent.multicast == eSAP_TRUE) ?
NL80211_KEYTYPE_GROUP :
NL80211_KEYTYPE_PAIRWISE),
pSapEvent->sapevt.sapStationMICFailureEvent.keyId,
pSapEvent->sapevt.sapStationMICFailureEvent.TSC,
GFP_KERNEL);
break;
case eSAP_STA_ASSOC_EVENT:
case eSAP_STA_REASSOC_EVENT:
wrqu.addr.sa_family = ARPHRD_ETHER;
memcpy(wrqu.addr.sa_data, &pSapEvent->sapevt.sapStationAssocReassocCompleteEvent.staMac,
sizeof(v_MACADDR_t));
hddLog(LOG1, " associated "MAC_ADDRESS_STR, MAC_ADDR_ARRAY(wrqu.addr.sa_data));
we_event = IWEVREGISTERED;
WLANSAP_Get_WPS_State((WLAN_HDD_GET_CTX(pHostapdAdapter))->pvosContext, &bWPSState);
if ( (eCSR_ENCRYPT_TYPE_NONE == pHddApCtx->ucEncryptType) ||
( eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == pHddApCtx->ucEncryptType ) ||
( eCSR_ENCRYPT_TYPE_WEP104_STATICKEY == pHddApCtx->ucEncryptType ) )
{
bAuthRequired = FALSE;
}
/* fAuthRequiredshould should be false for sap offload */
if ((bAuthRequired || bWPSState)
#ifdef SAP_AUTH_OFFLOAD
&& !cfg_param->enable_sap_auth_offload
#endif
)
{
vos_status = hdd_softap_RegisterSTA( pHostapdAdapter,
TRUE,
pHddApCtx->uPrivacy,
pSapEvent->sapevt.sapStationAssocReassocCompleteEvent.staId,
0,
0,
(v_MACADDR_t *)wrqu.addr.sa_data,
pSapEvent->sapevt.sapStationAssocReassocCompleteEvent.wmmEnabled);
if (!VOS_IS_STATUS_SUCCESS(vos_status))
hddLog(LOGW, FL("Failed to register STA %d "MAC_ADDRESS_STR""),
vos_status, MAC_ADDR_ARRAY(wrqu.addr.sa_data));
}
else
{
vos_status = hdd_softap_RegisterSTA( pHostapdAdapter,
FALSE,
pHddApCtx->uPrivacy,
pSapEvent->sapevt.sapStationAssocReassocCompleteEvent.staId,
0,
0,
(v_MACADDR_t *)wrqu.addr.sa_data,
pSapEvent->sapevt.sapStationAssocReassocCompleteEvent.wmmEnabled);
if (!VOS_IS_STATUS_SUCCESS(vos_status))
hddLog(LOGW, FL("Failed to register STA %d "MAC_ADDRESS_STR""),
vos_status, MAC_ADDR_ARRAY(wrqu.addr.sa_data));
}
if (VOS_IS_STATUS_SUCCESS(vos_status))
hdd_fill_station_info(pSapCtx,
&pSapEvent->sapevt.sapStationAssocReassocCompleteEvent);
staId =
pSapEvent->sapevt.sapStationAssocReassocCompleteEvent.staId;
if (VOS_IS_STATUS_SUCCESS(vos_status))
{
pSapCtx->aStaInfo[staId].rate_flags =
pSapEvent->sapevt.sapStationAssocReassocCompleteEvent.rate_flags;
}
// Stop AP inactivity timer
if (pHddApCtx->hdd_ap_inactivity_timer.state == VOS_TIMER_STATE_RUNNING)
{
vos_status = vos_timer_stop(&pHddApCtx->hdd_ap_inactivity_timer);
if (!VOS_IS_STATUS_SUCCESS(vos_status))
hddLog(LOGE, FL("Failed to start AP inactivity timer"));
}
#ifdef WLAN_OPEN_SOURCE
if (vos_wake_lock_active(&pHddCtx->sap_wake_lock))
{
vos_wake_lock_release(&pHddCtx->sap_wake_lock,
WIFI_POWER_EVENT_WAKELOCK_SAP);
}
vos_wake_lock_timeout_release(&pHddCtx->sap_wake_lock,
HDD_SAP_WAKE_LOCK_DURATION,
WIFI_POWER_EVENT_WAKELOCK_SAP);
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
{
struct station_info *staInfo;
v_U16_t iesLen = pSapEvent->sapevt.sapStationAssocReassocCompleteEvent.iesLen;
staInfo = vos_mem_malloc(sizeof(*staInfo));
if (staInfo == NULL) {
hddLog(LOGE, FL("alloc station_info failed"));
return VOS_STATUS_E_NOMEM;
}
memset(staInfo, 0, sizeof(*staInfo));
if (iesLen <= MAX_ASSOC_IND_IE_LEN )
{
staInfo->assoc_req_ies =
(const u8 *)&pSapEvent->sapevt.sapStationAssocReassocCompleteEvent.ies[0];
staInfo->assoc_req_ies_len = iesLen;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,31)) && \
((LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && \
!defined(WITH_BACKPORTS))
staInfo->filled |= STATION_INFO_ASSOC_REQ_IES;
#endif
cfg80211_new_sta(dev,
(const u8 *)&pSapEvent->sapevt.sapStationAssocReassocCompleteEvent.staMac.bytes[0],
staInfo, GFP_KERNEL);
vos_mem_free(staInfo);
}
else
{
hddLog(LOGE, FL(" Assoc Ie length is too long"));
}
}
#endif
hdd_manage_delack_timer(pHddCtx);
pScanInfo = &pHddCtx->scan_info;
// Lets do abort scan to ensure smooth authentication for client
if ((pScanInfo != NULL) && pScanInfo->mScanPending)
{
hdd_abort_mac_scan(pHddCtx, pScanInfo->sessionId,
eCSR_SCAN_ABORT_DEFAULT);
}
break;
case eSAP_STA_DISASSOC_EVENT:
memcpy(wrqu.addr.sa_data, &pSapEvent->sapevt.sapStationDisassocCompleteEvent.staMac,
sizeof(v_MACADDR_t));
hddLog(LOG1, " disassociated "MAC_ADDRESS_STR, MAC_ADDR_ARRAY(wrqu.addr.sa_data));
vos_status = vos_event_set(&pHostapdState->sta_discon_event);
if (pSapEvent->sapevt.sapStationDisassocCompleteEvent.reason == eSAP_USR_INITATED_DISASSOC)
hddLog(LOG1," User initiated disassociation");
else
hddLog(LOG1," MAC initiated disassociation");
we_event = IWEVEXPIRED;
vos_status = hdd_softap_GetStaId(pHostapdAdapter, &pSapEvent->sapevt.sapStationDisassocCompleteEvent.staMac, &staId);
if (!VOS_IS_STATUS_SUCCESS(vos_status))
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, FL("ERROR: HDD Failed to find sta id!!"));
return VOS_STATUS_E_FAILURE;
}
hdd_softap_DeregisterSTA(pHostapdAdapter, staId);
if (0 != (WLAN_HDD_GET_CTX(pHostapdAdapter))->cfg_ini->nAPAutoShutOff)
{
spin_lock_bh( &pSapCtx->staInfo_lock );
// Start AP inactivity timer if no stations associated with it
for (i = 0; i < WLAN_MAX_STA_COUNT; i++)
{
if (pSapCtx->aStaInfo[i].isUsed && i != (WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter))->uBCStaId)
{
bApActive = TRUE;
break;
}
}
spin_unlock_bh( &pSapCtx->staInfo_lock );
if (bApActive == FALSE)
{
if (pHddApCtx->hdd_ap_inactivity_timer.state == VOS_TIMER_STATE_STOPPED)
{
vos_status = vos_timer_start(&pHddApCtx->hdd_ap_inactivity_timer, (WLAN_HDD_GET_CTX(pHostapdAdapter))->cfg_ini->nAPAutoShutOff * 1000);
if (!VOS_IS_STATUS_SUCCESS(vos_status))
hddLog(LOGE, FL("Failed to init AP inactivity timer"));
}
else
VOS_ASSERT(vos_timer_getCurrentState(&pHddApCtx->hdd_ap_inactivity_timer) == VOS_TIMER_STATE_STOPPED);
}
}
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
cfg80211_del_sta(dev,
(const u8 *)&pSapEvent->sapevt.sapStationDisassocCompleteEvent.staMac.bytes[0],
GFP_KERNEL);
#endif
//Update the beacon Interval if it is P2P GO
vos_status = hdd_change_mcc_go_beacon_interval(pHostapdAdapter);
if (VOS_STATUS_SUCCESS != vos_status)
{
hddLog(LOGE, "%s: failed to update Beacon interval %d",
__func__, vos_status);
}
hdd_manage_delack_timer(pHddCtx);
break;
case eSAP_WPS_PBC_PROBE_REQ_EVENT:
{
static const char * message ="MLMEWPSPBCPROBEREQ.indication";
union iwreq_data wreq;
down(&pHddApCtx->semWpsPBCOverlapInd);
pHddApCtx->WPSPBCProbeReq.probeReqIELen = pSapEvent->sapevt.sapPBCProbeReqEvent.WPSPBCProbeReq.probeReqIELen;
vos_mem_copy(pHddApCtx->WPSPBCProbeReq.probeReqIE, pSapEvent->sapevt.sapPBCProbeReqEvent.WPSPBCProbeReq.probeReqIE,
pHddApCtx->WPSPBCProbeReq.probeReqIELen);
vos_mem_copy(pHddApCtx->WPSPBCProbeReq.peerMacAddr, pSapEvent->sapevt.sapPBCProbeReqEvent.WPSPBCProbeReq.peerMacAddr, sizeof(v_MACADDR_t));
hddLog(LOG1, "WPS PBC probe req "MAC_ADDRESS_STR, MAC_ADDR_ARRAY(pHddApCtx->WPSPBCProbeReq.peerMacAddr));
memset(&wreq, 0, sizeof(wreq));
wreq.data.length = strlen(message); // This is length of message
wireless_send_event(dev, IWEVCUSTOM, &wreq, (char *)message);
return VOS_STATUS_SUCCESS;
}
case eSAP_ASSOC_STA_CALLBACK_EVENT:
pAssocStasArray = pSapEvent->sapevt.sapAssocStaListEvent.pAssocStas;
if (pSapEvent->sapevt.sapAssocStaListEvent.noOfAssocSta != 0)
{ // List of associated stations
for (i = 0; i < pSapEvent->sapevt.sapAssocStaListEvent.noOfAssocSta; i++)
{
hddLog(LOG1,"Associated Sta Num %d:assocId=%d, staId=%d, staMac="MAC_ADDRESS_STR,
i+1,
pAssocStasArray->assocId,
pAssocStasArray->staId,
MAC_ADDR_ARRAY(pAssocStasArray->staMac.bytes));
pAssocStasArray++;
}
}
vos_mem_free(pSapEvent->sapevt.sapAssocStaListEvent.pAssocStas);// Release caller allocated memory here
pSapEvent->sapevt.sapAssocStaListEvent.pAssocStas = NULL;
return VOS_STATUS_SUCCESS;
case eSAP_REMAIN_CHAN_READY:
hdd_remainChanReadyHandler( pHostapdAdapter );
return VOS_STATUS_SUCCESS;
case eSAP_SEND_ACTION_CNF:
hdd_sendActionCnf( pHostapdAdapter,
( eSAP_STATUS_SUCCESS ==
pSapEvent->sapevt.sapActionCnf.actionSendSuccess ) ?
TRUE : FALSE );
return VOS_STATUS_SUCCESS;
case eSAP_UNKNOWN_STA_JOIN:
snprintf(unknownSTAEvent, IW_CUSTOM_MAX, "JOIN_UNKNOWN_STA-%02x:%02x:%02x:%02x:%02x:%02x",
pSapEvent->sapevt.sapUnknownSTAJoin.macaddr.bytes[0],
pSapEvent->sapevt.sapUnknownSTAJoin.macaddr.bytes[1],
pSapEvent->sapevt.sapUnknownSTAJoin.macaddr.bytes[2],
pSapEvent->sapevt.sapUnknownSTAJoin.macaddr.bytes[3],
pSapEvent->sapevt.sapUnknownSTAJoin.macaddr.bytes[4],
pSapEvent->sapevt.sapUnknownSTAJoin.macaddr.bytes[5]);
we_event = IWEVCUSTOM; /* Discovered a new node (AP mode). */
wrqu.data.pointer = unknownSTAEvent;
wrqu.data.length = strlen(unknownSTAEvent);
we_custom_event_generic = (v_BYTE_t *)unknownSTAEvent;
hddLog(LOGE,"%s", unknownSTAEvent);
break;
case eSAP_MAX_ASSOC_EXCEEDED:
snprintf(maxAssocExceededEvent, IW_CUSTOM_MAX, "Peer %02x:%02x:%02x:%02x:%02x:%02x denied"
" assoc due to Maximum Mobile Hotspot connections reached. Please disconnect"
" one or more devices to enable the new device connection",
pSapEvent->sapevt.sapMaxAssocExceeded.macaddr.bytes[0],
pSapEvent->sapevt.sapMaxAssocExceeded.macaddr.bytes[1],
pSapEvent->sapevt.sapMaxAssocExceeded.macaddr.bytes[2],
pSapEvent->sapevt.sapMaxAssocExceeded.macaddr.bytes[3],
pSapEvent->sapevt.sapMaxAssocExceeded.macaddr.bytes[4],
pSapEvent->sapevt.sapMaxAssocExceeded.macaddr.bytes[5]);
we_event = IWEVCUSTOM; /* Discovered a new node (AP mode). */
wrqu.data.pointer = maxAssocExceededEvent;
wrqu.data.length = strlen(maxAssocExceededEvent);
we_custom_event_generic = (v_BYTE_t *)maxAssocExceededEvent;
hddLog(LOG1,"%s", maxAssocExceededEvent);
break;
case eSAP_STA_ASSOC_IND:
return VOS_STATUS_SUCCESS;
case eSAP_DISCONNECT_ALL_P2P_CLIENT:
hddLog(LOG1, FL(" Disconnecting all the P2P Clients...."));
hdd_clear_all_sta(pHostapdAdapter, usrDataForCallback);
return VOS_STATUS_SUCCESS;
case eSAP_MAC_TRIG_STOP_BSS_EVENT :
vos_status = hdd_stop_bss_link(pHostapdAdapter, usrDataForCallback);
if (!VOS_IS_STATUS_SUCCESS(vos_status))
{
hddLog(LOGW, FL("hdd_stop_bss_link failed %d"), vos_status);
}
return VOS_STATUS_SUCCESS;
case eSAP_CHANNEL_CHANGED_EVENT:
hddLog(LOG1, FL("Received eSAP_CHANNEL_CHANGED_EVENT event"));
return hdd_chan_change_notify(pHostapdAdapter, dev,
pSapEvent->sapevt.sap_chan_selected.new_chan);
case eSAP_STA_LOSTLINK_DETECTED:
{
tSap_StationDisassocCompleteEvent *disassoc_comp =
&pSapEvent->sapevt.sapStationDisassocCompleteEvent;
struct hdd_cache_sta_info *sta_info = hdd_get_cache_stainfo(
pSapCtx->cache_sta_info,
disassoc_comp->staMac.bytes);
if (!sta_info) {
hddLog(LOGE, FL("invalid cache sta info"));
return VOS_STATUS_E_FAILURE;
}
WLANTL_GetSAPStaRSSi(pVosContext, disassoc_comp->staId,
&sta_info->rssi);
sta_info->rx_rate =
wlan_tl_get_sta_rx_rate(pVosContext, disassoc_comp->staId);
if (disassoc_comp->reason != eSAP_USR_INITATED_DISASSOC)
sta_info->reason_code = disassoc_comp->reason;
return VOS_STATUS_SUCCESS;
}
default:
hddLog(LOG1,"SAP message is not handled");
goto stopbss;
return VOS_STATUS_SUCCESS;
}
wireless_send_event(dev, we_event, &wrqu, (char *)we_custom_event_generic);
return VOS_STATUS_SUCCESS;
stopbss :
{
v_BYTE_t we_custom_event[64];
char *stopBssEvent = "STOP-BSS.response";//17
int event_len = strlen(stopBssEvent);
hddLog(LOG1, FL("BSS stop status = %s"),
pSapEvent->sapevt.sapStopBssCompleteEvent.status ?
"eSAP_STATUS_FAILURE" : "eSAP_STATUS_SUCCESS");
/* Change the BSS state now since, as we are shutting things down,
* we don't want interfaces to become re-enabled */
pHostapdState->bssState = BSS_STOP;
if (0 != (WLAN_HDD_GET_CTX(pHostapdAdapter))->cfg_ini->nAPAutoShutOff)
{
if (VOS_TIMER_STATE_RUNNING == pHddApCtx->hdd_ap_inactivity_timer.state)
{
vos_status = vos_timer_stop(&pHddApCtx->hdd_ap_inactivity_timer);
if (!VOS_IS_STATUS_SUCCESS(vos_status))
hddLog(LOGE, FL("Failed to stop AP inactivity timer"));
}
vos_status = vos_timer_destroy(&pHddApCtx->hdd_ap_inactivity_timer);
if (!VOS_IS_STATUS_SUCCESS(vos_status))
hddLog(LOGE, FL("Failed to Destroy AP inactivity timer"));
}
/* Stop the pkts from n/w stack as we are going to free all of
* the TX WMM queues for all STAID's */
/*
* If channel avoidance is in progress means driver is performing SAP
* restart. So don't do carrier off, which may lead framework to do
* driver reload.
*/
hddLog(LOG1, FL("ch avoid in progress: %d"),
pHddCtx->is_ch_avoid_in_progress);
if (pHddCtx->is_ch_avoid_in_progress &&
pHddCtx->cfg_ini->sap_internal_restart)
netif_tx_disable(dev);
else
hdd_hostapd_stop(dev);
/* reclaim all resources allocated to the BSS */
vos_status = hdd_softap_stop_bss(pHostapdAdapter);
if (!VOS_IS_STATUS_SUCCESS(vos_status))
hddLog(LOGW, FL("hdd_softap_stop_bss failed %d"), vos_status);
/* once the event is set, structure dev/pHostapdAdapter should
* not be touched since they are now subject to being deleted
* by another thread */
if (eSAP_STOP_BSS_EVENT == sapEvent)
vos_event_set(&pHostapdState->vosEvent);
if (hdd_is_any_session_connected(pHddCtx) == VOS_STATUS_E_FAILURE) {
hdd_enable_bmps_imps(pHddCtx);
sme_request_imps(pHddCtx->hHal);
}
/* notify userspace that the BSS has stopped */
memset(&we_custom_event, '\0', sizeof(we_custom_event));
memcpy(&we_custom_event, stopBssEvent, event_len);
memset(&wrqu, 0, sizeof(wrqu));
wrqu.data.length = event_len;
we_event = IWEVCUSTOM;
we_custom_event_generic = we_custom_event;
wireless_send_event(dev, we_event, &wrqu, (char *)we_custom_event_generic);
hdd_dump_concurrency_info(pHddCtx);
}
if (pHostapdAdapter->device_mode == WLAN_HDD_P2P_GO ||
pHostapdAdapter->device_mode == WLAN_HDD_SOFTAP)
{
hddLog(LOG1,
FL("SAP or Go is getting removed and we are trying to re-enable TDLS"));
wlan_hdd_tdls_reenable(pHddCtx);
}
return VOS_STATUS_SUCCESS;
}
int hdd_softap_unpackIE(
tHalHandle halHandle,
eCsrEncryptionType *pEncryptType,
eCsrEncryptionType *mcEncryptType,
eCsrAuthType *pAuthType,
v_BOOL_t *pMFPCapable,
v_BOOL_t *pMFPRequired,
u_int16_t gen_ie_len,
u_int8_t *gen_ie )
{
tDot11fIERSN dot11RSNIE;
tDot11fIEWPA dot11WPAIE;
tANI_U8 *pRsnIe;
tANI_U16 RSNIeLen;
tANI_U32 status;
if (NULL == halHandle)
{
hddLog(LOGE, FL("Error haHandle returned NULL"));
return -EINVAL;
}
// Validity checks
if ((gen_ie_len < VOS_MIN(DOT11F_IE_RSN_MIN_LEN, DOT11F_IE_WPA_MIN_LEN)) ||
(gen_ie_len > VOS_MAX(DOT11F_IE_RSN_MAX_LEN, DOT11F_IE_WPA_MAX_LEN)) )
return -EINVAL;
// Type check
if ( gen_ie[0] == DOT11F_EID_RSN)
{
// Validity checks
if ((gen_ie_len < DOT11F_IE_RSN_MIN_LEN ) ||
(gen_ie_len > DOT11F_IE_RSN_MAX_LEN) )
{
return VOS_STATUS_E_FAILURE;
}
// Skip past the EID byte and length byte
pRsnIe = gen_ie + 2;
RSNIeLen = gen_ie_len - 2;
// Unpack the RSN IE
memset(&dot11RSNIE, 0, sizeof(tDot11fIERSN));
status = sme_unpack_rsn_ie(halHandle,
pRsnIe,
RSNIeLen,
&dot11RSNIE);
if (!DOT11F_SUCCEEDED(status))
{
hddLog(LOGE,
FL("unpack failed for RSN IE status:(0x%08x)"),
status);
return -EINVAL;
}
// Copy out the encryption and authentication types
hddLog(LOG1, FL("%s: pairwise cipher suite count: %d"),
__func__, dot11RSNIE.pwise_cipher_suite_count );
hddLog(LOG1, FL("%s: authentication suite count: %d"),
__func__, dot11RSNIE.akm_suite_cnt);
/*Here we have followed the apple base code,
but probably I suspect we can do something different*/
//dot11RSNIE.akm_suite_cnt
// Just translate the FIRST one
*pAuthType = hdd_TranslateRSNToCsrAuthType(dot11RSNIE.akm_suite[0]);
//dot11RSNIE.pwise_cipher_suite_count
*pEncryptType = hdd_TranslateRSNToCsrEncryptionType(dot11RSNIE.pwise_cipher_suites[0]);
//dot11RSNIE.gp_cipher_suite_count
*mcEncryptType = hdd_TranslateRSNToCsrEncryptionType(dot11RSNIE.gp_cipher_suite);
// Set the PMKSA ID Cache for this interface
*pMFPCapable = 0 != (dot11RSNIE.RSN_Cap[0] & 0x80);
*pMFPRequired = 0 != (dot11RSNIE.RSN_Cap[0] & 0x40);
// Calling csrRoamSetPMKIDCache to configure the PMKIDs into the cache
} else
if (gen_ie[0] == DOT11F_EID_WPA)
{
// Validity checks
if ((gen_ie_len < DOT11F_IE_WPA_MIN_LEN ) ||
(gen_ie_len > DOT11F_IE_WPA_MAX_LEN))
{
return VOS_STATUS_E_FAILURE;
}
// Skip past the EID byte and length byte - and four byte WiFi OUI
pRsnIe = gen_ie + 2 + 4;
RSNIeLen = gen_ie_len - (2 + 4);
// Unpack the WPA IE
memset(&dot11WPAIE, 0, sizeof(tDot11fIEWPA));
status = dot11fUnpackIeWPA((tpAniSirGlobal) halHandle,
pRsnIe,
RSNIeLen,
&dot11WPAIE);
if (DOT11F_FAILED(status))
{
hddLog(LOGE,
FL("unpack failed for WPA IE status:(0x%08x)"),
status);
return -EINVAL;
}
// Copy out the encryption and authentication types
hddLog(LOG1, FL("%s: WPA unicast cipher suite count: %d"),
__func__, dot11WPAIE.unicast_cipher_count );
hddLog(LOG1, FL("%s: WPA authentication suite count: %d"),
__func__, dot11WPAIE.auth_suite_count);
//dot11WPAIE.auth_suite_count
// Just translate the FIRST one
*pAuthType = hdd_TranslateWPAToCsrAuthType(dot11WPAIE.auth_suites[0]);
//dot11WPAIE.unicast_cipher_count
*pEncryptType = hdd_TranslateWPAToCsrEncryptionType(dot11WPAIE.unicast_ciphers[0]);
//dot11WPAIE.unicast_cipher_count
*mcEncryptType = hdd_TranslateWPAToCsrEncryptionType(dot11WPAIE.multicast_cipher);
*pMFPCapable = VOS_FALSE;
*pMFPRequired = VOS_FALSE;
}
else
{
hddLog(LOGW, FL("%s: gen_ie[0]: %d"), __func__, gen_ie[0]);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
#ifdef FEATURE_WLAN_CH_AVOID
/*==========================================================================
FUNCTION sapUpdateUnsafeChannelList
DESCRIPTION
Function Undate unsafe channel list table
DEPENDENCIES
NA.
PARAMETERS
IN
pSapCtx : SAP context pointer, include unsafe channel list
RETURN VALUE
NONE
============================================================================*/
void hdd_hostapd_update_unsafe_channel_list(hdd_context_t *pHddCtx,
v_U16_t *unsafeChannelList, v_U16_t unsafeChannelCount)
{
v_U16_t i, j;
vos_mem_zero((void *)pHddCtx->unsafeChannelList,
sizeof(pHddCtx->unsafeChannelList));
if (0 == unsafeChannelCount)
{
pHddCtx->unsafeChannelCount = 0;
}
else
{
if (unsafeChannelCount > NUM_20MHZ_RF_CHANNELS)
{
VOS_TRACE(VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR,
FL("unsafeChannelCount%hd greater than %d"),
unsafeChannelCount, NUM_20MHZ_RF_CHANNELS);
unsafeChannelCount = NUM_20MHZ_RF_CHANNELS;
}
vos_mem_copy((void *)pHddCtx->unsafeChannelList,
unsafeChannelList,
unsafeChannelCount * sizeof(tANI_U16));
pHddCtx->unsafeChannelCount = unsafeChannelCount;
}
/* Flush, default set all channel safe */
for (i = 0; i < NUM_20MHZ_RF_CHANNELS; i++)
{
safeChannels[i].isSafe = VOS_TRUE;
}
/* Try to find unsafe channel */
for (i = 0; i < pHddCtx->unsafeChannelCount; i++)
{
for (j = 0; j < NUM_20MHZ_RF_CHANNELS; j++)
{
if(safeChannels[j].channelNumber == pHddCtx->unsafeChannelList[i])
{
/* Found unsafe channel, update it */
safeChannels[j].isSafe = VOS_FALSE;
VOS_TRACE(VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_INFO,
"%s : CH %d is not safe",
__func__, pHddCtx->unsafeChannelList[i]);
break;
}
}
}
return;
}
/**
* hdd_unsafe_channel_restart_sap - restart sap if sap is on unsafe channel
* @adapter: hdd ap adapter
*
* hdd_unsafe_channel_restart_sap check all unsafe channel list
* and if ACS is enabled, driver will ask userspace to restart the
* sap. User space on LTE coex indication restart driver.
*
* Return - none
*/
static void hdd_unsafe_channel_restart_sap(hdd_adapter_t *adapter,
hdd_context_t *hdd_ctx)
{
if (!(adapter && (WLAN_HDD_SOFTAP == adapter->device_mode))) {
return;
}
hddLog(LOG1, FL("Current operation channel %d"),
adapter->sessionCtx.ap.operatingChannel);
if (false == hdd_ctx->is_ch_avoid_in_progress) {
hdd_change_ch_avoidance_status(hdd_ctx, true);
vos_flush_work(
&hdd_ctx->sap_start_work);
/*
* current operating channel
* is un-safe channel, restart SAP
*/
hddLog(LOG1,
FL("Restarting SAP due to unsafe channel"));
adapter->sessionCtx.ap.sapConfig.channel =
AUTO_CHANNEL_SELECT;
if (hdd_ctx->cfg_ini->sap_internal_restart) {
netif_tx_disable(adapter->dev);
schedule_work(&hdd_ctx->sap_start_work);
} else {
hdd_hostapd_stop(adapter->dev);
}
return;
}
return;
}
static v_U16_t hdd_get_safe_channel_from_acs_range(hdd_context_t *hdd_ctx,
hdd_adapter_t *sap_adapter, v_U16_t *unsafeChannelList,
v_U16_t unsafeChannelCount)
{
v_U8_t valid_channels[WNI_CFG_VALID_CHANNEL_LIST_LEN];
v_U32_t startChannelNum;
v_U32_t endChannelNum;
v_U32_t valid_channel_count = WNI_CFG_VALID_CHANNEL_LIST_LEN;
v_U16_t i, j;
eHalStatus status;
bool found;
status = sme_GetCfgValidChannels(hdd_ctx->hHal, valid_channels,
&valid_channel_count);
if (!HAL_STATUS_SUCCESS(status))
return 0;
ccmCfgGetInt(hdd_ctx->hHal, WNI_CFG_SAP_CHANNEL_SELECT_START_CHANNEL,
&startChannelNum);
ccmCfgGetInt(hdd_ctx->hHal, WNI_CFG_SAP_CHANNEL_SELECT_END_CHANNEL,
&endChannelNum);
for (i = 0; i < valid_channel_count; i++) {
found = false;
for (j = 0; j < unsafeChannelCount; j++) {
if (valid_channels[i] == unsafeChannelList[j]) {
found = true;
break;
}
}
if (found)
continue;
if ((valid_channels[i] >= startChannelNum) &&
(valid_channels[i] <= endChannelNum)) {
return valid_channels[i];
}
}
return 0;
}
void hdd_check_for_unsafe_ch(hdd_adapter_t *phostapd_adapter,
hdd_context_t *hdd_ctxt)
{
v_U16_t channelLoop;
v_U16_t unsafeChannelCount = 0;
v_U16_t unsafeChannelList[NUM_20MHZ_RF_CHANNELS];
v_U16_t sta_chan;
v_U16_t restart_chan;
v_CONTEXT_t vos_ctx;
ptSapContext sap_ctx;
vos_ctx = hdd_ctxt->pvosContext;
if (!vos_ctx) {
hddLog(LOGE, FL("vos_ctx is NULL"));
return;
}
sap_ctx = VOS_GET_SAP_CB(vos_ctx);
if (!sap_ctx) {
hddLog(LOGE, FL("sap_ctx is NULL"));
return;
}
/* Get unsafe channel list */
vos_get_wlan_unsafe_channel(unsafeChannelList, sizeof(unsafeChannelList),
&unsafeChannelCount);
sta_chan = hdd_get_operating_channel(hdd_ctxt, WLAN_HDD_INFRA_STATION);
if (sta_chan) {
hddLog(LOG1, FL("Only SCC supported for STA+SAP"));
return;
}
for (channelLoop = 0; channelLoop < unsafeChannelCount; channelLoop++)
{
if ((unsafeChannelList[channelLoop] ==
phostapd_adapter->sessionCtx.ap.operatingChannel)) {
if ((AUTO_CHANNEL_SELECT ==
phostapd_adapter->sessionCtx.ap.sapConfig.channel)
&& (WLAN_HDD_SOFTAP == phostapd_adapter->device_mode)) {
/*
* current operating channel is un-safe channel
* restart driver
*/
if (hdd_ctxt->cfg_ini->force_scc_with_ecsa) {
restart_chan = hdd_get_safe_channel_from_acs_range(hdd_ctxt,
phostapd_adapter, unsafeChannelList,
unsafeChannelCount);
if (!restart_chan) {
hddLog(LOGE, FL("Failed to restart SAP as no safe channel found"));
return;
} else {
if (wlansap_chk_n_set_chan_change_in_progress(sap_ctx))
return;
INIT_COMPLETION(sap_ctx->ecsa_info.chan_switch_comp);
if (wlansap_set_channel_change(vos_ctx, restart_chan,
false)) {
wlansap_reset_chan_change_in_progress(sap_ctx);
complete(&sap_ctx->ecsa_info.chan_switch_comp);
return;
}
}
} else {
hdd_unsafe_channel_restart_sap(phostapd_adapter, hdd_ctxt);
}
/*
* On LE, this event is handled by wlan-services to
* restart SAP. On android, this event would be
* ignored.
*/
wlan_hdd_send_svc_nlink_msg(WLAN_SVC_SAP_RESTART_IND,
NULL, 0);
}
break;
}
}
return;
}
/**---------------------------------------------------------------------------
\brief hdd_hostapd_ch_avoid_cb() -
Avoid channel notification from FW handler.
FW will send un-safe channle list to avoid overwrapping.
hostapd should not use notified channel
\param - pAdapter HDD adapter pointer
indParam channel avoid notification parameter
\return - None
--------------------------------------------------------------------------*/
void hdd_hostapd_ch_avoid_cb
(
void *context,
void *indParam
)
{
hdd_adapter_t *pHostapdAdapter = NULL;
hdd_context_t *hddCtxt;
tSirChAvoidIndType *chAvoidInd;
v_U8_t rangeLoop;
v_U16_t channelLoop;
v_U16_t dupCheck;
v_U16_t startChannel;
v_U16_t endChannel;
v_U16_t unsafeChannelCount = 0;
v_U16_t unsafeChannelList[NUM_20MHZ_RF_CHANNELS];
v_CONTEXT_t pVosContext;
tHddAvoidFreqList hddAvoidFreqList;
tANI_U32 i;
#ifdef WLAN_FEATURE_AP_HT40_24G
ptSapContext pSapCtx = NULL;
tHalHandle hHal;
v_U8_t cbMode;
VOS_STATUS vosStatus = VOS_STATUS_SUCCESS;
v_U32_t delay;
#endif
/* Basic sanity */
if ((NULL == context) || (NULL == indParam))
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s : Invalid arguments", __func__);
return;
}
hddCtxt = (hdd_context_t *)context;
chAvoidInd = (tSirChAvoidIndType *)indParam;
pVosContext = hddCtxt->pvosContext;
/* Make unsafe channel list */
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"%s : band count %d",
__func__, chAvoidInd->avoidRangeCount);
vos_mem_zero((void *)unsafeChannelList,
NUM_20MHZ_RF_CHANNELS * sizeof(v_U16_t));
for (rangeLoop = 0; rangeLoop < chAvoidInd->avoidRangeCount; rangeLoop++)
{
if (unsafeChannelCount >= NUM_20MHZ_RF_CHANNELS) {
hddLog(LOGW, FL("LTE Coex unsafe channel list full"));
break;
}
startChannel = ieee80211_frequency_to_channel(
chAvoidInd->avoidFreqRange[rangeLoop].startFreq);
endChannel = ieee80211_frequency_to_channel(
chAvoidInd->avoidFreqRange[rangeLoop].endFreq);
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"%s : start %d : %d, end %d : %d",
__func__,
chAvoidInd->avoidFreqRange[rangeLoop].startFreq,
startChannel,
chAvoidInd->avoidFreqRange[rangeLoop].endFreq,
endChannel);
for (channelLoop = startChannel;
channelLoop < (endChannel + 1);
channelLoop++)
{
/* Channel duplicate check routine */
for (dupCheck = 0; dupCheck < unsafeChannelCount; dupCheck++)
{
if (unsafeChannelList[dupCheck] == channelLoop)
{
/* This channel is duplicated */
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"%s : found duplicated channel %d",
__func__, channelLoop);
break;
}
}
if (dupCheck == unsafeChannelCount)
{
int ii;
for(ii=0; ii<NUM_20MHZ_RF_CHANNELS; ii++)
{
if (channelLoop == safeChannels[ii].channelNumber)
{
unsafeChannelList[unsafeChannelCount] = channelLoop;
unsafeChannelCount++;
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"%s : unsafe channel %d, count %d",
__func__,
channelLoop, unsafeChannelCount);
if (unsafeChannelCount >= NUM_20MHZ_RF_CHANNELS) {
hddLog(LOGW, FL("LTE Coex unsafe channel list full"));
break;
}
}
}
}
else
{
/* DUP, do nothing */
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"%s : duplicated channel %d",
__func__, channelLoop);
}
}
}
/* Update unsafe channel cache
* WCN Platform Driver cache */
wcnss_set_wlan_unsafe_channel(unsafeChannelList,
unsafeChannelCount);
/* Store into local cache
* Start with STA and later start SAP
* in this scenario, local cache will be used */
hdd_hostapd_update_unsafe_channel_list(hddCtxt,
unsafeChannelList,
unsafeChannelCount);
/* generate vendor specific event */
vos_mem_zero((void *)&hddAvoidFreqList, sizeof(tHddAvoidFreqList));
for (i = 0; i < chAvoidInd->avoidRangeCount; i++)
{
hddAvoidFreqList.avoidFreqRange[i].startFreq =
chAvoidInd->avoidFreqRange[i].startFreq;
hddAvoidFreqList.avoidFreqRange[i].endFreq =
chAvoidInd->avoidFreqRange[i].endFreq;
}
hddAvoidFreqList.avoidFreqRangeCount = chAvoidInd->avoidRangeCount;
wlan_hdd_send_avoid_freq_event(hddCtxt, &hddAvoidFreqList);
/* Get SAP context first
* SAP and P2PGO would not concurrent */
pHostapdAdapter = hdd_get_adapter(hddCtxt, WLAN_HDD_SOFTAP);
#ifdef WLAN_FEATURE_AP_HT40_24G
if (NULL == pHostapdAdapter)
{
pHostapdAdapter = hdd_get_adapter(hddCtxt, WLAN_HDD_P2P_GO);
}
#endif
if ((pHostapdAdapter) &&
(test_bit(SOFTAP_BSS_STARTED, &pHostapdAdapter->event_flags)) &&
(unsafeChannelCount))
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"%s : Current operation channel %d",
__func__,
pHostapdAdapter->sessionCtx.ap.operatingChannel);
/* Check and Restart the SAP if it is on unsafe channel */
hdd_check_for_unsafe_ch(pHostapdAdapter, hddCtxt);
}
#ifdef WLAN_FEATURE_AP_HT40_24G
if (hddCtxt->cfg_ini->apHT40_24GEnabled)
{
pSapCtx = VOS_GET_SAP_CB(pVosContext);
if(pSapCtx == NULL)
{
VOS_TRACE(VOS_MODULE_ID_HDD_SAP_DATA, VOS_TRACE_LEVEL_ERROR,
FL("psapCtx is NULL"));
return;
}
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
FL("SAP Secondary channel: %d "),
pSapCtx->sap_sec_chan);
/* tHalHandle */
hHal = VOS_GET_HAL_CB(pSapCtx->pvosGCtx);
if (NULL == hHal)
{
VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR,
FL("In invalid hHal"));
return;
}
cbMode = sme_GetChannelBondingMode24G(hHal);
VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_INFO,
FL("Selected Channel bonding : %d"), cbMode);
if (cbMode && (pSapCtx->sap_sec_chan > 0))
{
int i;
eHalStatus halStatus;
for (i = 0; i < unsafeChannelCount; i++)
{
if ((pSapCtx->sap_sec_chan == unsafeChannelList[i]))
{
/* Current SAP Secondary channel is un-safe channel */
VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR,
FL("Move SAP from HT40 to HT20"));
halStatus = sme_SetHT2040Mode(hHal, pSapCtx->sessionId,
PHY_SINGLE_CHANNEL_CENTERED);
if (halStatus == eHAL_STATUS_FAILURE)
{
VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR,
FL("Failed to change HT20/40 mode"));
return;
}
/* Disable Channel Bonding for 2.4GHz */
sme_UpdateChannelBondingMode24G(hHal,
PHY_SINGLE_CHANNEL_CENTERED);
return;
}
}
}
if ((!pSapCtx->numHT40IntoSta)
&& (pHostapdAdapter)
&& (test_bit(SOFTAP_BSS_STARTED, &pHostapdAdapter->event_flags)))
{
/* if Unsafe channel is Zero or SAP Primary/Secondary channel
* are Safe then start HT20/40 timer to Move SAP from HT20
* to HT40.
*/
if (((!unsafeChannelCount)
|| (!sapCheckHT40SecondaryIsNotAllowed(pSapCtx))) && (!cbMode))
{
/* Stop Previous Running HT20/40 Timer & Start timer
with (OBSS TransitionDelayFactor * obss interval)
delay after time out move AP from HT20 -> HT40
mode
*/
if (VOS_TIMER_STATE_RUNNING == pSapCtx->sap_HT2040_timer.state)
{
vosStatus = vos_timer_stop(&pSapCtx->sap_HT2040_timer);
if (!VOS_IS_STATUS_SUCCESS(vosStatus))
VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR,
FL("Failed to Stop HT20/40 timer"));
}
delay =
(pSapCtx->ObssScanInterval * pSapCtx->ObssTransitionDelayFactor);
VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR,
FL("Start HT20/40 transition timer (%d sec)"), delay);
vosStatus = vos_timer_start( &pSapCtx->sap_HT2040_timer,
(delay * 1000));
if (!VOS_IS_STATUS_SUCCESS(vosStatus))
VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR,
FL("Failed to Start HT20/40 timer"));
}
else
{
/* Stop HT20/40 Timer */
if (VOS_TIMER_STATE_RUNNING == pSapCtx->sap_HT2040_timer.state)
{
VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_INFO,
FL("Stop HT20/40 transition timer"));
vosStatus = vos_timer_stop(&pSapCtx->sap_HT2040_timer);
if (!VOS_IS_STATUS_SUCCESS(vosStatus))
VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR,
FL("Failed to Stop HT20/40 timer"));
}
}
}
}
#endif
return;
}
#endif /* FEATURE_WLAN_CH_AVOID */
int
static __iw_softap_setparam(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev));
tHalHandle hHal;
hdd_context_t *pHddCtx = NULL;
int *value = (int *)extra;
int sub_cmd = value[0];
int set_value = value[1];
eHalStatus status;
int ret = 0; /* success */
int enable_pattrn_byte_match, enable_magic_pkt;
v_CONTEXT_t pVosContext;
ENTER();
if (NULL == pHostapdAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: hostapd Adapter is null",
__func__);
return -1;
}
pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter);
ret = wlan_hdd_validate_context(pHddCtx);
if (0 != ret)
{
return -1;
}
hHal = WLAN_HDD_GET_HAL_CTX(pHostapdAdapter);
if (!hHal)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Hal ctx is null", __func__);
return -1;
}
pVosContext = (WLAN_HDD_GET_CTX(pHostapdAdapter))->pvosContext;
if (!pVosContext)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Vos ctx is null", __func__);
return -1;
}
switch(sub_cmd)
{
case QCSAP_PARAM_CLR_ACL:
if ( VOS_STATUS_SUCCESS != WLANSAP_ClearACL( pVosContext ))
{
ret = -EIO;
}
break;
case QCSAP_PARAM_ACL_MODE:
if ((eSAP_ALLOW_ALL < (eSapMacAddrACL)set_value) ||
(eSAP_ACCEPT_UNLESS_DENIED > (eSapMacAddrACL)set_value))
{
hddLog(LOGE, FL("Invalid ACL Mode value %d"), set_value);
ret = -EINVAL;
}
else
{
WLANSAP_SetMode(pVosContext, set_value);
}
break;
case QCSAP_PARAM_SET_AUTO_CHANNEL:
if ((0 != set_value) && (1 != set_value))
{
hddLog(LOGE, FL("Invalid setAutoChannel value %d"), set_value);
ret = -EINVAL;
}
else
{
(WLAN_HDD_GET_CTX(pHostapdAdapter))->cfg_ini->apAutoChannelSelection = set_value;
}
break;
case QCSAP_PARAM_MAX_ASSOC:
if (WNI_CFG_ASSOC_STA_LIMIT_STAMIN > set_value)
{
hddLog(LOGE, FL("Invalid setMaxAssoc value %d"), set_value);
ret = -EINVAL;
}
else
{
if (WNI_CFG_ASSOC_STA_LIMIT_STAMAX < set_value)
{
hddLog(LOGW, FL("setMaxAssoc value %d higher than max allowed %d."
"Setting it to max allowed and continuing"),
set_value, WNI_CFG_ASSOC_STA_LIMIT_STAMAX);
set_value = WNI_CFG_ASSOC_STA_LIMIT_STAMAX;
}
status = ccmCfgSetInt(hHal, WNI_CFG_ASSOC_STA_LIMIT,
set_value, NULL, eANI_BOOLEAN_FALSE);
if ( status != eHAL_STATUS_SUCCESS )
{
hddLog(LOGE, FL("setMaxAssoc failure, status %d"),
status);
ret = -EIO;
}
}
break;
case QCSAP_PARAM_HIDE_SSID:
{
eHalStatus status = eHAL_STATUS_SUCCESS;
status = sme_HideSSID(hHal, pHostapdAdapter->sessionId, set_value);
if(eHAL_STATUS_SUCCESS != status)
{
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: QCSAP_PARAM_HIDE_SSID failed",
__func__);
return status;
}
break;
}
case QCSAP_PARAM_SET_MC_RATE:
{
tSirRateUpdateInd *rateUpdate;
rateUpdate = (tSirRateUpdateInd *)
vos_mem_malloc(sizeof(tSirRateUpdateInd));
if (NULL == rateUpdate)
{
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: SET_MC_RATE indication alloc fail", __func__);
ret = -1;
break;
}
vos_mem_zero(rateUpdate, sizeof(tSirRateUpdateInd ));
hddLog(VOS_TRACE_LEVEL_INFO, "MC Target rate %d", set_value);
/* Ignore unicast */
rateUpdate->ucastDataRate = -1;
rateUpdate->mcastDataRate24GHz = set_value;
rateUpdate->mcastDataRate5GHz = set_value;
rateUpdate->mcastDataRate24GHzTxFlag = 0;
rateUpdate->mcastDataRate5GHzTxFlag = 0;
status = sme_SendRateUpdateInd(hHal, rateUpdate);
if (eHAL_STATUS_SUCCESS != status)
{
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: SET_MC_RATE failed", __func__);
vos_mem_free(rateUpdate);
ret = -1;
}
break;
}
case QCSAP_PARAM_GET_FRAME_LOGS:
{
if (wlan_hdd_get_frame_logs(pHostapdAdapter, set_value)
!= VOS_STATUS_SUCCESS)
{
ret = -EINVAL;
}
break;
}
case QCSAP_PARAM_SET_PROXIMITY:
{
ret = wlan_hdd_set_proximity(set_value, hHal);
break;
}
case QCSAP_PARAM_SET_WOWL:
{
if (!pHddCtx->is_ap_mode_wow_supported)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Not supported",__func__);
return -ENOTSUPP;
}
switch (set_value)
{
case 0x00:
hdd_exit_wowl(pHostapdAdapter, eWOWL_EXIT_USER);
break;
case 0x01:
case 0x02:
case 0x03:
enable_magic_pkt = (set_value & 0x01) ? 1 : 0;
enable_pattrn_byte_match = (set_value & 0x02) ? 1 : 0;
hddLog(LOGE, "magic packet ? = %s pattern byte matching ? = %s",
(enable_magic_pkt ? "YES":"NO"),
(enable_pattrn_byte_match ? "YES":"NO"));
hdd_enter_wowl(pHostapdAdapter, enable_magic_pkt,
enable_pattrn_byte_match);
break;
default:
hddLog(LOGE, "Invalid arg %d in WE_WOWL IOCTL", set_value);
ret = -EINVAL;
break;
}
break;
}
case QCSAP_PARAM_CAP_TSF:
{
ret = hdd_capture_tsf(pHostapdAdapter,
(uint32_t *)&set_value, 1);
break;
}
case QCSAP_PARAM_SET_CHANNEL_CHANGE:
if (WLAN_HDD_SOFTAP == pHostapdAdapter->device_mode) {
ptSapContext sap_ctx;
sap_ctx = VOS_GET_SAP_CB(pVosContext);
if (!sap_ctx) {
hddLog(LOGE, FL("sap_ctx is NULL"));
return -EINVAL;
}
ret = wlansap_chk_n_set_chan_change_in_progress(sap_ctx);
if (ret)
return ret;
INIT_COMPLETION(sap_ctx->ecsa_info.chan_switch_comp);
hddLog(LOG1, FL("ET Channel Change to new channel= %d"),
set_value);
ret = wlansap_set_channel_change(pVosContext, set_value, false);
if (ret) {
wlansap_reset_chan_change_in_progress(sap_ctx);
complete(&sap_ctx->ecsa_info.chan_switch_comp);
}
} else {
hddLog(LOGE, FL("Channel %d Change Failed, Device in not in SAP/GO mode"),
set_value);
ret = -EINVAL;
}
break;
default:
hddLog(LOGE, FL("Invalid setparam command %d value %d"),
sub_cmd, set_value);
ret = -EINVAL;
break;
}
EXIT();
return ret;
}
int
static iw_softap_setparam(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_softap_setparam(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
int
static __iw_softap_getparam(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pHostapdAdapter;
tHalHandle hHal;
hdd_context_t *pHddCtx;
int *value = (int *)extra;
int sub_cmd = value[0];
eHalStatus status;
int ret = 0; /* success */
v_CONTEXT_t pVosContext;
ENTER();
pHostapdAdapter = (netdev_priv(dev));
if (NULL == pHostapdAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL",__func__);
return -EINVAL;
}
pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter);
ret = wlan_hdd_validate_context(pHddCtx);
if (0 != ret)
{
return ret;
}
hHal = WLAN_HDD_GET_HAL_CTX(pHostapdAdapter);
if (NULL == hHal)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Hal Context is NULL",__func__);
return -EINVAL;
}
pVosContext = pHddCtx->pvosContext;
if (NULL == pVosContext)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: pVosContext Context is NULL",__func__);
return -EINVAL;
}
switch (sub_cmd)
{
case QCSAP_PARAM_MAX_ASSOC:
status = ccmCfgGetInt(hHal, WNI_CFG_ASSOC_STA_LIMIT, (tANI_U32 *)value);
if (eHAL_STATUS_SUCCESS != status)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
FL("failed to get WNI_CFG_ASSOC_STA_LIMIT from cfg %d"),status);
ret = -EIO;
}
#ifdef WLAN_SOFTAP_VSTA_FEATURE
if (pHddCtx->cfg_ini->fEnableVSTASupport)
{
if (*value > VSTA_NUM_ASSOC_STA)
{
*value = VSTA_NUM_ASSOC_STA;
}
if ((pHddCtx->hddAdapters.count > VSTA_NUM_RESV_SELFSTA) &&
(*value > (VSTA_NUM_ASSOC_STA -
(pHddCtx->hddAdapters.count - VSTA_NUM_RESV_SELFSTA))))
{
*value = (VSTA_NUM_ASSOC_STA -
(pHddCtx->hddAdapters.count - VSTA_NUM_RESV_SELFSTA));
}
}
else
#endif
{
if (*value > NUM_ASSOC_STA)
{
*value = NUM_ASSOC_STA;
}
if ((pHddCtx->hddAdapters.count > NUM_RESV_SELFSTA) &&
(*value > (NUM_ASSOC_STA -
(pHddCtx->hddAdapters.count - NUM_RESV_SELFSTA))))
{
*value = (NUM_ASSOC_STA -
(pHddCtx->hddAdapters.count - NUM_RESV_SELFSTA));
}
}
break;
case QCSAP_PARAM_CLR_ACL:
if ( VOS_STATUS_SUCCESS != WLANSAP_ClearACL( pVosContext ))
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
FL("WLANSAP_ClearACL failed"));
ret = -EIO;
}
*value = 0;
break;
case QCSAP_PARAM_GET_WLAN_DBG:
{
vos_trace_display();
*value = 0;
break;
}
case QCSAP_PARAM_AUTO_CHANNEL:
{
*value = (WLAN_HDD_GET_CTX(pHostapdAdapter))->cfg_ini->apAutoChannelSelection;
break;
}
default:
hddLog(LOGE, FL("Invalid getparam command %d"), sub_cmd);
ret = -EINVAL;
break;
}
EXIT();
return ret;
}
int
static iw_softap_getparam(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_softap_getparam(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
int
static __iw_softap_setchar_getnone(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int sub_cmd;
int ret = 0; /* success */
char *pBuffer = NULL;
hdd_adapter_t *pAdapter;
hdd_context_t *pHddCtx;
struct iw_point s_priv_data;
ENTER();
if (!capable(CAP_NET_ADMIN))
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
FL("permission check failed"));
return -EPERM;
}
pAdapter = (netdev_priv(dev));
pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
ret = wlan_hdd_validate_context(pHddCtx);
if (0 != ret)
{
return ret;
}
if (!pHddCtx->is_ap_mode_wow_supported)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"%s: Not supported",__func__);
return -ENOTSUPP;
}
/* helper function to get iwreq_data with compat handling. */
if (hdd_priv_get_data(&s_priv_data, wrqu))
{
return -EINVAL;
}
/* make sure all params are correctly passed to function */
if ((NULL == s_priv_data.pointer) || (0 == s_priv_data.length))
{
return -EINVAL;
}
sub_cmd = s_priv_data.flags;
/* ODD number is used for set, copy data using copy_from_user */
pBuffer = mem_alloc_copy_from_user_helper(s_priv_data.pointer,
s_priv_data.length);
if (NULL == pBuffer)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"mem_alloc_copy_from_user_helper fail");
return -ENOMEM;
}
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"%s: Received length %d", __func__, s_priv_data.length);
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"%s: Received data %s", __func__, pBuffer);
switch(sub_cmd)
{
case WE_WOWL_ADD_PTRN:
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "ADD_PTRN");
ret = hdd_add_wowl_ptrn(pAdapter, pBuffer);
if (!ret)
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"Failed to add pattern :%d", ret);
break;
case WE_WOWL_DEL_PTRN:
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "DEL_PTRN");
ret = hdd_del_wowl_ptrn(pAdapter, pBuffer);
if (!ret)
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"Failed to del pattern :%d", ret);
break;
default:
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "ioctl not supported in SOFTAP");
ret = -EINVAL;
break;
}
kfree(pBuffer);
return ret;
}
int
static iw_softap_setchar_getnone(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_softap_setchar_getnone(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
/* Usage:
BLACK_LIST = 0
WHITE_LIST = 1
ADD MAC = 0
REMOVE MAC = 1
mac addr will be accepted as a 6 octet mac address with each octet inputted in hex
for e.g. 00:0a:f5:11:22:33 will be represented as 0x00 0x0a 0xf5 0x11 0x22 0x33
while using this ioctl
Syntax:
iwpriv softap.0 modify_acl
<6 octet mac addr> <list type> <cmd type>
Examples:
eg 1. to add a mac addr 00:0a:f5:89:89:90 to the black list
iwpriv softap.0 modify_acl 0x00 0x0a 0xf5 0x89 0x89 0x90 0 0
eg 2. to delete a mac addr 00:0a:f5:89:89:90 from white list
iwpriv softap.0 modify_acl 0x00 0x0a 0xf5 0x89 0x89 0x90 1 1
*/
int __iw_softap_modify_acl(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pHostapdAdapter;
v_CONTEXT_t pVosContext;
hdd_context_t *pHddCtx;
v_BYTE_t *value = (v_BYTE_t*)extra;
v_U8_t pPeerStaMac[VOS_MAC_ADDR_SIZE];
int listType, cmd, i;
int ret = 0; /* success */
ENTER();
pHostapdAdapter = (netdev_priv(dev));
if (NULL == pHostapdAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL",__func__);
return -EINVAL;
}
pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter);
ret = wlan_hdd_validate_context(pHddCtx);
if (0 != ret)
{
return ret;
}
pVosContext = pHddCtx->pvosContext;
if (NULL == pVosContext)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Vos Context is NULL",__func__);
return -EINVAL;
}
for (i=0; i<VOS_MAC_ADDR_SIZE; i++)
{
pPeerStaMac[i] = *(value+i);
}
listType = (int)(*(value+i));
i++;
cmd = (int)(*(value+i));
hddLog(LOG1, "%s: SAP Modify ACL arg0 " MAC_ADDRESS_STR " arg1 %d arg2 %d",
__func__, MAC_ADDR_ARRAY(pPeerStaMac), listType, cmd);
if (WLANSAP_ModifyACL(pVosContext, pPeerStaMac,(eSapACLType)listType,(eSapACLCmdType)cmd)
!= VOS_STATUS_SUCCESS)
{
hddLog(LOGE, FL("Modify ACL failed"));
ret = -EIO;
}
EXIT();
return ret;
}
int iw_softap_modify_acl(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_softap_modify_acl(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
int
static __iw_softap_getchannel(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pHostapdAdapter;
hdd_context_t *pHddCtx;
int ret = 0;
int *value;
ENTER();
pHostapdAdapter = (netdev_priv(dev));
if (NULL == pHostapdAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL",__func__);
return -EINVAL;
}
pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter);
ret = wlan_hdd_validate_context(pHddCtx);
if (0 != ret)
{
return ret;
}
value = (int *)extra;
*value = (WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter))->operatingChannel;
EXIT();
return 0;
}
int
static iw_softap_getchannel(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_softap_getchannel(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
int
static __iw_softap_set_max_tx_power(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pHostapdAdapter;
tHalHandle hHal;
hdd_context_t *pHddCtx;
int *value = (int *)extra;
int set_value, ret = 0;
tSirMacAddr bssid = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
tSirMacAddr selfMac = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
ENTER();
pHostapdAdapter = (netdev_priv(dev));
if (NULL == pHostapdAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL",__func__);
return -EINVAL;
}
pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter);
ret = wlan_hdd_validate_context(pHddCtx);
if (0 != ret)
{
return ret;
}
hHal = WLAN_HDD_GET_HAL_CTX(pHostapdAdapter);
if (NULL == hHal)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Hal Context is NULL",__func__);
return -EINVAL;
}
if (NULL == value)
return -ENOMEM;
/* Assign correct slef MAC address */
vos_mem_copy(bssid, pHostapdAdapter->macAddressCurrent.bytes,
VOS_MAC_ADDR_SIZE);
vos_mem_copy(selfMac, pHostapdAdapter->macAddressCurrent.bytes,
VOS_MAC_ADDR_SIZE);
set_value = value[0];
if (eHAL_STATUS_SUCCESS != sme_SetMaxTxPower(hHal, bssid, selfMac, set_value))
{
hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Setting maximum tx power failed",
__func__);
return -EIO;
}
EXIT();
return 0;
}
int
static iw_softap_set_max_tx_power(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_softap_set_max_tx_power(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
int
static __iw_display_data_path_snapshot(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
/* Function intitiating dumping states of
* HDD(WMM Tx Queues)
* TL State (with Per Client infor)
* DXE Snapshot (Called at the end of TL Snapshot)
*/
hdd_adapter_t *pHostapdAdapter;
hdd_context_t *pHddCtx;
int ret = 0;
ENTER();
pHostapdAdapter = (netdev_priv(dev));
if (NULL == pHostapdAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL",__func__);
return -EINVAL;
}
pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter);
ret = wlan_hdd_validate_context(pHddCtx);
if (0 != ret)
{
return ret;
}
hdd_wmm_tx_snapshot(pHostapdAdapter);
WLANTL_TLDebugMessage(WLANTL_DEBUG_TX_SNAPSHOT);
EXIT();
return 0;
}
int
static iw_display_data_path_snapshot(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_display_data_path_snapshot(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
int
static __iw_softap_set_tx_power(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pHostapdAdapter;
hdd_context_t *pHddCtx;
v_CONTEXT_t pVosContext;
tHalHandle hHal;
int *value = (int *)extra;
int set_value, ret = 0;
ptSapContext pSapCtx = NULL;
ENTER();
pHostapdAdapter = (netdev_priv(dev));
if (NULL == pHostapdAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL",__func__);
return -EINVAL;
}
pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter);
ret = wlan_hdd_validate_context(pHddCtx);
if (0 != ret)
{
return ret;
}
pVosContext = pHddCtx->pvosContext;
if (NULL == pVosContext)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Vos Context is NULL",__func__);
return -EINVAL;
}
hHal = WLAN_HDD_GET_HAL_CTX(pHostapdAdapter);
if (NULL == hHal)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Hal Context is NULL",__func__);
return -EINVAL;
}
if (NULL == value)
return -ENOMEM;
pSapCtx = VOS_GET_SAP_CB(pVosContext);
if (NULL == pSapCtx)
{
VOS_TRACE(VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR,
"%s: Invalid SAP pointer from pvosGCtx", __func__);
return VOS_STATUS_E_FAULT;
}
set_value = value[0];
if (eHAL_STATUS_SUCCESS != sme_SetTxPower(hHal, pSapCtx->sessionId, set_value))
{
hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Setting tx power failed",
__func__);
return -EIO;
}
EXIT();
return 0;
}
int
static iw_softap_set_tx_power(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_softap_set_tx_power(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
/**---------------------------------------------------------------------------
\brief iw_softap_set_trafficmonitor() -
This function dynamically enable/disable traffic monitor functonality
the command iwpriv wlanX setTrafficMon <value>.
\param - dev - Pointer to the net device.
- addr - Pointer to the sockaddr.
\return - 0 for success, non zero for failure
--------------------------------------------------------------------------*/
static int __iw_softap_set_trafficmonitor(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pAdapter;
int *isSetTrafficMon = (int *)extra;
hdd_context_t *pHddCtx;
int status;
ENTER();
pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
if (NULL == pAdapter)
{
VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR,
"%s: HDD adapter is Null", __func__);
return -ENODEV;
}
pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
status = wlan_hdd_validate_context(pHddCtx);
if (0 != status)
{
return status;
}
hddLog(VOS_TRACE_LEVEL_INFO, "%s : ", __func__);
if (NULL == isSetTrafficMon)
{
VOS_TRACE(VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR,
"%s: Invalid SAP pointer from extra", __func__);
return -ENOMEM;
}
if (TRUE == *isSetTrafficMon)
{
pHddCtx->cfg_ini->enableTrafficMonitor= TRUE;
if (VOS_STATUS_SUCCESS != hdd_start_trafficMonitor(pAdapter, false))
{
VOS_TRACE( VOS_MODULE_ID_HDD_SOFTAP, VOS_TRACE_LEVEL_ERROR,
"%s: failed to Start Traffic Monitor timer ", __func__ );
return -EIO;
}
}
else if (FALSE == *isSetTrafficMon)
{
pHddCtx->cfg_ini->enableTrafficMonitor= FALSE;
if (VOS_STATUS_SUCCESS != hdd_stop_trafficMonitor(pAdapter, false))
{
VOS_TRACE( VOS_MODULE_ID_HDD_SOFTAP, VOS_TRACE_LEVEL_ERROR,
"%s: failed to Stop Traffic Monitor timer ", __func__ );
return -EIO;
}
}
EXIT();
return 0;
}
static int iw_softap_set_trafficmonitor(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_softap_set_trafficmonitor(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
#define IS_BROADCAST_MAC(x) (((x[0] & x[1] & x[2] & x[3] & x[4] & x[5]) == 0xff) ? 1 : 0)
int
static __iw_softap_getassoc_stamacaddr(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pHostapdAdapter;
hdd_context_t *pHddCtx;
hdd_station_info_t *pStaInfo = NULL;
char *buf;
int cnt = 0;
int left;
int ret = 0;
/* maclist_index must be u32 to match userspace */
u32 maclist_index;
v_CONTEXT_t pVosContext = NULL;
ptSapContext pSapCtx = NULL;
ENTER();
pHostapdAdapter = (netdev_priv(dev));
if (NULL == pHostapdAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL",__func__);
return -EINVAL;
}
pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter);
ret = wlan_hdd_validate_context(pHddCtx);
if (0 != ret)
{
return ret;
}
/*
* NOTE WELL: this is a "get" ioctl but it uses an even ioctl
* number, and even numbered iocts are supposed to have "set"
* semantics. Hence the wireless extensions support in the kernel
* won't correctly copy the result to userspace, so the ioctl
* handler itself must copy the data. Output format is 32-bit
* record length, followed by 0 or more 6-byte STA MAC addresses.
*
* Further note that due to the incorrect semantics, the "iwpriv"
* userspace application is unable to correctly invoke this API,
* hence it is not registered in the hostapd_private_args. This
* API can only be invoked by directly invoking the ioctl() system
* call.
*/
/* make sure userspace allocated a reasonable buffer size */
if (wrqu->data.length < sizeof(maclist_index)) {
hddLog(LOG1, "%s: invalid userspace buffer", __func__);
return -EINVAL;
}
pVosContext = ( WLAN_HDD_GET_CTX(pHostapdAdapter))->pvosContext;
pSapCtx = VOS_GET_SAP_CB(pVosContext);
if(pSapCtx == NULL){
VOS_TRACE(VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR,
FL("psapCtx is NULL"));
return -EFAULT;
}
/* allocate local buffer to build the response */
buf = kmalloc(wrqu->data.length, GFP_KERNEL);
if (!buf) {
hddLog(LOG1, "%s: failed to allocate response buffer", __func__);
return -ENOMEM;
}
pStaInfo = pSapCtx->aStaInfo;
/* start indexing beyond where the record count will be written */
maclist_index = sizeof(maclist_index);
left = wrqu->data.length - maclist_index;
spin_lock_bh(&pSapCtx->staInfo_lock);
while ((cnt < WLAN_MAX_STA_COUNT) && (left >= VOS_MAC_ADDR_SIZE)) {
if ((pStaInfo[cnt].isUsed) &&
(!IS_BROADCAST_MAC(pStaInfo[cnt].macAddrSTA.bytes))) {
memcpy(&buf[maclist_index], &(pStaInfo[cnt].macAddrSTA),
VOS_MAC_ADDR_SIZE);
maclist_index += VOS_MAC_ADDR_SIZE;
left -= VOS_MAC_ADDR_SIZE;
}
cnt++;
}
spin_unlock_bh(&pSapCtx->staInfo_lock);
*((u32 *)buf) = maclist_index;
wrqu->data.length = maclist_index;
if (copy_to_user(wrqu->data.pointer, buf, maclist_index)) {
hddLog(LOG1, "%s: failed to copy response to user buffer", __func__);
ret = -EFAULT;
}
kfree(buf);
EXIT();
return ret;
}
int
static iw_softap_getassoc_stamacaddr(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_softap_getassoc_stamacaddr(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
/* Usage:
mac addr will be accepted as a 6 octet mac address with each octet inputted in hex
for e.g. 00:0a:f5:11:22:33 will be represented as 0x00 0x0a 0xf5 0x11 0x22 0x33
while using this ioctl
Syntax:
iwpriv softap.0 disassoc_sta <6 octet mac address>
e.g.
disassociate sta with mac addr 00:0a:f5:11:22:33 from softap
iwpriv softap.0 disassoc_sta 0x00 0x0a 0xf5 0x11 0x22 0x33
*/
int
static __iw_softap_disassoc_sta(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pHostapdAdapter;
hdd_context_t *pHddCtx;
v_U8_t *peerMacAddr;
int ret = 0;
ENTER();
if (!capable(CAP_NET_ADMIN)) {
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
FL("permission check failed"));
return -EPERM;
}
pHostapdAdapter = (netdev_priv(dev));
if (NULL == pHostapdAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL",__func__);
return -EINVAL;
}
pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter);
ret = wlan_hdd_validate_context(pHddCtx);
if (0 != ret)
{
return ret;
}
/* iwpriv tool or framework calls this ioctl with
* data passed in extra (less than 16 octets);
*/
peerMacAddr = (v_U8_t *)(extra);
hddLog(LOG1, "%s data " MAC_ADDRESS_STR,
__func__, MAC_ADDR_ARRAY(peerMacAddr));
hdd_softap_sta_disassoc(pHostapdAdapter, peerMacAddr);
EXIT();
return 0;
}
int
static iw_softap_disassoc_sta(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_softap_disassoc_sta(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
int
static __iw_softap_ap_stats(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pHostapdAdapter;
hdd_context_t *pHddCtx;
WLANTL_TRANSFER_STA_TYPE statBuffer;
char *pstatbuf;
int len, ret = 0;
ENTER();
pHostapdAdapter = (netdev_priv(dev));
if (NULL == pHostapdAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL",__func__);
return -EINVAL;
}
pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter);
ret = wlan_hdd_validate_context(pHddCtx);
if (0 != ret)
{
return ret;
}
memset(&statBuffer, 0, sizeof(statBuffer));
WLANSAP_GetStatistics((WLAN_HDD_GET_CTX(pHostapdAdapter))->pvosContext,
&statBuffer, (v_BOOL_t)wrqu->data.flags);
pstatbuf = kzalloc(QCSAP_MAX_WSC_IE, GFP_KERNEL);
if(NULL == pstatbuf) {
hddLog(LOG1, "unable to allocate memory");
return -ENOMEM;
}
len = scnprintf(pstatbuf, QCSAP_MAX_WSC_IE,
"RUF=%d RMF=%d RBF=%d "
"RUB=%d RMB=%d RBB=%d "
"TUF=%d TMF=%d TBF=%d "
"TUB=%d TMB=%d TBB=%d ",
(int)statBuffer.rxUCFcnt, (int)statBuffer.rxMCFcnt,
(int)statBuffer.rxBCFcnt, (int)statBuffer.rxUCBcnt,
(int)statBuffer.rxMCBcnt, (int)statBuffer.rxBCBcnt,
(int)statBuffer.txUCFcnt, (int)statBuffer.txMCFcnt,
(int)statBuffer.txBCFcnt, (int)statBuffer.txUCBcnt,
(int)statBuffer.txMCBcnt, (int)statBuffer.txBCBcnt);
if (len >= QCSAP_MAX_WSC_IE) {
hddLog(LOG1, "%s: failed to copy data to user buffer", __func__);
kfree(pstatbuf);
return -EFAULT;
}
strlcpy(extra, pstatbuf, len);
wrqu->data.length = len;
kfree(pstatbuf);
EXIT();
return 0;
}
int
static __iw_softap_ap_get_stats(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pAdapter;
hdd_tx_rx_stats_t *pStats;
ENTER();
pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
if (NULL == pAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL",__func__);
return -EINVAL;
}
pStats = &pAdapter->hdd_stats.hddTxRxStats;
snprintf(extra, QCSAP_MAX_STR_LEN,
"\nTransmit"
"\ncalled %u, dropped %u, backpressured %u, queued %u"
"\n dropped BK %u, BE %u, VI %u, VO %u"
"\n classified BK %u, BE %u, VI %u, VO %u"
"\nbackpressured BK %u, BE %u, VI %u, VO %u"
"\n queued BK %u, BE %u, VI %u, VO %u"
"\nfetched %u, empty %u, lowres %u, deqerr %u"
"\ndequeued %u, depressured %u, deque-depressured %u,\
completed %u, flushed %u"
"\n fetched BK %u, BE %u, VI %u, VO %u"
"\n dequeued BK %u, BE %u, VI %u, VO %u"
"\n depressured BK %u, BE %u, VI %u, VO %u"
"\nDeque depressured BK %u, BE %u, VI %u, VO %u"
"\n flushed BK %u, BE %u, VI %u, VO %u"
"\n\nReceive"
"\nchains %u, packets %u, dropped %u, delivered %u, refused %u"
"\n\nResetsStats"
"\n",
pStats->txXmitCalled,
pStats->txXmitDropped,
pStats->txXmitBackPressured,
pStats->txXmitQueued,
pStats->txXmitDroppedAC[WLANTL_AC_BK],
pStats->txXmitDroppedAC[WLANTL_AC_BE],
pStats->txXmitDroppedAC[WLANTL_AC_VI],
pStats->txXmitDroppedAC[WLANTL_AC_VO],
pStats->txXmitClassifiedAC[WLANTL_AC_BK],
pStats->txXmitClassifiedAC[WLANTL_AC_BE],
pStats->txXmitClassifiedAC[WLANTL_AC_VI],
pStats->txXmitClassifiedAC[WLANTL_AC_VO],
pStats->txXmitBackPressuredAC[WLANTL_AC_BK],
pStats->txXmitBackPressuredAC[WLANTL_AC_BE],
pStats->txXmitBackPressuredAC[WLANTL_AC_VI],
pStats->txXmitBackPressuredAC[WLANTL_AC_VO],
pStats->txXmitQueuedAC[WLANTL_AC_BK],
pStats->txXmitQueuedAC[WLANTL_AC_BE],
pStats->txXmitQueuedAC[WLANTL_AC_VI],
pStats->txXmitQueuedAC[WLANTL_AC_VO],
pStats->txFetched,
pStats->txFetchEmpty,
pStats->txFetchLowResources,
pStats->txFetchDequeueError,
pStats->txFetchDequeued,
pStats->txFetchDePressured,
pStats->txDequeDePressured,
pStats->txCompleted,
pStats->txFlushed,
pStats->txFetchedAC[WLANTL_AC_BK],
pStats->txFetchedAC[WLANTL_AC_BE],
pStats->txFetchedAC[WLANTL_AC_VI],
pStats->txFetchedAC[WLANTL_AC_VO],
pStats->txFetchDequeuedAC[WLANTL_AC_BK],
pStats->txFetchDequeuedAC[WLANTL_AC_BE],
pStats->txFetchDequeuedAC[WLANTL_AC_VI],
pStats->txFetchDequeuedAC[WLANTL_AC_VO],
pStats->txFetchDePressuredAC[WLANTL_AC_BK],
pStats->txFetchDePressuredAC[WLANTL_AC_BE],
pStats->txFetchDePressuredAC[WLANTL_AC_VI],
pStats->txFetchDePressuredAC[WLANTL_AC_VO],
pStats->txDequeDePressuredAC[WLANTL_AC_BK],
pStats->txDequeDePressuredAC[WLANTL_AC_BE],
pStats->txDequeDePressuredAC[WLANTL_AC_VI],
pStats->txDequeDePressuredAC[WLANTL_AC_VO],
pStats->txFlushedAC[WLANTL_AC_BK],
pStats->txFlushedAC[WLANTL_AC_BE],
pStats->txFlushedAC[WLANTL_AC_VI],
pStats->txFlushedAC[WLANTL_AC_VO],
pStats->rxChains,
pStats->rxPackets,
pStats->rxDropped,
pStats->rxDelivered,
pStats->rxRefused
);
wrqu->data.length = strlen(extra) + 1;
return 0;
}
int
static __iw_softap_ap_clear_stats(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pAdapter;
ENTER();
pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
if (NULL == pAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL",__func__);
return -EINVAL;
}
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,"%s: clearing", __func__);
memset(&pAdapter->stats, 0, sizeof(pAdapter->stats));
memset(&pAdapter->hdd_stats, 0, sizeof(pAdapter->hdd_stats));
return 0;
}
int
static iw_softap_get_stats(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_softap_ap_get_stats(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
int
static iw_softap_clear_stats(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_softap_ap_clear_stats(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
int
static iw_softap_ap_stats(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_softap_ap_stats(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
/**
* __iw_softap_get_three() - return three value to upper layer.
*
* @dev: pointer of net_device of this wireless card
* @info: meta data about Request sent
* @wrqu: include request info
* @extra: buf used for in/out
*
* Return: execute result
*/
static int __iw_softap_get_three(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
uint32_t *value = (uint32_t *)extra;
uint32_t sub_cmd = value[0];
int ret = 0; /* success */
hdd_adapter_t *padapter = WLAN_HDD_GET_PRIV_PTR(dev);
switch (sub_cmd) {
case QCSAP_IOCTL_GET_TSF:
ret = hdd_indicate_tsf(padapter, value, 3);
break;
default:
hddLog(LOGE, FL("Invalid getparam command %d"), sub_cmd);
break;
}
return ret;
}
/**
* iw_softap_get_three() - return three value to upper layer.
*
* @dev: pointer of net_device of this wireless card
* @info: meta data about Request sent
* @wrqu: include request info
* @extra: buf used for in/Output
*
* Return: execute result
*/
static int iw_softap_get_three(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_softap_get_three(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
static int __iw_softap_set_channel_range(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pHostapdAdapter;
tHalHandle hHal;
hdd_context_t *pHddCtx;
int *value = (int *)extra;
int startChannel = value[0];
int endChannel = value[1];
int band = value[2];
VOS_STATUS status;
int ret = 0; /* success */
ENTER();
if (!capable(CAP_NET_ADMIN))
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
FL("permission check failed"));
return -EPERM;
}
pHostapdAdapter = (netdev_priv(dev));
if (NULL == pHostapdAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL",__func__);
return -EINVAL;
}
pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter);
ret = wlan_hdd_validate_context(pHddCtx);
if (0 != ret)
{
return ret;
}
hHal = WLAN_HDD_GET_HAL_CTX(pHostapdAdapter);
if (NULL == hHal)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Hal Context is NULL",__func__);
return -EINVAL;
}
status = WLANSAP_SetChannelRange(hHal,startChannel,endChannel,band);
if(status != VOS_STATUS_SUCCESS)
{
hddLog( LOGE, FL("iw_softap_set_channel_range: startChannel = %d, endChannel = %d band = %d"),
startChannel,endChannel, band);
ret = -EINVAL;
}
pHddCtx->is_dynamic_channel_range_set = 1;
EXIT();
return ret;
}
static int iw_softap_set_channel_range(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_softap_set_channel_range(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
int __iw_softap_get_channel_list(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
v_U32_t num_channels = 0;
v_U8_t i = 0;
v_U8_t bandStartChannel = RF_CHAN_1;
v_U8_t bandEndChannel = RF_CHAN_165;
v_U32_t temp_num_channels = 0;
hdd_adapter_t *pHostapdAdapter;
tHalHandle hHal;
v_REGDOMAIN_t domainIdCurrentSoftap;
tpChannelListInfo channel_list = (tpChannelListInfo) extra;
eCsrBand curBand = eCSR_BAND_ALL;
hdd_context_t *pHddCtx;
int ret = 0;
ENTER();
pHostapdAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
if (NULL == pHostapdAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL",__func__);
return -EINVAL;
}
pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter);
ret = wlan_hdd_validate_context(pHddCtx);
if (0 != ret)
{
return ret;
}
hHal = WLAN_HDD_GET_HAL_CTX(pHostapdAdapter);
if (NULL == hHal)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Hal Context is NULL",__func__);
return -EINVAL;
}
if (eHAL_STATUS_SUCCESS != sme_GetFreqBand(hHal, &curBand))
{
hddLog(LOGE,FL("not able get the current frequency band"));
return -EIO;
}
wrqu->data.length = sizeof(tChannelListInfo);
ENTER();
if (eCSR_BAND_24 == curBand)
{
bandStartChannel = RF_CHAN_1;
bandEndChannel = RF_CHAN_14;
}
else if (eCSR_BAND_5G == curBand)
{
bandStartChannel = RF_CHAN_36;
bandEndChannel = RF_CHAN_165;
}
hddLog(LOG1, FL("curBand = %d, bandStartChannel = %hu, "
"bandEndChannel = %hu "), curBand,
bandStartChannel, bandEndChannel );
for( i = bandStartChannel; i <= bandEndChannel; i++ )
{
if( NV_CHANNEL_ENABLE == regChannels[i].enabled )
{
channel_list->channels[num_channels] = rfChannels[i].channelNum;
num_channels++;
}
}
/* remove indoor channels if the domain is FCC, channels 36 - 48 */
temp_num_channels = num_channels;
if(eHAL_STATUS_SUCCESS != sme_getSoftApDomain(hHal,(v_REGDOMAIN_t *) &domainIdCurrentSoftap))
{
hddLog(LOGE,FL("Failed to get Domain ID, %d"),domainIdCurrentSoftap);
return -EIO;
}
if(REGDOMAIN_FCC == domainIdCurrentSoftap &&
pHddCtx->cfg_ini->gEnableStrictRegulatoryForFCC )
{
for(i = 0; i < temp_num_channels; i++)
{
if((channel_list->channels[i] > 35) &&
(channel_list->channels[i] < 49))
{
vos_mem_move(&channel_list->channels[i],
&channel_list->channels[i+1],
temp_num_channels - (i-1));
num_channels--;
temp_num_channels--;
i--;
}
}
}
hddLog(LOG1,FL(" number of channels %d"), num_channels);
channel_list->num_channels = num_channels;
EXIT();
return 0;
}
int iw_softap_get_channel_list(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_softap_get_channel_list(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
static
int __iw_get_genie(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pHostapdAdapter;
hdd_context_t *pHddCtx;
v_CONTEXT_t pVosContext;
VOS_STATUS status;
v_U32_t length = DOT11F_IE_RSN_MAX_LEN;
v_U8_t genIeBytes[DOT11F_IE_RSN_MAX_LEN];
int ret = 0;
ENTER();
pHostapdAdapter = (netdev_priv(dev));
if (NULL == pHostapdAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL",__func__);
return -EINVAL;
}
pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter);
ret = wlan_hdd_validate_context(pHddCtx);
if (0 != ret)
{
return ret;
}
pVosContext = pHddCtx->pvosContext;
if (NULL == pVosContext)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: vos context is not valid ",__func__);
return -EINVAL;
}
hddLog(LOG1,FL("getGEN_IE ioctl"));
// Actually retrieve the RSN IE from CSR. (We previously sent it down in the CSR Roam Profile.)
status = WLANSap_getstationIE_information(pVosContext,
&length,
genIeBytes);
if (VOS_STATUS_SUCCESS != status) {
hddLog(LOGE, FL("failed to get sta ies"));
return -EFAULT;
}
wrqu->data.length = length;
if (length > DOT11F_IE_RSN_MAX_LEN) {
hddLog(LOGE,
FL("invalid buffer length length:%d"), length);
return -E2BIG;
}
vos_mem_copy(extra, genIeBytes, length);
hddLog(LOG1, FL("RSN IE of %d bytes returned"), wrqu->data.length);
EXIT();
return 0;
}
static
int iw_get_genie(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_get_genie(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
static
int __iw_get_WPSPBCProbeReqIEs(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev));
sQcSapreq_WPSPBCProbeReqIES_t WPSPBCProbeReqIEs;
hdd_ap_ctx_t *pHddApCtx;
hdd_context_t *pHddCtx;
int ret = 0;
ENTER();
pHostapdAdapter = (netdev_priv(dev));
if (NULL == pHostapdAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL",__func__);
return -EINVAL;
}
pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter);
ret = wlan_hdd_validate_context(pHddCtx);
if (0 != ret)
{
return ret;
}
pHddApCtx = WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter);
if (NULL == pHddApCtx)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: AP context is NULL",__func__);
return -EINVAL;
}
hddLog(LOG1,FL("get_WPSPBCProbeReqIEs ioctl"));
memset((void*)&WPSPBCProbeReqIEs, 0, sizeof(WPSPBCProbeReqIEs));
WPSPBCProbeReqIEs.probeReqIELen = pHddApCtx->WPSPBCProbeReq.probeReqIELen;
vos_mem_copy(&WPSPBCProbeReqIEs.probeReqIE,
pHddApCtx->WPSPBCProbeReq.probeReqIE,
WPSPBCProbeReqIEs.probeReqIELen);
vos_mem_copy(&WPSPBCProbeReqIEs.macaddr,
pHddApCtx->WPSPBCProbeReq.peerMacAddr,
sizeof(v_MACADDR_t));
if (copy_to_user(wrqu->data.pointer,
(void *)&WPSPBCProbeReqIEs,
sizeof(WPSPBCProbeReqIEs)))
{
hddLog(LOG1, "%s: failed to copy data to user buffer", __func__);
return -EFAULT;
}
wrqu->data.length = 12 + WPSPBCProbeReqIEs.probeReqIELen;
hddLog(LOG1, FL("Macaddress : "MAC_ADDRESS_STR),
MAC_ADDR_ARRAY(WPSPBCProbeReqIEs.macaddr));
up(&pHddApCtx->semWpsPBCOverlapInd);
EXIT();
return 0;
}
static
int iw_get_WPSPBCProbeReqIEs(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_get_WPSPBCProbeReqIEs(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
/**---------------------------------------------------------------------------
\brief __iw_set_auth_hostap() -
This function sets the auth type received from the wpa_supplicant.
\param - dev - Pointer to the net device.
- info - Pointer to the iw_request_info.
- wrqu - Pointer to the iwreq_data.
- extra - Pointer to the data.
\return - 0 for success, non zero for failure
--------------------------------------------------------------------------*/
int __iw_set_auth_hostap(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,char *extra)
{
hdd_adapter_t *pAdapter;
hdd_context_t *pHddCtx;
hdd_wext_state_t *pWextState;
int ret = 0;
ENTER();
pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
if (NULL == pAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL",__func__);
return -EINVAL;
}
pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
ret = wlan_hdd_validate_context(pHddCtx);
if (0 != ret)
{
return ret;
}
pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
if (NULL == pWextState)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: pWextState is NULL",__func__);
return -EINVAL;
}
switch(wrqu->param.flags & IW_AUTH_INDEX)
{
case IW_AUTH_TKIP_COUNTERMEASURES:
{
if(wrqu->param.value) {
hddLog(VOS_TRACE_LEVEL_INFO_HIGH,
"Counter Measure started %d", wrqu->param.value);
pWextState->mTKIPCounterMeasures = TKIP_COUNTER_MEASURE_STARTED;
}
else {
hddLog(VOS_TRACE_LEVEL_INFO_HIGH,
"Counter Measure stopped=%d", wrqu->param.value);
pWextState->mTKIPCounterMeasures = TKIP_COUNTER_MEASURE_STOPED;
}
hdd_softap_tkip_mic_fail_counter_measure(pAdapter,
wrqu->param.value);
}
break;
default:
hddLog(LOGW, "%s called with unsupported auth type %d", __func__,
wrqu->param.flags & IW_AUTH_INDEX);
break;
}
EXIT();
return 0;
}
int iw_set_auth_hostap(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_set_auth_hostap(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
static int __iw_set_ap_encodeext(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pHostapdAdapter;
v_CONTEXT_t pVosContext;
hdd_context_t *pHddCtx;
hdd_ap_ctx_t *pHddApCtx;
int retval = 0;
VOS_STATUS vstatus;
struct iw_encode_ext *ext = (struct iw_encode_ext*)extra;
v_U8_t groupmacaddr[WNI_CFG_BSSID_LEN] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
int key_index;
struct iw_point *encoding = &wrqu->encoding;
tCsrRoamSetKey setKey;
// tCsrRoamRemoveKey RemoveKey;
int i;
ENTER();
pHostapdAdapter = (netdev_priv(dev));
if (NULL == pHostapdAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL",__func__);
return -EINVAL;
}
pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter);
retval = wlan_hdd_validate_context(pHddCtx);
if (0 != retval)
{
return retval;
}
pVosContext = pHddCtx->pvosContext;
if (NULL == pVosContext)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: pVosContext is NULL",__func__);
return -EINVAL;
}
pHddApCtx = WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter);
if (NULL == pHddApCtx)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: AP Context is NULL",__func__);
return -EINVAL;
}
key_index = encoding->flags & IW_ENCODE_INDEX;
if(key_index > 0) {
/*Convert from 1-based to 0-based keying*/
key_index--;
}
if(!ext->key_len || ext->key_len > CSR_MAX_KEY_LEN) {
#if 0
/*Set the encrytion type to NONE*/
#if 0
pRoamProfile->EncryptionType.encryptionType[0] = eCSR_ENCRYPT_TYPE_NONE;
#endif
RemoveKey.keyId = key_index;
if(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
/*Key direction for group is RX only*/
vos_mem_copy(RemoveKey.peerMac,groupmacaddr,WNI_CFG_BSSID_LEN);
}
else {
vos_mem_copy(RemoveKey.peerMac,ext->addr.sa_data,WNI_CFG_BSSID_LEN);
}
switch(ext->alg)
{
case IW_ENCODE_ALG_NONE:
RemoveKey.encType = eCSR_ENCRYPT_TYPE_NONE;
break;
case IW_ENCODE_ALG_WEP:
RemoveKey.encType = (ext->key_len== 5) ? eCSR_ENCRYPT_TYPE_WEP40:eCSR_ENCRYPT_TYPE_WEP104;
break;
case IW_ENCODE_ALG_TKIP:
RemoveKey.encType = eCSR_ENCRYPT_TYPE_TKIP;
break;
case IW_ENCODE_ALG_CCMP:
RemoveKey.encType = eCSR_ENCRYPT_TYPE_AES;
break;
default:
RemoveKey.encType = eCSR_ENCRYPT_TYPE_NONE;
break;
}
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: Remove key cipher_alg:%d key_len%d *pEncryptionType :%d",
__func__,(int)ext->alg,(int)ext->key_len,RemoveKey.encType);
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO, "%s: Peer Mac = "MAC_ADDRESS_STR,
__func__, MAC_ADDR_ARRAY(RemoveKey.peerMac));
);
vstatus = WLANSAP_DelKeySta( pVosContext, &RemoveKey);
if ( vstatus != VOS_STATUS_SUCCESS )
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "[%4d] WLANSAP_DeleteKeysSta returned ERROR status= %d",
__LINE__, vstatus );
retval = -EINVAL;
}
#endif
return -EINVAL;
}
vos_mem_zero(&setKey,sizeof(tCsrRoamSetKey));
setKey.keyId = key_index;
setKey.keyLength = ext->key_len;
vos_mem_copy(&setKey.Key[0],ext->key,ext->key_len);
if(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
/*Key direction for group is RX only*/
setKey.keyDirection = eSIR_RX_ONLY;
vos_mem_copy(setKey.peerMac,groupmacaddr,WNI_CFG_BSSID_LEN);
}
else {
setKey.keyDirection = eSIR_TX_RX;
vos_mem_copy(setKey.peerMac,ext->addr.sa_data,WNI_CFG_BSSID_LEN);
}
if(ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)
{
setKey.keyDirection = eSIR_TX_DEFAULT;
vos_mem_copy(setKey.peerMac,ext->addr.sa_data,WNI_CFG_BSSID_LEN);
}
/*For supplicant pae role is zero*/
setKey.paeRole = 0;
switch(ext->alg)
{
case IW_ENCODE_ALG_NONE:
setKey.encType = eCSR_ENCRYPT_TYPE_NONE;
break;
case IW_ENCODE_ALG_WEP:
setKey.encType = (ext->key_len== 5) ? eCSR_ENCRYPT_TYPE_WEP40:eCSR_ENCRYPT_TYPE_WEP104;
pHddApCtx->uPrivacy = 1;
hddLog(LOG1, "(%s) uPrivacy=%d", __func__, pHddApCtx->uPrivacy);
break;
case IW_ENCODE_ALG_TKIP:
{
v_U8_t *pKey = &setKey.Key[0];
setKey.encType = eCSR_ENCRYPT_TYPE_TKIP;
vos_mem_zero(pKey, CSR_MAX_KEY_LEN);
/*Supplicant sends the 32bytes key in this order
|--------------|----------|----------|
| Tk1 |TX-MIC | RX Mic |
|--------------|----------|----------|
<---16bytes---><--8bytes--><--8bytes-->
*/
/*Sme expects the 32 bytes key to be in the below order
|--------------|----------|----------|
| Tk1 |RX-MIC | TX Mic |
|--------------|----------|----------|
<---16bytes---><--8bytes--><--8bytes-->
*/
/* Copy the Temporal Key 1 (TK1) */
vos_mem_copy(pKey,ext->key,16);
/*Copy the rx mic first*/
vos_mem_copy(&pKey[16],&ext->key[24],8);
/*Copy the tx mic */
vos_mem_copy(&pKey[24],&ext->key[16],8);
}
break;
case IW_ENCODE_ALG_CCMP:
setKey.encType = eCSR_ENCRYPT_TYPE_AES;
break;
default:
setKey.encType = eCSR_ENCRYPT_TYPE_NONE;
break;
}
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
("%s:EncryptionType:%d key_len:%d, KeyId:%d"), __func__, setKey.encType, setKey.keyLength,
setKey.keyId);
for(i=0; i< ext->key_len; i++)
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
("%02x"), setKey.Key[i]);
vstatus = WLANSAP_SetKeySta( pVosContext, &setKey);
if ( vstatus != VOS_STATUS_SUCCESS )
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"[%4d] WLANSAP_SetKeySta returned ERROR status= %d", __LINE__, vstatus );
retval = -EINVAL;
}
EXIT();
return retval;
}
static int iw_set_ap_encodeext(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_set_ap_encodeext(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
static int __iw_set_ap_mlme(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
#if 0
hdd_adapter_t *pAdapter = (netdev_priv(dev));
struct iw_mlme *mlme = (struct iw_mlme *)extra;
ENTER();
//reason_code is unused. By default it is set to eCSR_DISCONNECT_REASON_UNSPECIFIED
switch (mlme->cmd) {
case IW_MLME_DISASSOC:
case IW_MLME_DEAUTH:
hddLog(LOG1, "Station disassociate");
if( pAdapter->conn_info.connState == eConnectionState_Associated )
{
eCsrRoamDisconnectReason reason = eCSR_DISCONNECT_REASON_UNSPECIFIED;
if( mlme->reason_code == HDD_REASON_MICHAEL_MIC_FAILURE )
reason = eCSR_DISCONNECT_REASON_MIC_ERROR;
status = sme_RoamDisconnect( pAdapter->hHal,pAdapter->sessionId, reason);
//clear all the reason codes
if (status != 0)
{
hddLog(LOGE,"%s %d Command Disassociate/Deauthenticate : csrRoamDisconnect failure returned %d", __func__, (int)mlme->cmd, (int)status);
}
netif_stop_queue(dev);
netif_carrier_off(dev);
}
else
{
hddLog(LOGE,"%s %d Command Disassociate/Deauthenticate called but station is not in associated state", __func__, (int)mlme->cmd);
}
default:
hddLog(LOGE,"%s %d Command should be Disassociate/Deauthenticate", __func__, (int)mlme->cmd);
return -EINVAL;
}//end of switch
EXIT();
#endif
return 0;
// return status;
}
static int iw_set_ap_mlme(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_set_ap_mlme(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
static int __iw_get_ap_rts_threshold(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev));
v_U32_t status = 0;
status = hdd_wlan_get_rts_threshold(pHostapdAdapter, wrqu);
return status;
}
static int iw_get_ap_rts_threshold(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_get_ap_rts_threshold(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
static int __iw_get_ap_frag_threshold(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev));
v_U32_t status = 0;
status = hdd_wlan_get_frag_threshold(pHostapdAdapter, wrqu);
return status;
}
static int iw_get_ap_frag_threshold(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_get_ap_frag_threshold(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
static int __iw_get_ap_freq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *fwrq, char *extra)
{
v_U32_t status = FALSE, channel = 0, freq = 0;
hdd_adapter_t *pHostapdAdapter;
tHalHandle hHal;
hdd_hostapd_state_t *pHostapdState;
hdd_ap_ctx_t *pHddApCtx;
hdd_context_t *pHddCtx;
int ret = 0;
ENTER();
pHostapdAdapter = (netdev_priv(dev));
if (NULL == pHostapdAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL",__func__);
return -EINVAL;
}
pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter);
ret = wlan_hdd_validate_context(pHddCtx);
if (0 != ret)
{
return ret;
}
pHostapdState = WLAN_HDD_GET_HOSTAP_STATE_PTR(pHostapdAdapter);
if (NULL == pHostapdState)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: pHostapdState is NULL",__func__);
return -EINVAL;
}
hHal = WLAN_HDD_GET_HAL_CTX(pHostapdAdapter);
if (NULL == hHal)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Hal Context is NULL",__func__);
return -EINVAL;
}
pHddApCtx = WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter);
if (NULL == pHddApCtx)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: AP context is NULL",__func__);
return -EINVAL;
}
if(pHostapdState->bssState == BSS_STOP )
{
if (ccmCfgGetInt(hHal, WNI_CFG_CURRENT_CHANNEL, &channel)
!= eHAL_STATUS_SUCCESS)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
FL("failed to get WNI_CFG_CURRENT_CHANNEL from cfg"));
return -EIO;
}
else
{
status = hdd_wlan_get_freq(channel, &freq);
if( 0 == status)
{
/* Set Exponent parameter as 6 (MHZ) in struct iw_freq
* iwlist & iwconfig command shows frequency into proper
* format (2.412 GHz instead of 246.2 MHz)*/
fwrq->m = freq;
fwrq->e = MHZ;
}
}
}
else
{
channel = pHddApCtx->operatingChannel;
status = hdd_wlan_get_freq(channel, &freq);
if( 0 == status)
{
/* Set Exponent parameter as 6 (MHZ) in struct iw_freq
* iwlist & iwconfig command shows frequency into proper
* format (2.412 GHz instead of 246.2 MHz)*/
fwrq->m = freq;
fwrq->e = MHZ;
}
}
EXIT();
return 0;
}
static int iw_get_ap_freq(struct net_device *dev,
struct iw_request_info *info,
struct iw_freq *fwrq, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_get_ap_freq(dev, info, fwrq, extra);
vos_ssr_unprotect(__func__);
return ret;
}
static int __iw_softap_stopbss(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
hdd_adapter_t *pHostapdAdapter;
VOS_STATUS status = VOS_STATUS_SUCCESS;
hdd_context_t *pHddCtx = NULL;
ENTER();
pHostapdAdapter = (netdev_priv(dev));
if (NULL == pHostapdAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL",__func__);
return -EINVAL;
}
pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter);
status = wlan_hdd_validate_context(pHddCtx);
if (0 != status) {
return status;
}
if(test_bit(SOFTAP_BSS_STARTED, &pHostapdAdapter->event_flags))
{
hdd_hostapd_state_t *pHostapdState =
WLAN_HDD_GET_HOSTAP_STATE_PTR(pHostapdAdapter);
vos_event_reset(&pHostapdState->vosEvent);
if ( VOS_STATUS_SUCCESS == (status = WLANSAP_StopBss((WLAN_HDD_GET_CTX(pHostapdAdapter))->pvosContext) ) )
{
status = vos_wait_single_event(&pHostapdState->vosEvent, 10000);
if (!VOS_IS_STATUS_SUCCESS(status))
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
("ERROR: HDD vos wait for single_event failed!!"));
VOS_ASSERT(0);
}
}
clear_bit(SOFTAP_BSS_STARTED, &pHostapdAdapter->event_flags);
wlan_hdd_decr_active_session(pHddCtx, pHostapdAdapter->device_mode);
}
EXIT();
return (status == VOS_STATUS_SUCCESS) ? 0 : -EBUSY;
}
static int iw_softap_stopbss(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_softap_stopbss(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
static int __iw_softap_version(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev));
hdd_context_t *pHddCtx;
int ret = 0;
ENTER();
pHostapdAdapter = (netdev_priv(dev));
if (NULL == pHostapdAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL",__func__);
return -EINVAL;
}
pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter);
ret = wlan_hdd_validate_context(pHddCtx);
if (0 != ret)
{
return ret;
}
hdd_wlan_get_version(pHostapdAdapter, wrqu, extra);
EXIT();
return 0;
}
static int iw_softap_version(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_softap_version(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
int hdd_softap_get_sta_info(hdd_adapter_t *pAdapter, v_U8_t *pBuf, int buf_len)
{
v_U8_t i;
int len = 0;
const char sta_info_header[] = "staId staAddress\n";
v_CONTEXT_t pVosContext;
hdd_context_t *pHddCtx;
ptSapContext pSapCtx = NULL;
ENTER();
if (NULL == pAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL",__func__);
return -EINVAL;
}
pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
if (0 != wlan_hdd_validate_context(pHddCtx))
{
return VOS_STATUS_E_FAULT;
}
pVosContext = pHddCtx->pvosContext;
if (NULL == pVosContext)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: VOS context is not valid",__func__);
return VOS_STATUS_E_FAULT;
}
pSapCtx = VOS_GET_SAP_CB(pVosContext);
if(pSapCtx == NULL)
{
VOS_TRACE(VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR,
FL("psapCtx is NULL"));
return VOS_STATUS_E_FAULT;
}
len = snprintf(pBuf, buf_len, sta_info_header);
if (len >= buf_len) {
hddLog(LOGE, FL("Insufficient buffer:%d, %d"), buf_len, len);
return -E2BIG;
}
pBuf += len;
buf_len -= len;
for (i = 0; i < WLAN_MAX_STA_COUNT; i++)
{
if(pSapCtx->aStaInfo[i].isUsed)
{
len = scnprintf(pBuf, buf_len, "%5d .%02x:%02x:%02x:%02x:%02x:%02x\n",
pSapCtx->aStaInfo[i].ucSTAId,
pSapCtx->aStaInfo[i].macAddrSTA.bytes[0],
pSapCtx->aStaInfo[i].macAddrSTA.bytes[1],
pSapCtx->aStaInfo[i].macAddrSTA.bytes[2],
pSapCtx->aStaInfo[i].macAddrSTA.bytes[3],
pSapCtx->aStaInfo[i].macAddrSTA.bytes[4],
pSapCtx->aStaInfo[i].macAddrSTA.bytes[5]);
if (len >= buf_len) {
hddLog(LOGE, FL("Insufficient buffer:%d, %d"), buf_len, len);
return -E2BIG;
}
pBuf += len;
buf_len -= len;
}
if(WE_GET_STA_INFO_SIZE > buf_len)
{
break;
}
}
EXIT();
return 0;
}
static int __iw_softap_get_sta_info(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
hdd_adapter_t *pHostapdAdapter = (netdev_priv(dev));
int ret;
ENTER();
ret = hdd_softap_get_sta_info(pHostapdAdapter, extra, WE_SAP_MAX_STA_INFO);
if (ret) {
hddLog(VOS_TRACE_LEVEL_ERROR, "%s Failed!!!",__func__);
return ret;
}
wrqu->data.length = strlen(extra);
EXIT();
return 0;
}
static int iw_softap_get_sta_info(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_softap_get_sta_info(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
static int __iw_set_ap_genie(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pHostapdAdapter;
hdd_context_t *pHddCtx;
v_CONTEXT_t pVosContext;
eHalStatus halStatus= eHAL_STATUS_SUCCESS;
u_int8_t *genie = (u_int8_t *)extra;
int ret = 0;
ENTER();
pHostapdAdapter = (netdev_priv(dev));
if (NULL == pHostapdAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL",__func__);
return -EINVAL;
}
pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter);
ret = wlan_hdd_validate_context(pHddCtx);
if (0 != ret)
{
return ret;
}
pVosContext = pHddCtx->pvosContext;
if (NULL == pVosContext)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: VOS Context is NULL",__func__);
return -EINVAL;
}
if(!wrqu->data.length)
{
EXIT();
return 0;
}
if (wrqu->data.length > DOT11F_IE_RSN_MAX_LEN)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: WPARSN Ie input length is more than max[%d]", __func__,
wrqu->data.length);
return -EINVAL;
}
switch (genie[0])
{
case DOT11F_EID_WPA:
case DOT11F_EID_RSN:
if((WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter))->uPrivacy == 0)
{
hdd_softap_Deregister_BC_STA(pHostapdAdapter);
hdd_softap_Register_BC_STA(pHostapdAdapter, 1);
}
(WLAN_HDD_GET_AP_CTX_PTR(pHostapdAdapter))->uPrivacy = 1;
halStatus = WLANSAP_Set_WPARSNIes(pVosContext, genie, wrqu->data.length);
break;
default:
hddLog (LOGE, "%s Set UNKNOWN IE %X",__func__, genie[0]);
halStatus = 0;
}
EXIT();
return halStatus;
}
static int iw_set_ap_genie(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_set_ap_genie(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
static VOS_STATUS wlan_hdd_get_classAstats_for_station(hdd_adapter_t *pAdapter, u8 staid)
{
eHalStatus hstatus;
int ret;
void *cookie;
struct hdd_request *request;
struct stats_class_a_ctx *priv;
static const struct hdd_request_params params = {
.priv_size = sizeof(*priv),
.timeout_ms = WLAN_WAIT_TIME_STATS,
};
if (NULL == pAdapter)
{
hddLog(VOS_TRACE_LEVEL_ERROR,"%s: pAdapter is NULL", __func__);
return VOS_STATUS_E_FAULT;
}
request = hdd_request_alloc(&params);
if (!request) {
hddLog(VOS_TRACE_LEVEL_ERROR, FL("Request allocation failure"));
return VOS_STATUS_E_NOMEM;
}
cookie = hdd_request_cookie(request);
hstatus = sme_GetStatistics( WLAN_HDD_GET_HAL_CTX(pAdapter),
eCSR_HDD,
SME_GLOBAL_CLASSA_STATS,
hdd_get_class_a_statistics_cb,
0, // not periodic
FALSE, //non-cached results
staid,
cookie);
if (eHAL_STATUS_SUCCESS != hstatus)
{
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: Unable to retrieve statistics for link speed",
__func__);
}
else
{
ret = hdd_request_wait_for_response(request);
if (ret)
{
hddLog(VOS_TRACE_LEVEL_ERROR,
FL("SME timeout while retrieving link speed"));
}
else
{
priv = hdd_request_priv(request);
pAdapter->hdd_stats.ClassA_stat = priv->class_a_stats;
}
}
/*
* either we never sent a request, we sent a request and received a
* response or we sent a request and timed out. Regardless we are
* done with the request.
*/
hdd_request_put(request);
return VOS_STATUS_SUCCESS;
}
int __iw_get_softap_linkspeed(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
hdd_adapter_t *pHostapdAdapter;
hdd_context_t *pHddCtx;
char *pLinkSpeed = (char*)extra;
char *pmacAddress;
v_U32_t link_speed;
unsigned short staId;
int len = sizeof(v_U32_t)+1;
v_BYTE_t macAddress[VOS_MAC_ADDR_SIZE];
VOS_STATUS status = VOS_STATUS_E_FAILURE;
int rc, valid;
ENTER();
pHostapdAdapter = (netdev_priv(dev));
if (NULL == pHostapdAdapter)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL",__func__);
return -EINVAL;
}
pHddCtx = WLAN_HDD_GET_CTX(pHostapdAdapter);
valid = wlan_hdd_validate_context(pHddCtx);
if (0 != valid)
{
return valid;
}
hddLog(VOS_TRACE_LEVEL_INFO, "%s wrqu->data.length= %d", __func__, wrqu->data.length);
if (wrqu->data.length >= MAC_ADDRESS_STR_LEN - 1)
{
pmacAddress = kmalloc(MAC_ADDRESS_STR_LEN, GFP_KERNEL);
if (NULL == pmacAddress) {
hddLog(LOG1, "unable to allocate memory");
return -ENOMEM;
}
if (copy_from_user((void *)pmacAddress,
wrqu->data.pointer, MAC_ADDRESS_STR_LEN))
{
hddLog(LOG1, "%s: failed to copy data to user buffer", __func__);
kfree(pmacAddress);
return -EFAULT;
}
pmacAddress[MAC_ADDRESS_STR_LEN-1] = '\0';
status = hdd_string_to_hex (pmacAddress, MAC_ADDRESS_STR_LEN, macAddress );
kfree(pmacAddress);
if (!VOS_IS_STATUS_SUCCESS(status ))
{
hddLog(VOS_TRACE_LEVEL_ERROR, FL("String to Hex conversion Failed"));
}
}
/* If no mac address is passed and/or its length is less than 17,
* link speed for first connected client will be returned.
*/
if (wrqu->data.length < 17 || !VOS_IS_STATUS_SUCCESS(status ))
{
status = hdd_softap_GetConnectedStaId(pHostapdAdapter, (void *)(&staId));
}
else
{
status = hdd_softap_GetStaId(pHostapdAdapter,
(v_MACADDR_t *)macAddress, (void *)(&staId));
}
if (!VOS_IS_STATUS_SUCCESS(status))
{
hddLog(VOS_TRACE_LEVEL_ERROR, FL("ERROR: HDD Failed to find sta id!!"));
link_speed = 0;
}
else
{
status = wlan_hdd_get_classAstats_for_station(pHostapdAdapter , staId);
if (!VOS_IS_STATUS_SUCCESS(status ))
{
hddLog(VOS_TRACE_LEVEL_ERROR, FL("Unable to retrieve SME statistics"));
return -EINVAL;
}
WLANTL_GetSTALinkCapacity(pHddCtx->pvosContext,
staId, &link_speed);
link_speed = link_speed / 10;
if (0 == link_speed)
{
/* The linkspeed returned by HAL is in units of 500kbps.
* converting it to mbps.
* This is required to support legacy firmware which does
* not return link capacity.
*/
link_speed =(int)pHostapdAdapter->hdd_stats.ClassA_stat.tx_rate/2;
}
}
wrqu->data.length = len;
rc = snprintf(pLinkSpeed, len, "%u", link_speed);
if ((rc < 0) || (rc >= len))
{
// encoding or length error?
hddLog(VOS_TRACE_LEVEL_ERROR,FL( "Unable to encode link speed"));
return -EIO;
}
EXIT();
return 0;
}
int iw_get_softap_linkspeed(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_get_softap_linkspeed(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
static const iw_handler hostapd_handler[] =
{
(iw_handler) NULL, /* SIOCSIWCOMMIT */
(iw_handler) NULL, /* SIOCGIWNAME */
(iw_handler) NULL, /* SIOCSIWNWID */
(iw_handler) NULL, /* SIOCGIWNWID */
(iw_handler) NULL, /* SIOCSIWFREQ */
(iw_handler) iw_get_ap_freq, /* SIOCGIWFREQ */
(iw_handler) NULL, /* SIOCSIWMODE */
(iw_handler) NULL, /* SIOCGIWMODE */
(iw_handler) NULL, /* SIOCSIWSENS */
(iw_handler) NULL, /* SIOCGIWSENS */
(iw_handler) NULL, /* SIOCSIWRANGE */
(iw_handler) NULL, /* SIOCGIWRANGE */
(iw_handler) NULL, /* SIOCSIWPRIV */
(iw_handler) NULL, /* SIOCGIWPRIV */
(iw_handler) NULL, /* SIOCSIWSTATS */
(iw_handler) NULL, /* SIOCGIWSTATS */
(iw_handler) NULL, /* SIOCSIWSPY */
(iw_handler) NULL, /* SIOCGIWSPY */
(iw_handler) NULL, /* SIOCSIWTHRSPY */
(iw_handler) NULL, /* SIOCGIWTHRSPY */
(iw_handler) NULL, /* SIOCSIWAP */
(iw_handler) NULL, /* SIOCGIWAP */
(iw_handler) iw_set_ap_mlme, /* SIOCSIWMLME */
(iw_handler) NULL, /* SIOCGIWAPLIST */
(iw_handler) NULL, /* SIOCSIWSCAN */
(iw_handler) NULL, /* SIOCGIWSCAN */
(iw_handler) NULL, /* SIOCSIWESSID */
(iw_handler) NULL, /* SIOCGIWESSID */
(iw_handler) NULL, /* SIOCSIWNICKN */
(iw_handler) NULL, /* SIOCGIWNICKN */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* SIOCSIWRATE */
(iw_handler) NULL, /* SIOCGIWRATE */
(iw_handler) NULL, /* SIOCSIWRTS */
(iw_handler) iw_get_ap_rts_threshold, /* SIOCGIWRTS */
(iw_handler) NULL, /* SIOCSIWFRAG */
(iw_handler) iw_get_ap_frag_threshold, /* SIOCGIWFRAG */
(iw_handler) NULL, /* SIOCSIWTXPOW */
(iw_handler) NULL, /* SIOCGIWTXPOW */
(iw_handler) NULL, /* SIOCSIWRETRY */
(iw_handler) NULL, /* SIOCGIWRETRY */
(iw_handler) NULL, /* SIOCSIWENCODE */
(iw_handler) NULL, /* SIOCGIWENCODE */
(iw_handler) NULL, /* SIOCSIWPOWER */
(iw_handler) NULL, /* SIOCGIWPOWER */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) NULL, /* -- hole -- */
(iw_handler) iw_set_ap_genie, /* SIOCSIWGENIE */
(iw_handler) NULL, /* SIOCGIWGENIE */
(iw_handler) iw_set_auth_hostap, /* SIOCSIWAUTH */
(iw_handler) NULL, /* SIOCGIWAUTH */
(iw_handler) iw_set_ap_encodeext, /* SIOCSIWENCODEEXT */
(iw_handler) NULL, /* SIOCGIWENCODEEXT */
(iw_handler) NULL, /* SIOCSIWPMKSA */
};
/*
* Note that the following ioctls were defined with semantics which
* cannot be handled by the "iwpriv" userspace application and hence
* they are not included in the hostapd_private_args array
* QCSAP_IOCTL_ASSOC_STA_MACADDR
*/
static const struct iw_priv_args hostapd_private_args[] = {
{ QCSAP_IOCTL_SETPARAM,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "setparam" },
{ QCSAP_IOCTL_SETPARAM,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "" },
{ QCSAP_PARAM_GET_FRAME_LOGS,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "getFrameLogs" },
{ QCSAP_PARAM_MAX_ASSOC,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setMaxAssoc" },
{ QCSAP_PARAM_HIDE_SSID,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hideSSID" },
{ QCSAP_PARAM_SET_MC_RATE,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setMcRate" },
{ QCSAP_PARAM_SET_PROXIMITY,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setProximity" },
{ QCSAP_PARAM_CAP_TSF,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "cap_tsf" },
{QCSAP_PARAM_SET_CHANNEL_CHANGE,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setChanChange"},
{ QCSAP_PARAM_SET_WOWL,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "wowl" },
{ QCSAP_IOCTL_GETPARAM,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getparam" },
{ QCSAP_IOCTL_GETPARAM, 0,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "" },
{ QCSAP_PARAM_MAX_ASSOC, 0,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getMaxAssoc" },
{ QCSAP_PARAM_GET_WLAN_DBG, 0,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getwlandbg" },
{ QCSAP_PARAM_AUTO_CHANNEL, 0,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getAutoChannel" },
{ QCSAP_PARAM_SET_AUTO_CHANNEL,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setAutoChannel" },
{ QCSAP_PARAM_CLR_ACL, 0,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "setClearAcl" },
{ QCSAP_PARAM_ACL_MODE,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setAclMode" },
{ QCSAP_IOCTL_GET_STAWPAIE,
0, IW_PRIV_TYPE_BYTE | DOT11F_IE_RSN_MAX_LEN, "get_staWPAIE" },
{ QCSAP_IOCTL_STOPBSS,
IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED, 0, "stopbss" },
{ QCSAP_IOCTL_VERSION, 0,
IW_PRIV_TYPE_CHAR | QCSAP_MAX_WSC_IE, "version" },
{ QCSAP_IOCTL_GET_STA_INFO, 0,
IW_PRIV_TYPE_CHAR | WE_SAP_MAX_STA_INFO, "get_sta_info" },
{ QCSAP_IOCTL_GET_WPS_PBC_PROBE_REQ_IES,
IW_PRIV_TYPE_BYTE | sizeof(sQcSapreq_WPSPBCProbeReqIES_t) | IW_PRIV_SIZE_FIXED, 0, "getProbeReqIEs" },
{ QCSAP_IOCTL_GET_CHANNEL, 0,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getchannel" },
{ QCSAP_IOCTL_DISASSOC_STA,
IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 6 , 0, "disassoc_sta" },
{ QCSAP_IOCTL_AP_STATS, 0,
IW_PRIV_TYPE_CHAR | QCSAP_MAX_WSC_IE, "ap_stats" },
/* handlers for main ioctl */
{ QCSAP_IOCTL_PRIV_SET_NONE_GET_THREE_INT, 0,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, "" },
#ifdef WLAN_FEATURE_TSF
{ QCSAP_IOCTL_GET_TSF, 0,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3,
"get_tsf" },
#endif
{ QCSAP_IOCTL_GET_STATS, 0,
IW_PRIV_TYPE_CHAR | QCSAP_MAX_STR_LEN, "getStats"},
{ QCSAP_IOCTL_CLR_STATS, 0, 0, "clearStats" },
{ QCSAP_IOCTL_PRIV_GET_SOFTAP_LINK_SPEED,
IW_PRIV_TYPE_CHAR | 18,
IW_PRIV_TYPE_CHAR | 5, "getLinkSpeed" },
{ QCSAP_IOCTL_PRIV_SET_THREE_INT_GET_NONE,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, "" },
/* handlers for sub-ioctl */
{ WE_SET_WLAN_DBG,
IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3,
0,
"setwlandbg" },
/* handlers for main ioctl */
{ QCSAP_IOCTL_PRIV_SET_VAR_INT_GET_NONE,
IW_PRIV_TYPE_INT | MAX_VAR_ARGS,
0,
"" },
/* handlers for sub-ioctl */
{ WE_LOG_DUMP_CMD,
IW_PRIV_TYPE_INT | MAX_VAR_ARGS,
0,
"dump" },
{ WE_P2P_NOA_CMD,
IW_PRIV_TYPE_INT | MAX_VAR_ARGS,
0,
"SetP2pPs" },
/* handlers for sub ioctl */
{
WE_MCC_CONFIG_CREDENTIAL,
IW_PRIV_TYPE_INT | MAX_VAR_ARGS,
0,
"setMccCrdnl" },
/* handlers for sub ioctl */
{
WE_MCC_CONFIG_PARAMS,
IW_PRIV_TYPE_INT | MAX_VAR_ARGS,
0,
"setMccConfig" },
/* handlers for main ioctl */
{ QCSAP_IOCTL_MODIFY_ACL,
IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 8,
0,
"modify_acl" },
/* handlers for main ioctl */
{ QCSAP_IOCTL_GET_CHANNEL_LIST,
0,
IW_PRIV_TYPE_BYTE | sizeof(tChannelListInfo),
"getChannelList" },
/* handlers for main ioctl */
{ QCSAP_IOCTL_SET_TX_POWER,
IW_PRIV_TYPE_INT| IW_PRIV_SIZE_FIXED | 1,
0,
"setTxPower" },
/* handlers for main ioctl */
{ QCSAP_IOCTL_SET_MAX_TX_POWER,
IW_PRIV_TYPE_INT| IW_PRIV_SIZE_FIXED | 1,
0,
"setTxMaxPower" },
{ QCSAP_IOCTL_DATAPATH_SNAP_SHOT,
IW_PRIV_TYPE_NONE | IW_PRIV_TYPE_NONE,
0,
"dataSnapshot" },
/* handlers for main ioctl */
{ QCSAP_IOCTL_SET_TRAFFIC_MONITOR,
IW_PRIV_TYPE_INT| IW_PRIV_SIZE_FIXED | 1,
0,
"setTrafficMon" },
/* handlers for main ioctl */
{ QCSAP_IOCTL_SET_CHAR_GET_NONE,
IW_PRIV_TYPE_CHAR| 512,
0,
"" },
/* handlers for sub-ioctl */
{ WE_WOWL_ADD_PTRN,
IW_PRIV_TYPE_CHAR| 512,
0,
"wowlAddPtrn" },
{ WE_WOWL_DEL_PTRN,
IW_PRIV_TYPE_CHAR| 512,
0,
"wowlDelPtrn" },
};
static const iw_handler hostapd_private[] = {
[QCSAP_IOCTL_SETPARAM - SIOCIWFIRSTPRIV] = iw_softap_setparam, //set priv ioctl
[QCSAP_IOCTL_GETPARAM - SIOCIWFIRSTPRIV] = iw_softap_getparam, //get priv ioctl
[QCSAP_IOCTL_SET_CHAR_GET_NONE - SIOCIWFIRSTPRIV] =
iw_softap_setchar_getnone,
[QCSAP_IOCTL_GET_STAWPAIE - SIOCIWFIRSTPRIV] = iw_get_genie, //get station genIE
[QCSAP_IOCTL_STOPBSS - SIOCIWFIRSTPRIV] = iw_softap_stopbss, // stop bss
[QCSAP_IOCTL_VERSION - SIOCIWFIRSTPRIV] = iw_softap_version, // get driver version
[QCSAP_IOCTL_GET_WPS_PBC_PROBE_REQ_IES - SIOCIWFIRSTPRIV] = iw_get_WPSPBCProbeReqIEs,
[QCSAP_IOCTL_GET_CHANNEL - SIOCIWFIRSTPRIV] = iw_softap_getchannel,
[QCSAP_IOCTL_ASSOC_STA_MACADDR - SIOCIWFIRSTPRIV] = iw_softap_getassoc_stamacaddr,
[QCSAP_IOCTL_DISASSOC_STA - SIOCIWFIRSTPRIV] = iw_softap_disassoc_sta,
[QCSAP_IOCTL_AP_STATS - SIOCIWFIRSTPRIV] = iw_softap_ap_stats,
[QCSAP_IOCTL_PRIV_SET_NONE_GET_THREE_INT - SIOCIWFIRSTPRIV] = iw_softap_get_three,
[QCSAP_IOCTL_PRIV_SET_THREE_INT_GET_NONE - SIOCIWFIRSTPRIV] = iw_set_three_ints_getnone,
[QCSAP_IOCTL_PRIV_SET_VAR_INT_GET_NONE - SIOCIWFIRSTPRIV] = iw_set_var_ints_getnone,
[QCSAP_IOCTL_SET_CHANNEL_RANGE - SIOCIWFIRSTPRIV] = iw_softap_set_channel_range,
[QCSAP_IOCTL_MODIFY_ACL - SIOCIWFIRSTPRIV] = iw_softap_modify_acl,
[QCSAP_IOCTL_GET_CHANNEL_LIST - SIOCIWFIRSTPRIV] = iw_softap_get_channel_list,
[QCSAP_IOCTL_GET_STA_INFO - SIOCIWFIRSTPRIV] = iw_softap_get_sta_info,
[QCSAP_IOCTL_PRIV_GET_SOFTAP_LINK_SPEED - SIOCIWFIRSTPRIV] = iw_get_softap_linkspeed,
[QCSAP_IOCTL_SET_TX_POWER - SIOCIWFIRSTPRIV] = iw_softap_set_tx_power,
[QCSAP_IOCTL_SET_MAX_TX_POWER - SIOCIWFIRSTPRIV] = iw_softap_set_max_tx_power,
[QCSAP_IOCTL_DATAPATH_SNAP_SHOT - SIOCIWFIRSTPRIV] = iw_display_data_path_snapshot,
[QCSAP_IOCTL_SET_TRAFFIC_MONITOR - SIOCIWFIRSTPRIV] = iw_softap_set_trafficmonitor,
[QCSAP_IOCTL_GET_STATS - SIOCIWFIRSTPRIV] = iw_softap_get_stats,
[QCSAP_IOCTL_CLR_STATS - SIOCIWFIRSTPRIV] = iw_softap_clear_stats,
};
const struct iw_handler_def hostapd_handler_def = {
.num_standard = sizeof(hostapd_handler) / sizeof(hostapd_handler[0]),
.num_private = sizeof(hostapd_private) / sizeof(hostapd_private[0]),
.num_private_args = sizeof(hostapd_private_args) / sizeof(hostapd_private_args[0]),
.standard = (iw_handler *)hostapd_handler,
.private = (iw_handler *)hostapd_private,
.private_args = hostapd_private_args,
.get_wireless_stats = NULL,
};
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29)
struct net_device_ops net_ops_struct = {
.ndo_open = hdd_hostapd_open,
.ndo_stop = hdd_hostapd_stop,
.ndo_uninit = hdd_hostapd_uninit,
.ndo_start_xmit = hdd_softap_hard_start_xmit,
.ndo_tx_timeout = hdd_softap_tx_timeout,
.ndo_get_stats = hdd_softap_stats,
.ndo_set_mac_address = hdd_hostapd_set_mac_address,
.ndo_do_ioctl = hdd_hostapd_ioctl,
.ndo_change_mtu = hdd_hostapd_change_mtu,
.ndo_select_queue = hdd_hostapd_select_queue,
};
#endif
int hdd_set_hostapd(hdd_adapter_t *pAdapter)
{
return VOS_STATUS_SUCCESS;
}
void hdd_set_ap_ops( struct net_device *pWlanHostapdDev )
{
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,29)
pWlanHostapdDev->netdev_ops = &net_ops_struct;
#else
pWlanHostapdDev->open = hdd_hostapd_open;
pWlanHostapdDev->stop = hdd_hostapd_stop;
pWlanHostapdDev->uninit = hdd_hostapd_uninit;
pWlanHostapdDev->hard_start_xmit = hdd_softap_hard_start_xmit;
pWlanHostapdDev->tx_timeout = hdd_softap_tx_timeout;
pWlanHostapdDev->get_stats = hdd_softap_stats;
pWlanHostapdDev->set_mac_address = hdd_hostapd_set_mac_address;
pWlanHostapdDev->do_ioctl = hdd_hostapd_ioctl;
#endif
}
VOS_STATUS hdd_init_ap_mode( hdd_adapter_t *pAdapter, bool re_init)
{
hdd_hostapd_state_t * phostapdBuf;
#ifdef DHCP_SERVER_OFFLOAD
hdd_dhcp_state_t *dhcp_status;
#endif /* DHCP_SERVER_OFFLOAD */
#ifdef MDNS_OFFLOAD
hdd_mdns_state_t *mdns_status;
#endif /* MDNS_OFFLOAD */
struct net_device *dev = pAdapter->dev;
hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
VOS_STATUS status;
hdd_config_t *ini_cfg;
#ifdef FEATURE_WLAN_CH_AVOID
v_U16_t unsafeChannelList[NUM_20MHZ_RF_CHANNELS];
v_U16_t unsafeChannelCount;
#endif /* FEATURE_WLAN_CH_AVOID */
if (pHddCtx->isLogpInProgress && !re_init) {
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"%s:LOGP in Progress. Ignore!!!",__func__);
status = VOS_STATUS_E_FAILURE;
}
ENTER();
#ifdef SAP_AUTH_OFFLOAD
if (pHddCtx->cfg_ini->enable_sap_auth_offload)
{
if (!hdd_set_sap_auth_offload(pAdapter, TRUE))
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
FL("SAP AUTH OFFLOAD is not enabled successfully, Don't start SAP"));
return VOS_STATUS_E_FAILURE;
}
}
#endif
// Allocate the Wireless Extensions state structure
phostapdBuf = WLAN_HDD_GET_HOSTAP_STATE_PTR( pAdapter );
#ifdef DHCP_SERVER_OFFLOAD
dhcp_status = &pAdapter->dhcp_status;
#endif /* DHCP_SERVER_OFFLOAD */
#ifdef MDNS_OFFLOAD
mdns_status = &pAdapter->mdns_status;
#endif /* MDNS_OFFLOAD */
spin_lock_init(&pAdapter->sta_hash_lock);
pAdapter->is_sta_id_hash_initialized = VOS_FALSE;
sme_SetCurrDeviceMode(pHddCtx->hHal, pAdapter->device_mode);
#ifdef FEATURE_WLAN_CH_AVOID
/* Get unsafe cahnnel list from cached location */
wcnss_get_wlan_unsafe_channel(unsafeChannelList,
sizeof(unsafeChannelList),
&unsafeChannelCount);
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"%s : Unsafe Channel count %d",
__func__, unsafeChannelCount);
hdd_hostapd_update_unsafe_channel_list(pHddCtx,
unsafeChannelList,
unsafeChannelCount);
#endif /* FEATURE_WLAN_CH_AVOID */
// Zero the memory. This zeros the profile structure.
memset(phostapdBuf, 0,sizeof(hdd_hostapd_state_t));
#ifdef DHCP_SERVER_OFFLOAD
memset(dhcp_status, 0,sizeof(*dhcp_status));
#endif /* DHCP_SERVER_OFFLOAD */
#ifdef MDNS_OFFLOAD
memset(mdns_status, 0,sizeof(*mdns_status));
#endif /* MDNS_OFFLOAD */
// Set up the pointer to the Wireless Extensions state structure
// NOP
status = hdd_set_hostapd(pAdapter);
if(!VOS_IS_STATUS_SUCCESS(status)) {
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, ("ERROR: hdd_set_hostapd failed!!"));
return status;
}
status = vos_event_init(&phostapdBuf->vosEvent);
if (!VOS_IS_STATUS_SUCCESS(status))
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, ("ERROR: Hostapd HDD vos event init failed!!"));
return status;
}
status = vos_event_init(&phostapdBuf->sta_discon_event);
if (!VOS_IS_STATUS_SUCCESS(status))
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "ERROR: Hostapd HDD sta disassoc event init failed!!");
return status;
}
#ifdef DHCP_SERVER_OFFLOAD
status = vos_event_init(&dhcp_status->vos_event);
if (!VOS_IS_STATUS_SUCCESS(status)) {
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, ("ERROR: Hostapd HDD vos event init failed!!"));
return status;
}
#endif /* DHCP_SERVER_OFFLOAD */
#ifdef MDNS_OFFLOAD
status = vos_event_init(&mdns_status->vos_event);
if (!VOS_IS_STATUS_SUCCESS(status)) {
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
("Hostapd HDD vos event init failed!!"));
return status;
}
#endif /* MDNS_OFFLOAD */
sema_init(&(WLAN_HDD_GET_AP_CTX_PTR(pAdapter))->semWpsPBCOverlapInd, 1);
// Register as a wireless device
dev->wireless_handlers = (struct iw_handler_def *)& hostapd_handler_def;
//Initialize the data path module
status = hdd_softap_init_tx_rx(pAdapter, re_init);
if ( !VOS_IS_STATUS_SUCCESS( status ))
{
hddLog(VOS_TRACE_LEVEL_FATAL, "%s: hdd_softap_init_tx_rx failed", __func__);
}
status = hdd_wmm_adapter_init( pAdapter );
if (!VOS_IS_STATUS_SUCCESS(status))
{
hddLog(VOS_TRACE_LEVEL_ERROR,
"hdd_wmm_adapter_init() failed with status code %08d [x%08x]",
status, status );
goto error_wmm_init;
}
set_bit(WMM_INIT_DONE, &pAdapter->event_flags);
ini_cfg = pHddCtx->cfg_ini;
if (re_init && ini_cfg) {
hddLog(VOS_TRACE_LEVEL_INFO, FL("start_ch: %d end_ch:%d op_band:%d"),
ini_cfg->apStartChannelNum, ini_cfg->apEndChannelNum,
ini_cfg->apOperatingBand);
WLANSAP_SetChannelRange(WLAN_HDD_GET_HAL_CTX(pAdapter),
ini_cfg->apStartChannelNum,
ini_cfg->apEndChannelNum,
ini_cfg->apOperatingBand);
}
return status;
error_wmm_init:
hdd_softap_deinit_tx_rx(pAdapter, re_init);
EXIT();
return status;
}
hdd_adapter_t* hdd_wlan_create_ap_dev( hdd_context_t *pHddCtx, tSirMacAddr macAddr, tANI_U8 *iface_name )
{
struct net_device *pWlanHostapdDev = NULL;
hdd_adapter_t *pHostapdAdapter = NULL;
v_CONTEXT_t pVosContext= NULL;
pWlanHostapdDev = alloc_netdev_mq(sizeof(hdd_adapter_t), iface_name,
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0))
NET_NAME_UNKNOWN,
#endif
ether_setup, NUM_TX_QUEUES);
if (pWlanHostapdDev != NULL)
{
pHostapdAdapter = netdev_priv(pWlanHostapdDev);
//Init the net_device structure
ether_setup(pWlanHostapdDev);
//Initialize the adapter context to zeros.
vos_mem_zero(pHostapdAdapter, sizeof( hdd_adapter_t ));
pHostapdAdapter->dev = pWlanHostapdDev;
pHostapdAdapter->pHddCtx = pHddCtx;
pHostapdAdapter->magic = WLAN_HDD_ADAPTER_MAGIC;
//Get the Global VOSS context.
pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS, NULL);
//Save the adapter context in global context for future.
((VosContextType*)(pVosContext))->pHDDSoftAPContext = (v_VOID_t*)pHostapdAdapter;
//Init the net_device structure
strlcpy(pWlanHostapdDev->name, (const char *)iface_name, IFNAMSIZ);
hdd_set_ap_ops( pHostapdAdapter->dev );
pWlanHostapdDev->watchdog_timeo = HDD_TX_TIMEOUT;
pWlanHostapdDev->mtu = HDD_DEFAULT_MTU;
vos_mem_copy(pWlanHostapdDev->dev_addr, (void *)macAddr,sizeof(tSirMacAddr));
vos_mem_copy(pHostapdAdapter->macAddressCurrent.bytes, (void *)macAddr, sizeof(tSirMacAddr));
pWlanHostapdDev->destructor = free_netdev;
pWlanHostapdDev->ieee80211_ptr = &pHostapdAdapter->wdev ;
pHostapdAdapter->wdev.wiphy = pHddCtx->wiphy;
pHostapdAdapter->wdev.netdev = pWlanHostapdDev;
SET_NETDEV_DEV(pWlanHostapdDev, pHddCtx->parent_dev);
}
return pHostapdAdapter;
}
VOS_STATUS hdd_register_hostapd( hdd_adapter_t *pAdapter, tANI_U8 rtnl_lock_held )
{
struct net_device *dev = pAdapter->dev;
VOS_STATUS status = VOS_STATUS_SUCCESS;
ENTER();
if( rtnl_lock_held )
{
if (strnchr(dev->name, strlen(dev->name), '%')) {
if( dev_alloc_name(dev, dev->name) < 0 )
{
hddLog(VOS_TRACE_LEVEL_FATAL, "%s:Failed:dev_alloc_name", __func__);
return VOS_STATUS_E_FAILURE;
}
}
if (register_netdevice(dev))
{
hddLog(VOS_TRACE_LEVEL_FATAL,
"%s:Failed:register_netdevice", __func__);
return VOS_STATUS_E_FAILURE;
}
}
else
{
if (register_netdev(dev))
{
hddLog(VOS_TRACE_LEVEL_FATAL, "%s: Failed:register_netdev", __func__);
return VOS_STATUS_E_FAILURE;
}
}
set_bit(NET_DEVICE_REGISTERED, &pAdapter->event_flags);
EXIT();
return status;
}
VOS_STATUS hdd_unregister_hostapd(hdd_adapter_t *pAdapter, tANI_U8 rtnl_held)
{
ENTER();
hdd_softap_deinit_tx_rx(pAdapter, false);
/* if we are being called during driver unload, then the dev has already
been invalidated. if we are being called at other times, then we can
detatch the wireless device handlers */
if (pAdapter->dev)
{
if (TRUE == rtnl_held)
{
pAdapter->dev->wireless_handlers = NULL;
}
else
{
rtnl_lock();
pAdapter->dev->wireless_handlers = NULL;
rtnl_unlock();
}
}
EXIT();
return 0;
}
/**
* hdd_sap_indicate_disconnect_for_sta() - Indicate disconnect indication
* to supplicant, if there any clients connected to SAP interface.
* @adapter: sap adapter context
*
* Return: nothing
*/
void hdd_sap_indicate_disconnect_for_sta(hdd_adapter_t *adapter)
{
tSap_Event sap_event;
int staId;
hdd_context_t *hdd_ctx;
v_CONTEXT_t vos_ctx;
ptSapContext sap_ctx;
ENTER();
hdd_ctx = WLAN_HDD_GET_CTX(adapter);
if (NULL == hdd_ctx || NULL == hdd_ctx->cfg_ini) {
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"%s: HDD context is Null", __func__);
return;
}
vos_ctx = hdd_ctx->pvosContext;
if (NULL == vos_ctx) {
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: VOS context is not valid",__func__);
return;
}
sap_ctx = VOS_GET_SAP_CB(vos_ctx);
if (!sap_ctx) {
hddLog(LOGE, FL("invalid sap context"));
return;
}
for (staId = 0; staId < WLAN_MAX_STA_COUNT; staId++) {
if (sap_ctx->aStaInfo[staId].isUsed) {
hddLog(LOG1, FL("staId: %d isUsed: %d %pK"),
staId, sap_ctx->aStaInfo[staId].isUsed,
sap_ctx);
if (vos_is_macaddr_broadcast(
&sap_ctx->aStaInfo[staId].macAddrSTA))
continue;
sap_event.sapHddEventCode = eSAP_STA_DISASSOC_EVENT;
vos_mem_copy(
&sap_event.sapevt.
sapStationDisassocCompleteEvent.staMac,
&sap_ctx->aStaInfo[staId].macAddrSTA,
sizeof(v_MACADDR_t));
sap_event.sapevt.sapStationDisassocCompleteEvent.
reason =
eSAP_MAC_INITATED_DISASSOC;
sap_event.sapevt.sapStationDisassocCompleteEvent.
statusCode =
eSIR_SME_RESOURCES_UNAVAILABLE;
hdd_hostapd_SAPEventCB(&sap_event,
sap_ctx->pUsrContext);
}
}
clear_bit(SOFTAP_BSS_STARTED, &adapter->event_flags);
EXIT();
}
/**
* hdd_sap_destroy_timers() - Destroy sap timers
* @adapter: sap adapter context
*
* Return: nothing
*/
void hdd_sap_destroy_timers(hdd_adapter_t *adapter)
{
hdd_context_t *hdd_ctx;
v_CONTEXT_t vos_ctx;
ptSapContext sap_ctx;
VOS_STATUS status = VOS_STATUS_E_FAILURE;
ENTER();
hdd_ctx = WLAN_HDD_GET_CTX(adapter);
if (NULL == hdd_ctx || NULL == hdd_ctx->cfg_ini) {
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"%s: HDD context is Null", __func__);
return;
}
vos_ctx = hdd_ctx->pvosContext;
if (NULL == vos_ctx) {
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: VOS context is not valid",__func__);
return;
}
sap_ctx = VOS_GET_SAP_CB(vos_ctx);
if (!sap_ctx) {
hddLog(LOGE, FL("invalid sap context"));
return;
}
if (VOS_TIMER_STATE_RUNNING == sap_ctx->sap_HT2040_timer.state) {
status = vos_timer_stop(&sap_ctx->sap_HT2040_timer);
if (!VOS_IS_STATUS_SUCCESS(status))
VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR,
FL("Failed to Stop HT20/40 timer"));
}
status = vos_timer_destroy(&sap_ctx->sap_HT2040_timer);
if (!VOS_IS_STATUS_SUCCESS(status))
VOS_TRACE( VOS_MODULE_ID_SAP, VOS_TRACE_LEVEL_ERROR,
FL("Failed to Destroy HT20/40 timer"));
}
/**
* hdd_force_scc_restart_sap - restart sap to forcer SCC
* @adapter: hdd ap adapter
*
* hdd_force_scc_restart_sap will choose station channel and will
* schedule work to restart the sap.
*
* Return - none
*/
void hdd_force_scc_restart_sap(hdd_adapter_t *adapter,
hdd_context_t *hdd_ctx, tANI_U8 channelId)
{
if (!(adapter && (WLAN_HDD_SOFTAP == adapter->device_mode))) {
return;
}
hddLog(LOG1, FL("Current operation channel %d"),
adapter->sessionCtx.ap.operatingChannel);
hddLog(LOG1, FL("STA channel is %d"),
channelId);
vos_flush_work(
&hdd_ctx->sap_start_work);
hddLog(LOGE,
FL("Restarting SAP for force SCC "));
adapter->sessionCtx.ap.sapConfig.channel = channelId;
if (hdd_ctx->cfg_ini->sap_internal_restart) {
netif_tx_disable(adapter->dev);
schedule_work(&hdd_ctx->sap_start_work);
} else {
hdd_hostapd_stop(adapter->dev);
}
return;
}
/**
* hdd_get_cache_stainfo() - get stainfo for the specified peer
* @stainfo: array of station info
* @mac_addr: mac address of requested peer
*
* This function find the stainfo for the peer with mac_addr
*
* Return: stainfo if found, NULL if not found
*/
struct hdd_cache_sta_info *hdd_get_cache_stainfo(
struct hdd_cache_sta_info *astainfo,
u8 *mac_addr)
{
struct hdd_cache_sta_info *stainfo = NULL;
int i;
for (i = 0; i < WLAN_MAX_STA_COUNT; i++) {
if (vos_mem_compare(&astainfo[i].macAddrSTA,
mac_addr,
HDD_MAC_ADDR_LEN)) {
stainfo = &astainfo[i];
break;
}
}
return stainfo;
}