blob: 83d3b82076a1fc8691b3e3eedccf40dd640c153c [file] [log] [blame]
/*
* Copyright (c) 2011-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_wext.c
\brief Airgo Linux Wireless Extensions Common Control Plane Types and
interfaces.
$Id: wlan_hdd_wext.c,v 1.34 2007/04/14 01:49:23 jimz Exp jimz $This file defines all of the types that are utilized by the CCP module
of the "Portable" HDD. This file also includes the underlying Linux
Wireless Extensions Data types referred to by CCP.
======================================================================== */
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/wireless.h>
#include <macTrace.h>
#include <wlan_hdd_includes.h>
#include <wlan_nlink_common.h>
#include <vos_api.h>
#include <net/arp.h>
#include "ccmApi.h"
#include "sirParams.h"
#include "csrApi.h"
#include "csrInsideApi.h"
#if defined WLAN_FEATURE_VOWIFI
#include "smeRrmInternal.h"
#endif
#include <aniGlobal.h>
#include "dot11f.h"
#include <wlan_hdd_wowl.h>
#include <wlan_hdd_cfg.h>
#include <wlan_hdd_wmm.h>
#include "utilsApi.h"
#include "wlan_hdd_p2p.h"
#ifdef FEATURE_WLAN_TDLS
#include "wlan_hdd_tdls.h"
#endif
#include "ieee80211_common.h"
#include "ol_if_athvar.h"
#include "dbglog_host.h"
#include "wma.h"
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#endif
#include "wlan_hdd_power.h"
#include "qwlan_version.h"
#include "wlan_hdd_host_offload.h"
#include "wlan_hdd_keep_alive.h"
#ifdef WLAN_FEATURE_PACKET_FILTERING
#include "wlan_hdd_packet_filtering.h"
#endif
#include <linux/wireless.h>
#include <net/cfg80211.h>
#include "wlan_qct_tl.h"
#include "wlan_hdd_misc.h"
#include "wlan_hdd_dev_pwr.h"
#include "qc_sap_ioctl.h"
#include "sme_Api.h"
#include "wlan_qct_wda.h"
#include "vos_trace.h"
#include "wlan_hdd_assoc.h"
#include "adf_trace.h"
#ifdef QCA_PKT_PROTO_TRACE
#include "vos_packet.h"
#endif /* QCA_PKT_PROTO_TRACE */
#ifdef CONFIG_HAS_EARLYSUSPEND
#include "wlan_hdd_cfg80211.h"
#endif
#include "wlan_hdd_ocb.h"
#include "wlan_hdd_tsf.h"
#include "vos_nvitem.h"
#include "wlan_hdd_oemdata.h"
#define HDD_FINISH_ULA_TIME_OUT 800
#define HDD_SET_MCBC_FILTERS_TO_FW 1
#define HDD_DELETE_MCBC_FILTERS_FROM_FW 0
static int ioctl_debug;
module_param(ioctl_debug, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
/* To Validate Channel against the Frequency and Vice-Versa */
static const hdd_freq_chan_map_t freq_chan_map[] = { {2412, 1}, {2417, 2},
{2422, 3}, {2427, 4}, {2432, 5}, {2437, 6}, {2442, 7}, {2447, 8},
{2452, 9}, {2457, 10}, {2462, 11}, {2467 ,12}, {2472, 13},
{2484, 14}, {5180, 36}, {5200, 40}, {5220, 44},
{5240, 48}, {5260, 52}, {5280, 56}, {5300, 60}, {5320, 64}, {5500, 100},
{5520, 104}, {5540, 108}, {5560, 112}, {5580, 116}, {5600, 120},
{5620, 124}, {5640, 128}, {5660, 132}, {5680, 136}, {5700, 140},
{5720, 144}, {5745, 149}, {5765, 153}, {5785, 157}, {5805, 161},
{5825, 165}, {5852, 170}, {5855, 171}, {5860, 172}, {5865, 173},
{5870, 174}, {5875, 175}, {5880, 176}, {5885, 177}, {5890, 178},
{5895, 179}, {5900, 180}, {5905, 181}, {5910, 182}, {5915, 183},
{5920, 184} };
#define FREQ_CHAN_MAP_TABLE_SIZE (sizeof(freq_chan_map)/sizeof(freq_chan_map[0]))
#define RC_2_RATE_IDX(_rc) ((_rc) & 0x7)
#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1)
#define RC_2_RATE_IDX_11AC(_rc) ((_rc) & 0xf)
#define HT_RC_2_STREAMS_11AC(_rc) ((((_rc) & 0x30) >> 4) + 1)
/* Private ioctls and their sub-ioctls */
#define WLAN_PRIV_SET_INT_GET_NONE (SIOCIWFIRSTPRIV + 0)
#define WE_SET_11D_STATE 1
#define WE_WOWL 2
#define WE_SET_POWER 3
#define WE_SET_MAX_ASSOC 4
#define WE_SET_SAP_AUTO_CHANNEL_SELECTION 5
#define WE_SET_DATA_INACTIVITY_TO 6
#define WE_SET_MAX_TX_POWER 7
#define WE_SET_HIGHER_DTIM_TRANSITION 8
#define WE_SET_TM_LEVEL 9
#define WE_SET_PHYMODE 10
#define WE_SET_NSS 11
#define WE_SET_LDPC 12
#define WE_SET_TX_STBC 13
#define WE_SET_RX_STBC 14
#define WE_SET_SHORT_GI 15
#define WE_SET_RTSCTS 16
#define WE_SET_CHWIDTH 17
#define WE_SET_ANI_EN_DIS 18
#define WE_SET_ANI_POLL_PERIOD 19
#define WE_SET_ANI_LISTEN_PERIOD 20
#define WE_SET_ANI_OFDM_LEVEL 21
#define WE_SET_ANI_CCK_LEVEL 22
#define WE_SET_DYNAMIC_BW 23
#define WE_SET_TX_CHAINMASK 24
#define WE_SET_RX_CHAINMASK 25
#define WE_SET_11N_RATE 26
#define WE_SET_AMPDU 27
#define WE_SET_AMSDU 28
#define WE_SET_TXPOW_2G 29
#define WE_SET_TXPOW_5G 30
/* Private ioctl for firmware debug log */
#define WE_DBGLOG_LOG_LEVEL 31
#define WE_DBGLOG_VAP_ENABLE 32
#define WE_DBGLOG_VAP_DISABLE 33
#define WE_DBGLOG_MODULE_ENABLE 34
#define WE_DBGLOG_MODULE_DISABLE 35
#define WE_DBGLOG_MOD_LOG_LEVEL 36
#define WE_DBGLOG_TYPE 37
#define WE_SET_TXRX_FWSTATS 38
#define WE_SET_VHT_RATE 39
#define WE_DBGLOG_REPORT_ENABLE 40
#define WE_TXRX_FWSTATS_RESET 41
#define WE_SET_MAX_TX_POWER_2_4 42
#define WE_SET_MAX_TX_POWER_5_0 43
/* 44 is unused */
/* Private ioctl for packet power save */
#define WE_PPS_PAID_MATCH 45
#define WE_PPS_GID_MATCH 46
#define WE_PPS_EARLY_TIM_CLEAR 47
#define WE_PPS_EARLY_DTIM_CLEAR 48
#define WE_PPS_EOF_PAD_DELIM 49
#define WE_PPS_MACADDR_MISMATCH 50
#define WE_PPS_DELIM_CRC_FAIL 51
#define WE_PPS_GID_NSTS_ZERO 52
#define WE_PPS_RSSI_CHECK 53
/* 54 is unused */
#define WE_SET_HTSMPS 55
/* Private ioctl for QPower */
#define WE_SET_QPOWER_MAX_PSPOLL_COUNT 56
#define WE_SET_QPOWER_MAX_TX_BEFORE_WAKE 57
#define WE_SET_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL 58
#define WE_SET_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL 59
#define WE_SET_BURST_ENABLE 60
#define WE_SET_BURST_DUR 61
/* GTX Commands */
#define WE_SET_GTX_HT_MCS 62
#define WE_SET_GTX_VHT_MCS 63
#define WE_SET_GTX_USRCFG 64
#define WE_SET_GTX_THRE 65
#define WE_SET_GTX_MARGIN 66
#define WE_SET_GTX_STEP 67
#define WE_SET_GTX_MINTPC 68
#define WE_SET_GTX_BWMASK 69
/* Private ioctl to configure MCC home channels time quota and latency */
#define WE_MCC_CONFIG_LATENCY 70
#define WE_MCC_CONFIG_QUOTA 71
/* Private IOCTL for debug connection issues */
#define WE_SET_DEBUG_LOG 72
#define WE_SET_SCAN_BAND_PREFERENCE 73
#ifdef WE_SET_TX_POWER
#undef WE_SET_TX_POWER
#endif
#define WE_SET_TX_POWER 74
/* Private ioctl for earlyrx power save feature */
#define WE_SET_EARLY_RX_ADJUST_ENABLE 75
#define WE_SET_EARLY_RX_TGT_BMISS_NUM 76
#define WE_SET_EARLY_RX_BMISS_SAMPLE_CYCLE 77
#define WE_SET_EARLY_RX_SLOP_STEP 78
#define WE_SET_EARLY_RX_INIT_SLOP 79
#define WE_SET_EARLY_RX_ADJUST_PAUSE 80
#define WE_SET_MC_RATE 81
#define WE_SET_EARLY_RX_DRIFT_SAMPLE 82
/* Private ioctl for packet power save */
#define WE_PPS_5G_EBT 83
#define WE_SET_CTS_CBW 84
#define WE_DUMP_STATS 85
#define WE_CLEAR_STATS 86
#define WE_SET_CHANNEL 87
#define WE_SET_MODULATED_DTIM 88
#define WE_SET_MON_FILTER 89
typedef enum eMonFilterType{
MON_MGMT_PKT,
MON_CTRL_PKT,
MON_DATA_PKT,
MON_ALL_PKT,
} tMonFilterType;
#define WE_SET_TDLS_OFFCHANNEL_MODE 90
#define WE_SET_TDLS_OFFCHANNEL 91
#define WE_SET_TDLS_OFFCHANNEL_SEC_OFFSET 92
/* Private ioctls and their sub-ioctls */
#define WLAN_PRIV_SET_NONE_GET_INT (SIOCIWFIRSTPRIV + 1)
#define WE_GET_11D_STATE 1
#define WE_IBSS_STATUS 2
#define WE_SET_SAP_CHANNELS 3
#define WE_GET_WLAN_DBG 4
#define WE_GET_MAX_ASSOC 6
/* 7 is unused */
#define WE_GET_SAP_AUTO_CHANNEL_SELECTION 8
#define WE_GET_CONCURRENCY_MODE 9
#define WE_GET_NSS 11
#define WE_GET_LDPC 12
#define WE_GET_TX_STBC 13
#define WE_GET_RX_STBC 14
#define WE_GET_SHORT_GI 15
#define WE_GET_RTSCTS 16
#define WE_GET_CHWIDTH 17
#define WE_GET_ANI_EN_DIS 18
#define WE_GET_ANI_POLL_PERIOD 19
#define WE_GET_ANI_LISTEN_PERIOD 20
#define WE_GET_ANI_OFDM_LEVEL 21
#define WE_GET_ANI_CCK_LEVEL 22
#define WE_GET_DYNAMIC_BW 23
#define WE_GET_TX_CHAINMASK 24
#define WE_GET_RX_CHAINMASK 25
#define WE_GET_11N_RATE 26
#define WE_GET_AMPDU 27
#define WE_GET_AMSDU 28
#define WE_GET_TXPOW_2G 29
#define WE_GET_TXPOW_5G 30
/* 31 is unused */
#define WE_GET_PPS_PAID_MATCH 32
#define WE_GET_PPS_GID_MATCH 33
#define WE_GET_PPS_EARLY_TIM_CLEAR 34
#define WE_GET_PPS_EARLY_DTIM_CLEAR 35
#define WE_GET_PPS_EOF_PAD_DELIM 36
#define WE_GET_PPS_MACADDR_MISMATCH 37
#define WE_GET_PPS_DELIM_CRC_FAIL 38
#define WE_GET_PPS_GID_NSTS_ZERO 39
#define WE_GET_PPS_RSSI_CHECK 40
/* Private ioctl for QPower */
#define WE_GET_QPOWER_MAX_PSPOLL_COUNT 41
#define WE_GET_QPOWER_MAX_TX_BEFORE_WAKE 42
#define WE_GET_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL 43
#define WE_GET_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL 44
#define WE_GET_BURST_ENABLE 45
#define WE_GET_BURST_DUR 46
/* GTX Commands */
#define WE_GET_GTX_HT_MCS 47
#define WE_GET_GTX_VHT_MCS 48
#define WE_GET_GTX_USRCFG 49
#define WE_GET_GTX_THRE 50
#define WE_GET_GTX_MARGIN 51
#define WE_GET_GTX_STEP 52
#define WE_GET_GTX_MINTPC 53
#define WE_GET_GTX_BWMASK 54
#define WE_GET_SCAN_BAND_PREFERENCE 55
#define WE_GET_TEMPERATURE 56
#define WE_GET_FW_STATUS 57
#define WE_CAP_TSF 58
/* Private ioctls and their sub-ioctls */
#define WLAN_PRIV_SET_INT_GET_INT (SIOCIWFIRSTPRIV + 2)
/* Private ioctls and their sub-ioctls */
#define WLAN_PRIV_SET_CHAR_GET_NONE (SIOCIWFIRSTPRIV + 3)
#define WE_WOWL_ADD_PTRN 1
#define WE_WOWL_DEL_PTRN 2
#if defined WLAN_FEATURE_VOWIFI
#define WE_NEIGHBOR_REPORT_REQUEST 3
#endif
#define WE_SET_AP_WPS_IE 4 //This is called in station mode to set probe rsp ie.
#define WE_SET_CONFIG 5
/* Private ioctls and their sub-ioctls */
#define WLAN_PRIV_SET_THREE_INT_GET_NONE (SIOCIWFIRSTPRIV + 4)
#define WE_SET_WLAN_DBG 1
#define WE_SET_DP_TRACE 2
#define WE_SET_SAP_CHANNELS 3
/* Private ioctls and their sub-ioctls */
#define WLAN_PRIV_GET_CHAR_SET_NONE (SIOCIWFIRSTPRIV + 5)
#define WE_WLAN_VERSION 1
#define WE_GET_STATS 2
#define WE_GET_CFG 3
#define WE_GET_WMM_STATUS 4
#define WE_GET_CHANNEL_LIST 5
#ifdef WLAN_FEATURE_11AC
#define WE_GET_RSSI 6
#endif
#ifdef FEATURE_WLAN_TDLS
#define WE_GET_TDLS_PEERS 8
#endif
#ifdef WLAN_FEATURE_11W
#define WE_GET_11W_INFO 9
#endif
#define WE_GET_STATES 10
#define WE_GET_IBSS_STA_INFO 11
#define WE_GET_PHYMODE 12
#ifdef FEATURE_OEM_DATA_SUPPORT
#define WE_GET_OEM_DATA_CAP 13
#endif
#define WE_GET_SNR 14
/* Private ioctls and their sub-ioctls */
#define WLAN_PRIV_SET_NONE_GET_NONE (SIOCIWFIRSTPRIV + 6)
#define WE_ENABLE_DXE_STALL_DETECT 6
#define WE_DISPLAY_DXE_SNAP_SHOT 7
#define WE_SET_REASSOC_TRIGGER 8
#define WE_DISPLAY_DATAPATH_SNAP_SHOT 9
#define WE_IBSS_GET_PEER_INFO_ALL 10
#define WE_DUMP_AGC_START 11
#define WE_DUMP_AGC 12
#define WE_DUMP_CHANINFO_START 13
#define WE_DUMP_CHANINFO 14
#define WE_DUMP_WATCHDOG 15
#ifdef CONFIG_ATH_PCIE_ACCESS_DEBUG
#define WE_DUMP_PCIE_LOG 16
#endif
#define WE_GET_RECOVERY_STAT 17
/* Private ioctls and their sub-ioctls */
#define WLAN_PRIV_SET_VAR_INT_GET_NONE (SIOCIWFIRSTPRIV + 7)
#define WE_LOG_DUMP_CMD 1
#define WE_P2P_NOA_CMD 2
//IOCTL to configure MCC params
#define WE_MCC_CONFIG_CREDENTIAL 3
#define WE_MCC_CONFIG_PARAMS 4
#ifdef FEATURE_WLAN_TDLS
#define WE_TDLS_CONFIG_PARAMS 5
#endif
#define WE_IBSS_GET_PEER_INFO 6
#define WE_UNIT_TEST_CMD 7
#define WE_MTRACE_DUMP_CMD 8
#define WE_MTRACE_SELECTIVE_MODULE_LOG_ENABLE_CMD 9
#ifdef WLAN_FEATURE_GPIO_LED_FLASHING
#define WE_LED_FLASHING_PARAM 10
#endif
#ifdef MEMORY_DEBUG
#define WE_MEM_TRACE_DUMP 11
#endif
#ifdef FEATURE_WLAN_TDLS
#undef MAX_VAR_ARGS
#define MAX_VAR_ARGS 11
#else
#define MAX_VAR_ARGS 7
#endif
/* Private ioctls (with no sub-ioctls) */
/* note that they must be odd so that they have "get" semantics */
#define WLAN_PRIV_ADD_TSPEC (SIOCIWFIRSTPRIV + 9)
#define WLAN_PRIV_DEL_TSPEC (SIOCIWFIRSTPRIV + 11)
#define WLAN_PRIV_GET_TSPEC (SIOCIWFIRSTPRIV + 13)
/* (SIOCIWFIRSTPRIV + 8) is currently unused */
/* (SIOCIWFIRSTPRIV + 16) is currently unused */
/* (SIOCIWFIRSTPRIV + 10) is currently unused */
/* (SIOCIWFIRSTPRIV + 12) is currently unused */
/* (SIOCIWFIRSTPRIV + 14) is currently unused */
#define WLAN_PRIV_SET_NONE_GET_THREE_INT (SIOCIWFIRSTPRIV + 15)
#define WE_GET_TSF 1
/* (SIOCIWFIRSTPRIV + 17) is currently unused */
#define WLAN_GET_ISOLATION (SIOCIWFIRSTPRIV + 19)
#ifdef WLAN_FEATURE_VOWIFI_11R
#define WLAN_PRIV_SET_FTIES (SIOCIWFIRSTPRIV + 20)
#endif
/* Private ioctl for setting the host offload feature */
#define WLAN_PRIV_SET_HOST_OFFLOAD (SIOCIWFIRSTPRIV + 18)
/* Private ioctl to get the statistics */
#define WLAN_GET_WLAN_STATISTICS (SIOCIWFIRSTPRIV + 21)
/* Private ioctl to set the Keep Alive Params */
#define WLAN_SET_KEEPALIVE_PARAMS (SIOCIWFIRSTPRIV + 22)
#ifdef WLAN_FEATURE_PACKET_FILTERING
/* Private ioctl to set the Packet Filtering Params */
#define WLAN_SET_PACKET_FILTER_PARAMS (SIOCIWFIRSTPRIV + 23)
#endif
#ifdef FEATURE_WLAN_SCAN_PNO
/* Private ioctl to get the statistics */
#define WLAN_SET_PNO (SIOCIWFIRSTPRIV + 24)
#endif
#define WLAN_SET_BAND_CONFIG (SIOCIWFIRSTPRIV + 25) /*Don't change this number*/
#define WLAN_PRIV_SET_MCBC_FILTER (SIOCIWFIRSTPRIV + 26)
#define WLAN_PRIV_CLEAR_MCBC_FILTER (SIOCIWFIRSTPRIV + 27)
/* Private ioctl to trigger reassociation */
#define WLAN_SET_POWER_PARAMS (SIOCIWFIRSTPRIV + 29)
/* 802.11p IOCTL */
#define WLAN_SET_DOT11P_CHANNEL_SCHED (SIOCIWFIRSTPRIV + 30)
#define WLAN_GET_LINK_SPEED (SIOCIWFIRSTPRIV + 31)
/* Private ioctls and their sub-ioctls */
#define WLAN_PRIV_SET_TWO_INT_GET_NONE (SIOCIWFIRSTPRIV + 28)
#define WE_SET_SMPS_PARAM 1
#ifdef WLAN_DEBUG
#define WE_SET_FW_CRASH_INJECT 2
#endif
#define WE_SET_MON_MODE_CHAN 3
#define WE_DUMP_DP_TRACE_LEVEL 4
#define WLAN_STATS_INVALID 0
#define WLAN_STATS_RETRY_CNT 1
#define WLAN_STATS_MUL_RETRY_CNT 2
#define WLAN_STATS_TX_FRM_CNT 3
#define WLAN_STATS_RX_FRM_CNT 4
#define WLAN_STATS_FRM_DUP_CNT 5
#define WLAN_STATS_FAIL_CNT 6
#define WLAN_STATS_RTS_FAIL_CNT 7
#define WLAN_STATS_ACK_FAIL_CNT 8
#define WLAN_STATS_RTS_SUC_CNT 9
#define WLAN_STATS_RX_DISCARD_CNT 10
#define WLAN_STATS_RX_ERROR_CNT 11
#define WLAN_STATS_TX_BYTE_CNT 12
#define WLAN_STATS_RX_BYTE_CNT 13
#define WLAN_STATS_RX_RATE 14
#define WLAN_STATS_TX_RATE 15
#define WLAN_STATS_RX_UC_BYTE_CNT 16
#define WLAN_STATS_RX_MC_BYTE_CNT 17
#define WLAN_STATS_RX_BC_BYTE_CNT 18
#define WLAN_STATS_TX_UC_BYTE_CNT 19
#define WLAN_STATS_TX_MC_BYTE_CNT 20
#define WLAN_STATS_TX_BC_BYTE_CNT 21
#define FILL_TLV(__p, __type, __size, __val, __tlen) do { \
if ((__tlen + __size + 2) < WE_MAX_STR_LEN) \
{ \
*__p++ = __type; \
*__p++ = __size; \
memcpy(__p, __val, __size); \
__p += __size; \
__tlen += __size + 2; \
} \
else \
{ \
hddLog(VOS_TRACE_LEVEL_ERROR, "FILL_TLV Failed!!!"); \
} \
} while(0);
#define VERSION_VALUE_MAX_LEN 32
#define TX_PER_TRACKING_DEFAULT_RATIO 5
#define TX_PER_TRACKING_MAX_RATIO 10
#define TX_PER_TRACKING_DEFAULT_WATERMARK 5
#define WLAN_ADAPTER 0
#define P2P_ADAPTER 1
/*MCC Configuration parameters */
enum {
MCC_SCHEDULE_TIME_SLICE_CFG_PARAM = 1,
MCC_MAX_NULL_SEND_TIME_CFG_PARAM,
MCC_TX_EARLY_STOP_TIME_CFG_PARAM,
MCC_RX_DRAIN_TIME_CFG_PARAM,
MCC_CHANNEL_SWITCH_TIME_CFG_PARAM,
MCC_MIN_CHANNEL_TIME_CFG_PARAM,
MCC_PARK_BEFORE_TBTT_CFG_PARAM,
MCC_MIN_AFTER_DTIM_CFG_PARAM,
MCC_TOO_CLOSE_MARGIN_CFG_PARAM,
};
static const struct qwlan_hw qwlan_hw_list[] = {
{
.id = AR6320_REV1_VERSION,
.subid = 0,
.name = "QCA6174_REV1",
},
{
.id = AR6320_REV1_1_VERSION,
.subid = 0x1,
.name = "QCA6174_REV1_1",
},
{
.id = AR6320_REV1_3_VERSION,
.subid = 0x2,
.name = "QCA6174_REV1_3",
},
{
.id = AR6320_REV2_1_VERSION,
.subid = 0x4,
.name = "QCA6174_REV2_1",
},
{
.id = AR6320_REV2_1_VERSION,
.subid = 0x5,
.name = "QCA6174_REV2_2",
},
{
.id = AR6320_REV3_VERSION,
.subid = 0x6,
.name = "QCA6174_REV2.3",
},
{
.id = AR6320_REV3_VERSION,
.subid = 0x8,
.name = "QCA6174_REV3",
},
{
.id = AR6320_REV3_VERSION,
.subid = 0x9,
.name = "QCA6174_REV3_1",
},
{
.id = AR6320_REV3_2_VERSION,
.subid = 0xA,
.name = "QCA6174_REV3_2",
},
{
.id = AR6320_REV3_VERSION,
.subid = 0x0,
.name = "QCA9377_REV1",
},
{
.id = QCA9377_REV1_1_VERSION,
.subid = 0x1,
.name = "QCA93x7_REV1_1",
},
{
.id = QCA9379_REV1_VERSION,
.subid = 0xC,
.name = "QCA9379_REV1",
},
{
.id = QCA9379_REV1_VERSION,
.subid = 0xD,
.name = "QCA9379_REV1_1",
}
};
int hdd_validate_mcc_config(hdd_adapter_t *pAdapter, v_UINT_t staId,
v_UINT_t arg1, v_UINT_t arg2, v_UINT_t arg3);
#ifdef WLAN_FEATURE_PACKET_FILTERING
int wlan_hdd_set_filter(hdd_context_t *pHddCtx, tpPacketFilterCfg pRequest,
v_U8_t sessionId);
#endif
/**---------------------------------------------------------------------------
\brief mem_alloc_copy_from_user_helper -
Helper function to allocate buffer and copy user data.
\param - wrqu - Pointer to IOCTL Data.
len - size
\return - On Success pointer to buffer, On failure NULL
--------------------------------------------------------------------------*/
void *mem_alloc_copy_from_user_helper(const void *wrqu_data, size_t len)
{
u8 *ptr = NULL;
/* in order to protect the code, an extra byte is post appended to the buffer
* and the null termination is added. However, when allocating (len+1) byte
* of memory, we need to make sure that there is no uint overflow when doing
* addition. In theory check len < UINT_MAX protects the uint overflow. For
* wlan private ioctl, the buffer size is much less than UINT_MAX, as a good
* guess, now, it is assumed that the private command buffer size is no
* greater than 4K (4096 bytes). So we use 4096 as the upper boundary for now.
*/
if (len > MAX_USER_COMMAND_SIZE)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"Invalid length");
return NULL;
}
ptr = vos_mem_malloc(len + 1);
if (NULL == ptr)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"unable to allocate memory");
return NULL;
}
if (copy_from_user(ptr, wrqu_data, len))
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: failed to copy data to user buffer", __func__);
vos_mem_free(ptr);
return NULL;
}
ptr[len] = '\0';
return ptr;
}
/**---------------------------------------------------------------------------
\brief hdd_priv_get_data -
Helper function to get compatible struct iw_point passed to ioctl
\param - p_priv_data - pointer to iw_point struct to be filled
wrqu - Pointer to IOCTL Data received from user space
\return - 0 if p_priv_data successfully filled
error otherwise
--------------------------------------------------------------------------*/
int hdd_priv_get_data(struct iw_point *p_priv_data,
union iwreq_data *wrqu)
{
if ((NULL == p_priv_data) || (NULL == wrqu)) {
return -EINVAL;
}
#ifdef CONFIG_COMPAT
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,6,0)) && defined(CONFIG_X86_64)
if (in_compat_syscall()) {
#else
if (is_compat_task()) {
#endif
struct compat_iw_point *p_compat_priv_data;
/* Compat task: typecast to compat structure and copy the members. */
p_compat_priv_data = (struct compat_iw_point *) &wrqu->data;
p_priv_data->pointer = compat_ptr(p_compat_priv_data->pointer);
p_priv_data->length = p_compat_priv_data->length;
p_priv_data->flags = p_compat_priv_data->flags;
} else {
#endif /* #ifdef CONFIG_COMPAT */
/* Non compat task: directly copy the structure. */
memcpy(p_priv_data, &wrqu->data, sizeof(struct iw_point));
#ifdef CONFIG_COMPAT
}
#endif /* #ifdef CONFIG_COMPAT */
return 0;
}
#define WLAN_HDD_MAX_BW_VALUE 5
/**
* wlan_hdd_validate_mon_channel() - check channel number is valid or not
* @channel: channel number
*
* @return: VOS_STATUS
*/
VOS_STATUS wlan_hdd_validate_mon_channel(int channel)
{
uint8_t fValidChannel = FALSE, count = 0;
for (count = RF_CHAN_1; count <= RF_CHAN_165; count++)
{
if ( channel == rfChannels[count].channelNum )
{
fValidChannel = TRUE;
break;
}
}
if (fValidChannel != TRUE)
{
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: Invalid Channel [%d]", __func__, channel);
return VOS_STATUS_E_FAILURE;
}
return VOS_STATUS_SUCCESS;
}
/**
* wlan_hdd_validate_mon_bw() - check bandwidth value is valid or not
* @bw: bandwidth value
*
* @return: VOS_STATUS
*/
VOS_STATUS wlan_hdd_validate_mon_bw(int bw)
{
if (bw >= 0 && bw <= WLAN_HDD_MAX_BW_VALUE)
return VOS_STATUS_SUCCESS;
return VOS_STATUS_E_FAILURE;
}
/**---------------------------------------------------------------------------
\brief hdd_wlan_get_stats -
Helper function to get stats
\param - pAdapter Pointer to the adapter.
wrqu - Pointer to IOCTL REQUEST Data.
extra - Pointer to char
\return - zero on success, non zero value on failure
--------------------------------------------------------------------------*/
int hdd_wlan_get_stats(hdd_adapter_t *pAdapter, v_U16_t *length,
char *buffer, v_U16_t buf_len)
{
hdd_tx_rx_stats_t *pStats = &pAdapter->hdd_stats.hddTxRxStats;
v_U32_t len;
__u32 total_rxPkt = 0, total_rxDropped = 0;
__u32 total_rxDelv = 0, total_rxRefused = 0;
int i = 0, ret;
VOS_STATUS status;
for (; i < NUM_CPUS; i++) {
total_rxPkt += pStats->rxPackets[i];
total_rxDropped += pStats->rxDropped[i];
total_rxDelv += pStats->rxDelivered[i];
total_rxRefused += pStats->rxRefused[i];
}
len = snprintf(buffer, buf_len,
"\nTransmit"
"\n called %u, dropped %u,"
"\n dropped BK %u, BE %u, VI %u, VO %u"
"\n classified BK %u, BE %u, VI %u, VO %u"
"\n completed %u,"
"\n\nReceive Total"
"\n packets %u, dropped %u, delivered %u, refused %u"
"\n",
pStats->txXmitCalled,
pStats->txXmitDropped,
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->txCompleted,
total_rxPkt, total_rxDropped, total_rxDelv, total_rxRefused);
if (len >= buf_len) {
hddLog(LOGE,FL("Insufficient buffer:%d, %d"), buf_len, len);
return -E2BIG;
}
for (i = 0; i < NUM_CPUS; i++) {
ret = snprintf(buffer+len, buf_len-len,
"\nReceive CPU: %d"
"\n packets %u, dropped %u, delivered %u, refused %u",
i, pStats->rxPackets[i], pStats->rxDropped[i],
pStats->rxDelivered[i], pStats->rxRefused[i]);
if (ret >= (buf_len-len)) {
hddLog(LOGE,FL("Insufficient buffer:%d, %d"), (buf_len-len), ret);
return -E2BIG;
}
len += ret;
}
ret = snprintf(buffer+len, buf_len-len,
"\n\nTX_FLOW"
"\nCurrent status %s"
"\ntx-flow timer start count %u"
"\npause count %u, unpause count %u\n",
(pStats->is_txflow_paused == TRUE ? "PAUSED" : "UNPAUSED"),
pStats->txflow_timer_cnt,
pStats->txflow_pause_cnt,
pStats->txflow_unpause_cnt
);
if (ret >= (buf_len-len)) {
hddLog(LOGE,FL("Insufficient buffer:%d, %d"), (buf_len-len), ret);
return -E2BIG;
}
len += ret;
status = WLANTL_Get_llStats(pAdapter->sessionId,
&buffer[len], (buf_len - len));
if (!VOS_IS_STATUS_SUCCESS(status)) {
hddLog(LOGE,FL("Error in getting stats:%d"), ret);
ret = (status == VOS_STATUS_E_NOMEM) ? -E2BIG: -EINVAL;
return ret;
}
*length = strlen(buffer) + 1;
return 0;
}
/**---------------------------------------------------------------------------
\brief hdd_wlan_dump_stats -
Helper function to dump stats
\param - pAdapter Pointer to the adapter.
value - value given by user
\return - none
--------------------------------------------------------------------------*/
void hdd_wlan_dump_stats(hdd_adapter_t *pAdapter, int value)
{
hdd_context_t* hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
switch(value)
{
case WLAN_TXRX_HIST_STATS:
wlan_hdd_display_tx_rx_histogram(hdd_ctx);
break;
case WLAN_HDD_NETIF_OPER_HISTORY:
wlan_hdd_display_netif_queue_history(hdd_ctx);
break;
default:
WLANTL_display_datapath_stats(hdd_ctx->pvosContext, value);
break;
}
}
/**---------------------------------------------------------------------------
\brief hdd_wlan_get_version() -
This function use to get Wlan Driver, Firmware, & Hardware Version.
\param - pAdapter Pointer to the adapter.
wrqu - Pointer to IOCTL REQUEST Data.
extra - Pointer to char
\return - none
--------------------------------------------------------------------------*/
void hdd_wlan_get_version(hdd_adapter_t *pAdapter, union iwreq_data *wrqu,
char *extra)
{
tSirVersionString wcnss_SW_version;
const char *pSWversion;
const char *pHWversion;
v_U32_t MSPId = 0, mSPId = 0, SIId = 0, CRMId = 0;
hdd_context_t *pHddContext;
int i = 0;
pHddContext = WLAN_HDD_GET_CTX(pAdapter);
if (!pHddContext) {
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s:Invalid context, HDD context is null", __func__);
goto error;
}
snprintf(wcnss_SW_version, sizeof(tSirVersionString), "%08x",
pHddContext->target_fw_version);
pSWversion = wcnss_SW_version;
MSPId = (pHddContext->target_fw_version & 0xf0000000) >> 28;
mSPId = (pHddContext->target_fw_version & 0xf000000) >> 24;
SIId = (pHddContext->target_fw_version & 0xf00000) >> 20;
CRMId = pHddContext->target_fw_version & 0x7fff;
for (i = 0; i < ARRAY_SIZE(qwlan_hw_list); i++) {
if (pHddContext->target_hw_version == qwlan_hw_list[i].id &&
pHddContext->target_hw_revision == qwlan_hw_list[i].subid) {
pHWversion = qwlan_hw_list[i].name;
break;
}
}
if (i == ARRAY_SIZE(qwlan_hw_list))
pHWversion = "Unknown";
pHddContext->target_hw_name = pHWversion;
if (wrqu) {
wrqu->data.length = scnprintf(extra, WE_MAX_STR_LEN,
"Host SW:%s, FW:%d.%d.%d.%d, HW:%s",
QWLAN_VERSIONSTR,
MSPId,
mSPId,
SIId,
CRMId,
pHWversion);
} else {
pr_info("Host SW:%s, FW:%d.%d.%d.%d, HW:%s\n",
QWLAN_VERSIONSTR,
MSPId,
mSPId,
SIId,
CRMId,
pHWversion);
}
error:
return;
}
v_MACADDR_t* hdd_wlan_get_ibss_mac_addr_from_staid(hdd_adapter_t *pAdapter, v_U8_t staIdx)
{
v_U8_t idx;
hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
for ( idx = 0; idx < HDD_MAX_NUM_IBSS_STA; idx++ )
{
if ( 0 != pHddStaCtx->conn_info.staId[ idx ] &&
staIdx == pHddStaCtx->conn_info.staId[ idx ])
{
return (&pHddStaCtx->conn_info.peerMacAddress[ idx ]);
}
}
return NULL;
}
eHalStatus hdd_wlan_get_ibss_peer_info(hdd_adapter_t *pAdapter, v_U8_t staIdx)
{
eHalStatus status = eHAL_STATUS_FAILURE;
tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
hdd_station_ctx_t *pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
tSirPeerInfoRspParams *pPeerInfo = &pStaCtx->ibss_peer_info;
status = sme_RequestIBSSPeerInfo(hHal, pAdapter, hdd_get_ibss_peer_info_cb,
VOS_FALSE, staIdx);
INIT_COMPLETION(pAdapter->ibss_peer_info_comp);
if (eHAL_STATUS_SUCCESS == status)
{
unsigned long rc;
rc = wait_for_completion_timeout
(&pAdapter->ibss_peer_info_comp,
msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
if (!rc) {
hddLog(VOS_TRACE_LEVEL_ERROR,
FL("failed wait on ibss_peer_info_comp"));
return eHAL_STATUS_FAILURE;
}
/** Print the peer info */
pr_info("pPeerInfo->numIBSSPeers = %d ", pPeerInfo->numPeers);
pr_info("============================================================");
{
uint8_t mac_addr[VOS_MAC_ADDR_SIZE];
uint32_t tx_rate = pPeerInfo->peerInfoParams[0].txRate;
vos_mem_copy(mac_addr, pPeerInfo->peerInfoParams[0].mac_addr,
sizeof(mac_addr));
pr_info("PEER ADDR : %pM TxRate: %d Mbps RSSI: %d",
mac_addr, (int)tx_rate, (int)pPeerInfo->peerInfoParams[0].rssi);
}
}
else
{
hddLog(VOS_TRACE_LEVEL_WARN,
"%s: Warning: sme_RequestIBSSPeerInfo Request failed", __func__);
}
return status;
}
eHalStatus hdd_wlan_get_ibss_peer_info_all(hdd_adapter_t *pAdapter)
{
eHalStatus status = eHAL_STATUS_FAILURE;
tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
hdd_station_ctx_t *pStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
tSirPeerInfoRspParams *pPeerInfo = &pStaCtx->ibss_peer_info;
int i;
status = sme_RequestIBSSPeerInfo(hHal, pAdapter, hdd_get_ibss_peer_info_cb,
VOS_TRUE, 0xFF);
INIT_COMPLETION(pAdapter->ibss_peer_info_comp);
if (eHAL_STATUS_SUCCESS == status)
{
unsigned long rc;
rc = wait_for_completion_timeout
(&pAdapter->ibss_peer_info_comp,
msecs_to_jiffies(IBSS_PEER_INFO_REQ_TIMOEUT));
if (!rc) {
hddLog(VOS_TRACE_LEVEL_ERROR,
FL("failed wait on ibss_peer_info_comp"));
return eHAL_STATUS_FAILURE;
}
/** Print the peer info */
pr_info("pPeerInfo->numIBSSPeers = %d ", (int)pPeerInfo->numPeers);
pr_info("============================================================");
for (i = 0; i < pPeerInfo->numPeers; i++) {
uint8_t mac_addr[VOS_MAC_ADDR_SIZE];
uint32_t tx_rate;
tx_rate = pPeerInfo->peerInfoParams[i].txRate;
vos_mem_copy(mac_addr, pPeerInfo->peerInfoParams[i].mac_addr,
sizeof(mac_addr));
pr_info(" PEER ADDR : %pM TxRate: %d Mbps RSSI: %d",
mac_addr, (int)tx_rate, (int)pPeerInfo->peerInfoParams[i].rssi);
}
}
else
{
hddLog(VOS_TRACE_LEVEL_WARN,
"%s: Warning: sme_RequestIBSSPeerInfo Request failed", __func__);
}
return status;
}
int hdd_wlan_get_rts_threshold(hdd_adapter_t *pAdapter, union iwreq_data *wrqu)
{
tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
v_U32_t threshold = 0;
hdd_context_t *hdd_ctx;
int ret;
ENTER();
if (NULL == pAdapter) {
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL", __func__);
return -EINVAL;
}
hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
ret = wlan_hdd_validate_context(hdd_ctx);
if (0 != ret)
return ret;
if ( eHAL_STATUS_SUCCESS !=
ccmCfgGetInt(hHal, WNI_CFG_RTS_THRESHOLD, &threshold) )
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,
FL("failed to get ini parameter, WNI_CFG_RTS_THRESHOLD"));
return -EIO;
}
wrqu->rts.value = threshold;
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
("Rts-Threshold=%d!!"), wrqu->rts.value);
EXIT();
return 0;
}
int hdd_wlan_get_frag_threshold(hdd_adapter_t *pAdapter, union iwreq_data *wrqu)
{
tHalHandle hHal;
v_U32_t threshold = 0, ret;
hdd_context_t *hdd_ctx;
ENTER();
if (NULL == pAdapter) {
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Adapter is NULL", __func__);
return -EINVAL;
}
hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
ret = wlan_hdd_validate_context(hdd_ctx);
if (0 != ret)
return ret;
if ( ccmCfgGetInt(hHal, WNI_CFG_FRAGMENTATION_THRESHOLD, &threshold)
!= eHAL_STATUS_SUCCESS )
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,
FL("failed to get ini parameter, WNI_CFG_FRAGMENTATION_THRESHOLD"));
return -EIO;
}
wrqu->frag.value = threshold;
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
("Frag-Threshold=%d!!"), wrqu->frag.value);
EXIT();
return 0;
}
int hdd_wlan_get_freq(v_U32_t channel, v_U32_t *pfreq)
{
int i;
if (channel > 0)
{
for (i=0; i < FREQ_CHAN_MAP_TABLE_SIZE; i++)
{
if (channel == freq_chan_map[i].chan)
{
*pfreq = freq_chan_map[i].freq;
return 1;
}
}
}
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
("Invalid channel no=%d!!"), channel);
return -EINVAL;
}
static v_BOOL_t
hdd_IsAuthTypeRSN( tHalHandle halHandle, eCsrAuthType authType)
{
v_BOOL_t rsnType = VOS_FALSE;
// is the authType supported?
switch (authType)
{
case eCSR_AUTH_TYPE_NONE: //never used
rsnType = eANI_BOOLEAN_FALSE;
break;
// MAC layer authentication types
case eCSR_AUTH_TYPE_OPEN_SYSTEM:
rsnType = eANI_BOOLEAN_FALSE;
break;
case eCSR_AUTH_TYPE_SHARED_KEY:
rsnType = eANI_BOOLEAN_FALSE;
break;
case eCSR_AUTH_TYPE_AUTOSWITCH:
rsnType = eANI_BOOLEAN_FALSE;
break;
// Upper layer authentication types
case eCSR_AUTH_TYPE_WPA:
rsnType = eANI_BOOLEAN_TRUE;
break;
case eCSR_AUTH_TYPE_WPA_PSK:
rsnType = eANI_BOOLEAN_TRUE;
break;
case eCSR_AUTH_TYPE_WPA_NONE:
rsnType = eANI_BOOLEAN_TRUE;
break;
#ifdef WLAN_FEATURE_VOWIFI_11R
case eCSR_AUTH_TYPE_FT_RSN:
#endif
case eCSR_AUTH_TYPE_RSN:
rsnType = eANI_BOOLEAN_TRUE;
break;
#ifdef WLAN_FEATURE_VOWIFI_11R
case eCSR_AUTH_TYPE_FT_RSN_PSK:
#endif
case eCSR_AUTH_TYPE_RSN_PSK:
#ifdef WLAN_FEATURE_11W
case eCSR_AUTH_TYPE_RSN_PSK_SHA256:
case eCSR_AUTH_TYPE_RSN_8021X_SHA256:
#endif
rsnType = eANI_BOOLEAN_TRUE;
break;
//case eCSR_AUTH_TYPE_FAILED:
case eCSR_AUTH_TYPE_UNKNOWN:
rsnType = eANI_BOOLEAN_FALSE;
break;
default:
hddLog(LOGE, FL("%s called with unknown authType - default to Open, None"),
__func__);
rsnType = eANI_BOOLEAN_FALSE;
break;
}
hddLog(LOGE, FL("%s called with authType: %d, returned: %d"),
__func__, authType, rsnType);
return rsnType;
}
static void hdd_GetRssiCB( v_S7_t rssi, tANI_U32 staId, void *pContext )
{
struct statsContext *pStatsContext;
hdd_adapter_t *pAdapter;
if (ioctl_debug)
{
pr_info("%s: rssi [%d] STA [%d] pContext [%pK]\n",
__func__, (int)rssi, (int)staId, pContext);
}
if (NULL == pContext)
{
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: Bad param, pContext [%pK]",
__func__, pContext);
return;
}
pStatsContext = pContext;
pAdapter = pStatsContext->pAdapter;
/* there is a race condition that exists between this callback
function and the caller since the caller could time out either
before or while this code is executing. we use a spinlock to
serialize these actions */
spin_lock(&hdd_context_lock);
if ((NULL == pAdapter) || (PEER_INFO_CONTEXT_MAGIC != pStatsContext->magic))
{
/* the caller presumably timed out so there is nothing we can do */
spin_unlock(&hdd_context_lock);
hddLog(VOS_TRACE_LEVEL_WARN,
"%s: Invalid context, pAdapter [%pK] magic [%08x]",
__func__, pAdapter, pStatsContext->magic);
if (ioctl_debug)
{
pr_info("%s: Invalid context, pAdapter [%pK] magic [%08x]\n",
__func__, pAdapter, pStatsContext->magic);
}
return;
}
/* context is valid so caller is still waiting */
/* paranoia: invalidate the magic */
pStatsContext->magic = 0;
/* copy over the rssi */
pAdapter->rssi = rssi;
if (pAdapter->rssi > 0)
pAdapter->rssi = 0;
/* notify the caller */
complete(&pStatsContext->completion);
/* serialization is complete */
spin_unlock(&hdd_context_lock);
}
static void hdd_GetSnrCB(tANI_S8 snr, tANI_U32 staId, void *pContext)
{
struct statsContext *pStatsContext;
hdd_adapter_t *pAdapter;
if (ioctl_debug)
{
pr_info("%s: snr [%d] STA [%d] pContext [%pK]\n",
__func__, (int)snr, (int)staId, pContext);
}
if (NULL == pContext)
{
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: Bad param, pContext [%pK]",
__func__, pContext);
return;
}
pStatsContext = pContext;
pAdapter = pStatsContext->pAdapter;
/* there is a race condition that exists between this callback
function and the caller since the caller could time out either
before or while this code is executing. we use a spinlock to
serialize these actions */
spin_lock(&hdd_context_lock);
if ((NULL == pAdapter) || (SNR_CONTEXT_MAGIC != pStatsContext->magic))
{
/* the caller presumably timed out so there is nothing we can do */
spin_unlock(&hdd_context_lock);
hddLog(VOS_TRACE_LEVEL_WARN,
"%s: Invalid context, pAdapter [%pK] magic [%08x]",
__func__, pAdapter, pStatsContext->magic);
if (ioctl_debug)
{
pr_info("%s: Invalid context, pAdapter [%pK] magic [%08x]\n",
__func__, pAdapter, pStatsContext->magic);
}
return;
}
/* context is valid so caller is still waiting */
/* paranoia: invalidate the magic */
pStatsContext->magic = 0;
/* copy over the snr */
pAdapter->snr = snr;
/* notify the caller */
complete(&pStatsContext->completion);
/* serialization is complete */
spin_unlock(&hdd_context_lock);
}
VOS_STATUS wlan_hdd_get_rssi(hdd_adapter_t *pAdapter, v_S7_t *rssi_value)
{
struct statsContext context;
hdd_context_t *pHddCtx;
hdd_station_ctx_t *pHddStaCtx;
eHalStatus hstatus;
unsigned long rc;
if (NULL == pAdapter)
{
hddLog(VOS_TRACE_LEVEL_WARN,
"%s: Invalid context, pAdapter", __func__);
return VOS_STATUS_E_FAULT;
}
if ((WLAN_HDD_GET_CTX(pAdapter))->isLogpInProgress)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s:LOGP in Progress. Ignore!!!",__func__);
/* return a cached value */
*rssi_value = pAdapter->rssi;
return VOS_STATUS_SUCCESS;
}
pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
if (eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
hddLog(LOG1, "%s: Not associated, rssi on disconnect %d",
__func__, pAdapter->rssi_on_disconnect);
*rssi_value = pAdapter->rssi_on_disconnect;
return VOS_STATUS_SUCCESS;
}
if (VOS_TRUE == pHddStaCtx->hdd_ReassocScenario)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"%s: Roaming in progress, return cached RSSI", __func__);
*rssi_value = pAdapter->rssi;
return VOS_STATUS_SUCCESS;
}
init_completion(&context.completion);
context.pAdapter = pAdapter;
context.magic = PEER_INFO_CONTEXT_MAGIC;
hstatus = sme_GetRssi(pHddCtx->hHal, hdd_GetRssiCB,
pHddStaCtx->conn_info.staId[ 0 ],
pHddStaCtx->conn_info.bssId, pAdapter->rssi,
&context, pHddCtx->pvosContext);
if (eHAL_STATUS_SUCCESS != hstatus)
{
hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Unable to retrieve RSSI",
__func__);
/* we'll returned a cached value below */
}
else
{
/* request was sent -- wait for the response */
rc = wait_for_completion_timeout(&context.completion,
msecs_to_jiffies(WLAN_WAIT_TIME_STATS));
if (!rc) {
hddLog(VOS_TRACE_LEVEL_ERROR,
FL("SME timed out while retrieving RSSI"));
/* we'll now returned a cached value below */
}
}
/* either we never sent a request, we sent a request and received a
response or we sent a request and timed out. if we never sent a
request or if we sent a request and got a response, we want to
clear the magic out of paranoia. if we timed out there is a
race condition such that the callback function could be
executing at the same time we are. of primary concern is if the
callback function had already verified the "magic" but had not
yet set the completion variable when a timeout occurred. we
serialize these activities by invalidating the magic while
holding a shared spinlock which will cause us to block if the
callback is currently executing */
spin_lock(&hdd_context_lock);
context.magic = 0;
spin_unlock(&hdd_context_lock);
*rssi_value = pAdapter->rssi;
hddLog(LOG1, FL("RSSI = %d"), *rssi_value);
return VOS_STATUS_SUCCESS;
}
VOS_STATUS wlan_hdd_get_snr(hdd_adapter_t *pAdapter, v_S7_t *snr)
{
struct statsContext context;
hdd_context_t *pHddCtx;
hdd_station_ctx_t *pHddStaCtx;
eHalStatus hstatus;
unsigned long rc;
int valid;
ENTER();
if (NULL == pAdapter)
{
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: Invalid context, pAdapter", __func__);
return VOS_STATUS_E_FAULT;
}
pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
valid = wlan_hdd_validate_context(pHddCtx);
if (0 != valid)
return VOS_STATUS_E_FAULT;
pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
init_completion(&context.completion);
context.pAdapter = pAdapter;
context.magic = SNR_CONTEXT_MAGIC;
hstatus = sme_GetSnr(pHddCtx->hHal, hdd_GetSnrCB,
pHddStaCtx->conn_info.staId[ 0 ],
pHddStaCtx->conn_info.bssId,
&context);
if (eHAL_STATUS_SUCCESS != hstatus)
{
hddLog(VOS_TRACE_LEVEL_ERROR,"%s: Unable to retrieve RSSI",
__func__);
/* we'll returned a cached value below */
}
else
{
/* request was sent -- wait for the response */
rc = wait_for_completion_timeout(&context.completion,
msecs_to_jiffies(WLAN_WAIT_TIME_STATS));
if (!rc) {
hddLog(VOS_TRACE_LEVEL_ERROR,
FL("SME timed out while retrieving SNR"));
/* we'll now returned a cached value below */
}
}
/* either we never sent a request, we sent a request and received a
response or we sent a request and timed out. if we never sent a
request or if we sent a request and got a response, we want to
clear the magic out of paranoia. if we timed out there is a
race condition such that the callback function could be
executing at the same time we are. of primary concern is if the
callback function had already verified the "magic" but had not
yet set the completion variable when a timeout occurred. we
serialize these activities by invalidating the magic while
holding a shared spinlock which will cause us to block if the
callback is currently executing */
spin_lock(&hdd_context_lock);
context.magic = 0;
spin_unlock(&hdd_context_lock);
*snr = pAdapter->snr;
EXIT();
return VOS_STATUS_SUCCESS;
}
void hdd_StatisticsCB( void *pStats, void *pContext )
{
hdd_adapter_t *pAdapter = (hdd_adapter_t *)pContext;
hdd_stats_t *pStatsCache = NULL;
hdd_wext_state_t *pWextState;
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
tCsrSummaryStatsInfo *pSummaryStats = NULL;
tCsrGlobalClassAStatsInfo *pClassAStats = NULL;
tCsrGlobalClassBStatsInfo *pClassBStats = NULL;
tCsrGlobalClassCStatsInfo *pClassCStats = NULL;
tCsrGlobalClassDStatsInfo *pClassDStats = NULL;
tCsrPerStaStatsInfo *pPerStaStats = NULL;
if (pAdapter!= NULL)
pStatsCache = &pAdapter->hdd_stats;
pSummaryStats = (tCsrSummaryStatsInfo *)pStats;
pClassAStats = (tCsrGlobalClassAStatsInfo *)( pSummaryStats + 1 );
pClassBStats = (tCsrGlobalClassBStatsInfo *)( pClassAStats + 1 );
pClassCStats = (tCsrGlobalClassCStatsInfo *)( pClassBStats + 1 );
pClassDStats = (tCsrGlobalClassDStatsInfo *)( pClassCStats + 1 );
pPerStaStats = (tCsrPerStaStatsInfo *)( pClassDStats + 1 );
if (pStatsCache!=NULL)
{
// and copy the stats into the cache we keep in the adapter instance structure
vos_mem_copy( &pStatsCache->summary_stat, pSummaryStats, sizeof( pStatsCache->summary_stat ) );
vos_mem_copy( &pStatsCache->ClassA_stat, pClassAStats, sizeof( pStatsCache->ClassA_stat ) );
vos_mem_copy( &pStatsCache->ClassB_stat, pClassBStats, sizeof( pStatsCache->ClassB_stat ) );
vos_mem_copy( &pStatsCache->ClassC_stat, pClassCStats, sizeof( pStatsCache->ClassC_stat ) );
vos_mem_copy( &pStatsCache->ClassD_stat, pClassDStats, sizeof( pStatsCache->ClassD_stat ) );
vos_mem_copy( &pStatsCache->perStaStats, pPerStaStats, sizeof( pStatsCache->perStaStats ) );
}
if (pAdapter) {
pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
vos_status = vos_event_set(&pWextState->vosevent);
if (!VOS_IS_STATUS_SUCCESS(vos_status)) {
hddLog(LOGE, FL("vos_event_set failed"));
return;
}
}
}
void ccmCfgSetCallback(tHalHandle halHandle, tANI_S32 result)
{
v_CONTEXT_t pVosContext;
hdd_context_t *pHddCtx;
VOS_STATUS hdd_reconnect_all_adapters( hdd_context_t *pHddCtx );
#if 0
hdd_wext_state_t *pWextState;
v_U32_t roamId;
#endif
ENTER();
pVosContext = vos_get_global_context(VOS_MODULE_ID_SYS,NULL);
pHddCtx = (hdd_context_t*) vos_get_context(VOS_MODULE_ID_HDD,pVosContext);
if (NULL == pHddCtx)
{
hddLog(VOS_TRACE_LEVEL_ERROR, "%s: Invalid pHddCtx", __func__);
return;
}
#if 0
pWextState = pAdapter->pWextState;
#endif
if (WNI_CFG_NEED_RESTART == result || WNI_CFG_NEED_RELOAD == result)
{
//TODO Verify is this is really used. If yes need to fix it.
hdd_reconnect_all_adapters( pHddCtx );
#if 0
pAdapter->conn_info.connState = eConnectionState_NotConnected;
INIT_COMPLETION(pAdapter->disconnect_comp_var);
vosStatus = sme_RoamDisconnect(halHandle, pAdapter->sessionId, eCSR_DISCONNECT_REASON_UNSPECIFIED);
if(VOS_STATUS_SUCCESS == vosStatus)
wait_for_completion_interruptible_timeout(&pAdapter->disconnect_comp_var,
msecs_to_jiffies(WLAN_WAIT_TIME_DISCONNECT));
sme_RoamConnect(halHandle,
pAdapter->sessionId, &(pWextState->roamProfile),
&roamId);
#endif
}
EXIT();
}
/* hdd_clearRoamProfileIe() - Clear roam profile IEs
* @pAdapter: Adapter handle
*
* Clears roam profile information elements
* Returns: none
*/
void hdd_clearRoamProfileIe( hdd_adapter_t *pAdapter)
{
int i = 0;
hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
ENTER();
if (!pWextState) {
hddLog(LOGE, FL("ERROR: pWextState not found"));
return;
}
/* clear WPA/RSN/WSC IE information in the profile */
pWextState->roamProfile.nWPAReqIELength = 0;
pWextState->roamProfile.pWPAReqIE = (tANI_U8 *)NULL;
pWextState->roamProfile.nRSNReqIELength = 0;
pWextState->roamProfile.pRSNReqIE = (tANI_U8 *)NULL;
#ifdef FEATURE_WLAN_WAPI
pWextState->roamProfile.nWAPIReqIELength = 0;
pWextState->roamProfile.pWAPIReqIE = (tANI_U8 *)NULL;
#endif
pWextState->roamProfile.bWPSAssociation = VOS_FALSE;
pWextState->roamProfile.bOSENAssociation = VOS_FALSE;
pWextState->roamProfile.pAddIEScan = (tANI_U8 *)NULL;
pWextState->roamProfile.nAddIEScanLength = 0;
pWextState->roamProfile.pAddIEAssoc = (tANI_U8 *)NULL;
pWextState->roamProfile.nAddIEAssocLength = 0;
pWextState->roamProfile.EncryptionType.numEntries = 1;
pWextState->roamProfile.EncryptionType.encryptionType[0]
= eCSR_ENCRYPT_TYPE_NONE;
pWextState->roamProfile.mcEncryptionType.numEntries = 1;
pWextState->roamProfile.mcEncryptionType.encryptionType[0]
= eCSR_ENCRYPT_TYPE_NONE;
pWextState->roamProfile.AuthType.numEntries = 1;
pWextState->roamProfile.AuthType.authType[0] = eCSR_AUTH_TYPE_OPEN_SYSTEM;
vos_mem_zero((pWextState->roamProfile.bssid_hint), VOS_MAC_ADDR_SIZE);
#ifdef WLAN_FEATURE_11W
pWextState->roamProfile.MFPEnabled = eANI_BOOLEAN_FALSE;
pWextState->roamProfile.MFPRequired = 0;
pWextState->roamProfile.MFPCapable = 0;
#endif
pWextState->authKeyMgmt = 0;
for (i=0; i < CSR_MAX_NUM_KEY; i++)
pWextState->roamProfile.Keys.KeyLength[i] = 0;
#ifdef FEATURE_WLAN_WAPI
pAdapter->wapi_info.wapiAuthMode = WAPI_AUTH_MODE_OPEN;
pAdapter->wapi_info.nWapiMode = 0;
#endif
vos_mem_zero((void *)(pWextState->req_bssId), VOS_MAC_ADDR_SIZE);
EXIT();
}
void wlan_hdd_ula_done_cb(v_VOID_t *callbackContext)
{
hdd_adapter_t *pAdapter = (hdd_adapter_t*)callbackContext;
if (WLAN_HDD_ADAPTER_MAGIC != pAdapter->magic)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"%s: Invalid pAdapter magic", __func__);
}
else
{
complete(&pAdapter->ula_complete);
}
}
VOS_STATUS wlan_hdd_check_ula_done(hdd_adapter_t *pAdapter)
{
hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
VOS_STATUS vos_status;
unsigned long rc;
if (VOS_FALSE == pHddStaCtx->conn_info.uIsAuthenticated)
{
INIT_COMPLETION(pAdapter->ula_complete);
/*To avoid race condition between the set key and the last EAPOL
packet, notify TL to finish upper layer authentication incase if the
last EAPOL packet pending in the TL queue.*/
vos_status = WLANTL_Finish_ULA(wlan_hdd_ula_done_cb, pAdapter);
if ( vos_status != VOS_STATUS_SUCCESS )
{
VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"[%4d] WLANTL_Finish_ULA returned ERROR status= %d",
__LINE__, vos_status );
return vos_status;
}
rc = wait_for_completion_timeout(&pAdapter->ula_complete,
msecs_to_jiffies(HDD_FINISH_ULA_TIME_OUT));
if (rc <= 0)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
FL("failure wait on ULA to complete %ld"), rc);
/* we'll still fall through and return success since the
* connection may still get established but is just taking
* too long for us to wait */
}
}
return VOS_STATUS_SUCCESS;
}
v_U8_t* wlan_hdd_get_vendor_oui_ie_ptr(v_U8_t *oui, v_U8_t oui_size, v_U8_t *ie, int ie_len)
{
int left = ie_len;
v_U8_t *ptr = ie;
v_U8_t elem_id,elem_len;
v_U8_t eid = 0xDD;
if ( NULL == ie || 0 == ie_len )
return NULL;
while(left >= 2)
{
elem_id = ptr[0];
elem_len = ptr[1];
left -= 2;
if(elem_len > left)
{
hddLog(VOS_TRACE_LEVEL_FATAL,
FL("****Invalid IEs eid = %d elem_len=%d left=%d*****"),
eid,elem_len,left);
return NULL;
}
if ((elem_id == eid) && (elem_len >= oui_size))
{
if(memcmp( &ptr[2], oui, oui_size)==0)
return ptr;
}
left -= elem_len;
ptr += (elem_len + 2);
}
return NULL;
}
/**
* hdd_get_ldpc() - Get adapter LDPC
* @adapter: adapter being queried
* @value: where to store the value
*
* Return: 0 on success, negative errno on failure
*/
int hdd_get_ldpc(hdd_adapter_t *adapter, int *value)
{
tHalHandle hal = WLAN_HDD_GET_HAL_CTX(adapter);
int ret;
ENTER();
ret = sme_GetHTConfig(hal, adapter->sessionId,
WNI_CFG_HT_CAP_INFO_ADVANCE_CODING);
if (ret < 0) {
hddLog(LOGE, FL("Failed to get LDPC value"));
} else {
*value = ret;
ret = 0;
}
return ret;
}
/**
* hdd_set_ldpc() - Set adapter LDPC
* @adapter: adapter being modified
* @value: new LDPC value
*
* Return: 0 on success, negative errno on failure
*/
int hdd_set_ldpc(hdd_adapter_t *adapter, int value)
{
tHalHandle hal = WLAN_HDD_GET_HAL_CTX(adapter);
int ret;
hddLog(LOG1, FL("%d"), value);
if (value) {
/* make sure HT capabilities allow this */
eHalStatus status;
uint32_t cfg_value;
union {
uint16_t cfg_value16;
tSirMacHTCapabilityInfo ht_cap_info;
} u;
status = ccmCfgGetInt(hal, WNI_CFG_HT_CAP_INFO, &cfg_value);
if (eHAL_STATUS_SUCCESS != status) {
hddLog(LOGE, FL("Failed to get HT capability info"));
return -EIO;
}
u.cfg_value16 = cfg_value & 0xFFFF;
if (!u.ht_cap_info.advCodingCap) {
hddLog(LOGE, FL("LDCP not supported"));
return -EINVAL;
}
}
ret = sme_UpdateHTConfig(hal, adapter->sessionId,
WNI_CFG_HT_CAP_INFO_ADVANCE_CODING,
value);
if (ret)
hddLog(LOGE, FL("Failed to set LDPC value"));
return ret;
}
/**
* hdd_get_tx_stbc() - Get adapter TX STBC
* @adapter: adapter being queried
* @value: where to store the value
*
* Return: 0 on success, negative errno on failure
*/
int hdd_get_tx_stbc(hdd_adapter_t *adapter, int *value)
{
tHalHandle hal = WLAN_HDD_GET_HAL_CTX(adapter);
int ret;
ENTER();
ret = sme_GetHTConfig(hal, adapter->sessionId,
WNI_CFG_HT_CAP_INFO_TX_STBC);
if (ret < 0) {
hddLog(LOGE, FL("Failed to get TX STBC value"));
} else {
*value = ret;
ret = 0;
}
return ret;
}
/**
* hdd_set_tx_stbc() - Set adapter TX STBC
* @adapter: adapter being modified
* @value: new TX STBC value
*
* Return: 0 on success, negative errno on failure
*/
int hdd_set_tx_stbc(hdd_adapter_t *adapter, int value)
{
tHalHandle hal = WLAN_HDD_GET_HAL_CTX(adapter);
int ret;
hddLog(LOG1, FL("%d"), value);
if (value) {
/* make sure HT capabilities allow this */
eHalStatus status;
uint32_t cfg_value;
union {
uint16_t cfg_value16;
tSirMacHTCapabilityInfo ht_cap_info;
} u;
status = ccmCfgGetInt(hal, WNI_CFG_HT_CAP_INFO, &cfg_value);
if (eHAL_STATUS_SUCCESS != status) {
hddLog(LOGE, FL("Failed to get HT capability info"));
return -EIO;
}
u.cfg_value16 = cfg_value & 0xFFFF;
if (!u.ht_cap_info.txSTBC) {
hddLog(LOGE, FL("TX STBC not supported"));
return -EINVAL;
}
}
ret = sme_UpdateHTConfig(hal, adapter->sessionId,
WNI_CFG_HT_CAP_INFO_TX_STBC,
value);
if (ret)
hddLog(LOGE, FL("Failed to set TX STBC value"));
return ret;
}
/**
* hdd_get_rx_stbc() - Get adapter RX STBC
* @adapter: adapter being queried
* @value: where to store the value
*
* Return: 0 on success, negative errno on failure
*/
int hdd_get_rx_stbc(hdd_adapter_t *adapter, int *value)
{
tHalHandle hal = WLAN_HDD_GET_HAL_CTX(adapter);
int ret;
ENTER();
ret = sme_GetHTConfig(hal, adapter->sessionId,
WNI_CFG_HT_CAP_INFO_RX_STBC);
if (ret < 0) {
hddLog(LOGE, FL("Failed to get RX STBC value"));
} else {
*value = ret;
ret = 0;
}
return ret;
}
/**
* hdd_set_rx_stbc() - Set adapter RX STBC
* @adapter: adapter being modified
* @value: new RX STBC value
*
* Return: 0 on success, negative errno on failure
*/
int hdd_set_rx_stbc(hdd_adapter_t *adapter, int value)
{
tHalHandle hal = WLAN_HDD_GET_HAL_CTX(adapter);
int ret;
hddLog(LOG1, FL("%d"), value);
if (value) {
/* make sure HT capabilities allow this */
eHalStatus status;
uint32_t cfg_value;
union {
uint16_t cfg_value16;
tSirMacHTCapabilityInfo ht_cap_info;
} u;
status = ccmCfgGetInt(hal, WNI_CFG_HT_CAP_INFO, &cfg_value);
if (eHAL_STATUS_SUCCESS != status) {
hddLog(LOGE, FL("Failed to get HT capability info"));
return -EIO;
}
u.cfg_value16 = cfg_value & 0xFFFF;
if (!u.ht_cap_info.rxSTBC) {
hddLog(LOGE, FL("RX STBC not supported"));
return -EINVAL;
}
}
ret = sme_UpdateHTConfig(hal, adapter->sessionId,
WNI_CFG_HT_CAP_INFO_RX_STBC,
value);
if (ret)
hddLog(LOGE, FL("Failed to set RX STBC value"));
return ret;
}
/**
* __iw_set_commit() - set commit
* @dev: pointer to net_device
* @info: pointer to iw_request_info
* @wrqu: pointer to iwreq_data
* @extra: extra
*
* Return: 0 on success, error number otherwise
*/
static int __iw_set_commit(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *adapter;
hdd_context_t *hdd_ctx;
int ret;
ENTER();
adapter = WLAN_HDD_GET_PRIV_PTR(dev);
hdd_ctx = WLAN_HDD_GET_CTX(adapter);
ret = wlan_hdd_validate_context(hdd_ctx);
if (0 != ret)
return ret;
/* Do nothing for now */
return 0;
}
/**
* iw_set_commit() - SSR wrapper function for __iw_set_commit
* @dev: pointer to net_device
* @info: pointer to iw_request_info
* @wrqu: pointer to iwreq_data
* @extra: extra
*
* Return: 0 on success, error number otherwise
*/
int iw_set_commit(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_set_commit(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
/**
* __iw_get_name() - get name
* @dev: pointer to net_device
* @info: pointer to iw_request_info
* @wrqu: pointer to iwreq_data
* @extra: extra
*
* Return: 0 on success, error number otherwise
*/
static int __iw_get_name(struct net_device *dev,
struct iw_request_info *info,
char *wrqu, char *extra)
{
ENTER();
strlcpy(wrqu, "Qcom:802.11n", IFNAMSIZ);
EXIT();
return 0;
}
/**
* __iw_get_name() - SSR wrapper for __iw_get_name
* @dev: pointer to net_device
* @info: pointer to iw_request_info
* @wrqu: pointer to iwreq_data
* @extra: extra
*
* Return: 0 on success, error number otherwise
*/
static int iw_get_name(struct net_device *dev,
struct iw_request_info *info,
char *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_get_name(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
/**
* __iw_set_mode() - SIOCSIWMODE ioctl handler
* @dev: device upon which the ioctl was received
* @info: ioctl request information
* @wrqu: ioctl request data
* @extra: ioctl extra data
*
* Return: 0 on success, non-zero on error
*/
static int __iw_set_mode(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_wext_state_t *pWextState;
hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
tCsrRoamProfile *pRoamProfile;
eCsrRoamBssType LastBSSType;
eMib_dot11DesiredBssType connectedBssType;
hdd_config_t *pConfig;
struct wireless_dev *wdev;
hdd_context_t *hdd_ctx;
int ret;
ENTER();
hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
ret = wlan_hdd_validate_context(hdd_ctx);
if (0 != ret)
return ret;
pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
wdev = dev->ieee80211_ptr;
pRoamProfile = &pWextState->roamProfile;
LastBSSType = pRoamProfile->BSSType;
hddLog(LOG1, "%s Old Bss type = %d", __func__, LastBSSType);
switch (wrqu->mode)
{
case IW_MODE_ADHOC:
hddLog(LOG1, "%s Setting AP Mode as IW_MODE_ADHOC", __func__);
pRoamProfile->BSSType = eCSR_BSS_TYPE_START_IBSS;
// Set the phymode correctly for IBSS.
pConfig = (WLAN_HDD_GET_CTX(pAdapter))->cfg_ini;
pWextState->roamProfile.phyMode = hdd_cfg_xlate_to_csr_phy_mode(pConfig->dot11Mode);
pAdapter->device_mode = WLAN_HDD_IBSS;
wdev->iftype = NL80211_IFTYPE_ADHOC;
break;
case IW_MODE_INFRA:
hddLog(LOG1, "%s Setting AP Mode as IW_MODE_INFRA", __func__);
pRoamProfile->BSSType = eCSR_BSS_TYPE_INFRASTRUCTURE;
wdev->iftype = NL80211_IFTYPE_STATION;
break;
case IW_MODE_AUTO:
hddLog(LOG1, "%s Setting AP Mode as IW_MODE_AUTO", __func__);
pRoamProfile->BSSType = eCSR_BSS_TYPE_ANY;
break;
default:
hddLog(LOGE, "%s Unknown AP Mode value %d ", __func__, wrqu->mode);
return -EOPNOTSUPP;
}
if ( LastBSSType != pRoamProfile->BSSType )
{
//the BSS mode changed
// We need to issue disconnect if connected or in IBSS disconnect state
if ( hdd_connGetConnectedBssType( WLAN_HDD_GET_STATION_CTX_PTR(pAdapter), &connectedBssType ) ||
( eCSR_BSS_TYPE_START_IBSS == LastBSSType ) )
{
VOS_STATUS vosStatus;
// need to issue a disconnect to CSR.
INIT_COMPLETION(pAdapter->disconnect_comp_var);
vosStatus = sme_RoamDisconnect( WLAN_HDD_GET_HAL_CTX(pAdapter),
pAdapter->sessionId,
eCSR_DISCONNECT_REASON_IBSS_LEAVE );
if(VOS_STATUS_SUCCESS == vosStatus)
{
unsigned long rc;
rc = wait_for_completion_timeout(
&pAdapter->disconnect_comp_var,
msecs_to_jiffies(WLAN_WAIT_TIME_DISCONNECT));
if (!rc)
hddLog(VOS_TRACE_LEVEL_ERROR,
FL("failed wait on disconnect_comp_var"));
}
}
}
EXIT();
return 0;
}
/**
* iw_set_mode() - SSR wrapper for __iw_set_mode()
* @dev: pointer to net_device
* @info: pointer to iw_request_info
* @wrqu: pointer to iwreq_data
* @extra: pointer to extra ioctl payload
*
* Return: 0 on success, error number otherwise
*/
static int iw_set_mode(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_set_mode(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
/**
* __iw_get_mode() - SIOCGIWMODE ioctl handler
* @dev: device upon which the ioctl was received
* @info: ioctl request information
* @wrqu: ioctl request data
* @extra: ioctl extra data
*
* Return: 0 on success, non-zero on error
*/
static int
__iw_get_mode(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_wext_state_t *pWextState;
hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
hdd_context_t *hdd_ctx;
int ret;
ENTER();
hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
ret = wlan_hdd_validate_context(hdd_ctx);
if (0 != ret)
return ret;
pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
switch (pWextState->roamProfile.BSSType) {
case eCSR_BSS_TYPE_INFRASTRUCTURE:
if(VOS_MONITOR_MODE == vos_get_conparam()){
hddLog(LOG1, FL("returns IW_MODE_MONITOR"));
wrqu->mode = IW_MODE_MONITOR;
}else{
hddLog(LOG1, FL("returns IW_MODE_INFRA"));
wrqu->mode = IW_MODE_INFRA;
}
break;
case eCSR_BSS_TYPE_IBSS:
case eCSR_BSS_TYPE_START_IBSS:
hddLog(LOG1, FL("returns IW_MODE_ADHOC"));
wrqu->mode = IW_MODE_ADHOC;
break;
case eCSR_BSS_TYPE_ANY:
default:
hddLog(LOG1, FL("returns IW_MODE_AUTO"));
wrqu->mode = IW_MODE_AUTO;
break;
}
EXIT();
return 0;
}
/**
* iw_get_mode() - SSR wrapper for __iw_get_mode()
* @dev: pointer to net_device
* @info: pointer to iw_request_info
* @wrqu: pointer to iwreq_data
* @extra: pointer to extra ioctl payload
*
* Return: 0 on success, error number otherwise
*/
static int iw_get_mode(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_get_mode(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
/**
* __iw_set_freq() - SIOCSIWFREQ ioctl handler
* @dev: device upon which the ioctl was received
* @info: ioctl request information
* @wrqu: ioctl request data
* @extra: ioctl extra data
*
* Return: 0 on success, non-zero on error
*/
static int __iw_set_freq(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
v_U32_t numChans = 0;
v_U8_t validChan[WNI_CFG_VALID_CHANNEL_LIST_LEN];
v_U32_t indx = 0;
hdd_wext_state_t *pWextState;
hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
tCsrRoamProfile * pRoamProfile;
hdd_context_t *hdd_ctx;
int ret;
ENTER();
hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
ret = wlan_hdd_validate_context(hdd_ctx);
if (0 != ret)
return ret;
pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
pRoamProfile = &pWextState->roamProfile;
hddLog(LOG1,"setCHANNEL ioctl");
/* Link is up then return cant set channel*/
if(eConnectionState_IbssConnected == pHddStaCtx->conn_info.connState ||
eConnectionState_Associated == pHddStaCtx->conn_info.connState)
{
hddLog( LOGE, "IBSS Associated");
return -EOPNOTSUPP;
}
/* Settings by Frequency as input */
if((wrqu->freq.e == 1) && (wrqu->freq.m >= (tANI_U32)2.412e8) &&
(wrqu->freq.m <= (tANI_U32)5.825e8))
{
tANI_U32 freq = wrqu->freq.m / 100000;
while ((indx < FREQ_CHAN_MAP_TABLE_SIZE) && (freq != freq_chan_map[indx].freq))
indx++;
if (indx >= FREQ_CHAN_MAP_TABLE_SIZE)
{
return -EINVAL;
}
wrqu->freq.e = 0;
wrqu->freq.m = freq_chan_map[indx].chan;
}
if (wrqu->freq.e == 0)
{
if((wrqu->freq.m < WNI_CFG_CURRENT_CHANNEL_STAMIN) ||
(wrqu->freq.m > WNI_CFG_CURRENT_CHANNEL_STAMAX))
{
hddLog(LOG1,"%s: Channel [%d] is outside valid range from %d to %d",
__func__, wrqu->freq.m, WNI_CFG_CURRENT_CHANNEL_STAMIN,
WNI_CFG_CURRENT_CHANNEL_STAMAX);
return -EINVAL;
}
numChans = WNI_CFG_VALID_CHANNEL_LIST_LEN;
if (ccmCfgGetStr(hHal, WNI_CFG_VALID_CHANNEL_LIST,
validChan, &numChans) != eHAL_STATUS_SUCCESS){
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,
FL("failed to get ini parameter, WNI_CFG_VALID_CHANNEL_LIST"));
return -EIO;
}
for (indx = 0; indx < numChans; indx++) {
if (wrqu->freq.m == validChan[indx]){
break;
}
}
}
else{
return -EINVAL;
}
if(indx >= numChans)
{
return -EINVAL;
}
/* Set the Operational Channel */
numChans = pRoamProfile->ChannelInfo.numOfChannels = 1;
pHddStaCtx->conn_info.operationChannel = wrqu->freq.m;
pRoamProfile->ChannelInfo.ChannelList = &pHddStaCtx->conn_info.operationChannel;
hddLog(LOG1,"pRoamProfile->operationChannel = %d", wrqu->freq.m);
EXIT();
return ret;
}
/**
* iw_set_freq() - SSR wrapper for __iw_set_freq()
* @dev: pointer to net_device
* @info: pointer to iw_request_info
* @wrqu: pointer to iwreq_data
* @extra: pointer to extra ioctl payload
*
* Return: 0 on success, error number otherwise
*/
static int iw_set_freq(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_set_freq(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
/**
* __iw_get_freq() - SIOCGIWFREQ ioctl handler
* @dev: device upon which the ioctl was received
* @info: ioctl request information
* @fwrq: ioctl frequency data
* @extra: ioctl extra data
*
* Return: 0 on success, non-zero on error
*/
static int __iw_get_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 *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
tHalHandle hHal;
hdd_wext_state_t *pWextState;
tCsrRoamProfile * pRoamProfile;
hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
hdd_context_t *hdd_ctx;
int ret;
ENTER();
hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
ret = wlan_hdd_validate_context(hdd_ctx);
if (0 != ret)
return ret;
pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
pRoamProfile = &pWextState->roamProfile;
if( pHddStaCtx->conn_info.connState== eConnectionState_Associated )
{
if (sme_GetOperationChannel(hHal, &channel, pAdapter->sessionId) != eHAL_STATUS_SUCCESS)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
FL("failed to get operating channel %u"), pAdapter->sessionId);
return -EIO;
}
else
{
status = hdd_wlan_get_freq(channel, &freq);
if( TRUE == 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
{
/* 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 = 0;
fwrq->e = MHZ;
}
return 0;
}
/**
* iw_get_freq() - SSR wrapper for __iw_get_freq()
* @dev: pointer to net_device
* @info: pointer to iw_request_info
* @fwrq: pointer to frequency data
* @extra: pointer to extra ioctl payload
*
* Return: 0 on success, error number otherwise
*/
static int iw_get_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_freq(dev, info, fwrq, extra);
vos_ssr_unprotect(__func__);
return ret;
}
/**
* __iw_get_tx_power() - SIOCGIWTXPOW ioctl handler
* @dev: device upon which the ioctl was received
* @info: ioctl request information
* @wrqu: ioctl request data
* @extra: ioctl extra data
*
* Return: 0 on success, non-zero on error
*/
static int __iw_get_tx_power(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
hdd_context_t *pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
int ret;
ENTER();
ret = wlan_hdd_validate_context(pHddCtx);
if (0 != ret)
return ret;
if(eConnectionState_Associated != pHddStaCtx->conn_info.connState)
{
wrqu->txpower.value = 0;
return 0;
}
wlan_hdd_get_classAstats(pAdapter);
wrqu->txpower.value = pAdapter->hdd_stats.ClassA_stat.max_pwr;
return 0;
}
/**
* iw_get_tx_power() - SSR wrapper for __iw_get_tx_power()
* @dev: pointer to net_device
* @info: pointer to iw_request_info
* @wrqu: pointer to iwreq_data
* @extra: pointer to extra ioctl payload
*
* Return: 0 on success, error number otherwise
*/
static int iw_get_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_get_tx_power(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
/**
* __iw_set_tx_power() - SIOCSIWTXPOW ioctl handler
* @dev: device upon which the ioctl was received
* @info: ioctl request information
* @wrqu: ioctl request data
* @extra: ioctl extra data
*
* Return: 0 on success, non-zero on error
*/
static int __iw_set_tx_power(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
hdd_context_t *hdd_ctx;
int ret;
ENTER();
hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
ret = wlan_hdd_validate_context(hdd_ctx);
if (0 != ret)
return ret;
if ( ccmCfgSetInt(hHal, WNI_CFG_CURRENT_TX_POWER_LEVEL, wrqu->txpower.value, ccmCfgSetCallback, eANI_BOOLEAN_TRUE) != eHAL_STATUS_SUCCESS )
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
FL("failed to set ini parameter, WNI_CFG_CURRENT_TX_POWER_LEVEL"));
return -EIO;
}
EXIT();
return 0;
}
/**
* iw_set_tx_power() - SSR wrapper for __iw_set_tx_power()
* @dev: pointer to net_device
* @info: pointer to iw_request_info
* @wrqu: pointer to iwreq_data
* @extra: pointer to extra ioctl payload
*
* Return: 0 on success, error number otherwise
*/
static int iw_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_set_tx_power(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
/**
* __iw_get_bitrate() - SIOCGIWRATE ioctl handler
* @dev: device upon which the ioctl was received
* @info: ioctl request information
* @wrqu: ioctl request data
* @extra: ioctl extra data
*
* Return: 0 on success, non-zero on error
*/
static int __iw_get_bitrate(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
VOS_STATUS vos_status = VOS_STATUS_SUCCESS;
eHalStatus status = eHAL_STATUS_SUCCESS;
hdd_wext_state_t *pWextState;
hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
hdd_context_t *hdd_ctx;
int ret;
ENTER();
hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
ret = wlan_hdd_validate_context(hdd_ctx);
if (0 != ret)
return ret;
if(eConnectionState_Associated != pHddStaCtx->conn_info.connState) {
wrqu->bitrate.value = 0;
}
else {
status = sme_GetStatistics( WLAN_HDD_GET_HAL_CTX(pAdapter), eCSR_HDD,
SME_SUMMARY_STATS |
SME_GLOBAL_CLASSA_STATS |
SME_GLOBAL_CLASSB_STATS |
SME_GLOBAL_CLASSC_STATS |
SME_GLOBAL_CLASSD_STATS |
SME_PER_STA_STATS,
hdd_StatisticsCB, 0, FALSE,
pHddStaCtx->conn_info.staId[0], pAdapter,
pAdapter->sessionId );
if(eHAL_STATUS_SUCCESS != status)
{
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: Unable to retrieve statistics",
__func__);
return status;
}
pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
vos_status = vos_wait_single_event(&pWextState->vosevent, WLAN_WAIT_TIME_STATS);
if (!VOS_IS_STATUS_SUCCESS(vos_status))
{
hddLog(VOS_TRACE_LEVEL_ERROR,
"%s: SME timeout while retrieving statistics",
__func__);
return VOS_STATUS_E_FAILURE;
}
wrqu->bitrate.value = pAdapter->hdd_stats.ClassA_stat.tx_rate*500*1000;
}
EXIT();
return vos_status;
}
/**
* iw_get_bitrate() - SSR wrapper for __iw_get_bitrate()
* @dev: pointer to net_device
* @info: pointer to iw_request_info
* @wrqu: pointer to iwreq_data
* @extra: pointer to extra ioctl payload
*
* Return: 0 on success, error number otherwise
*/
static int iw_get_bitrate(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_get_bitrate(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
/**
* __iw_set_bitrate() - SIOCSIWRATE ioctl handler
* @dev: device upon which the ioctl was received
* @info: ioctl request information
* @wrqu: ioctl request data
* @extra: ioctl extra data
*
* Return: 0 on success, non-zero on error
*/
static int __iw_set_bitrate(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
hdd_wext_state_t *pWextState;
hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
v_U8_t supp_rates[WNI_CFG_SUPPORTED_RATES_11A_LEN];
v_U32_t a_len = WNI_CFG_SUPPORTED_RATES_11A_LEN;
v_U32_t b_len = WNI_CFG_SUPPORTED_RATES_11B_LEN;
v_U32_t i, rate;
v_U32_t valid_rate = FALSE, active_phy_mode = 0;
hdd_context_t *hdd_ctx;
int ret;
ENTER();
hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
ret = wlan_hdd_validate_context(hdd_ctx);
if (0 != ret)
return ret;
pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
if (eConnectionState_Associated != pHddStaCtx->conn_info.connState)
{
return -ENXIO ;
}
rate = wrqu->bitrate.value;
if (rate == -1)
{
rate = WNI_CFG_FIXED_RATE_AUTO;
valid_rate = TRUE;
}
else if (ccmCfgGetInt(WLAN_HDD_GET_HAL_CTX(pAdapter),
WNI_CFG_DOT11_MODE, &active_phy_mode) == eHAL_STATUS_SUCCESS)
{
if (active_phy_mode == WNI_CFG_DOT11_MODE_11A || active_phy_mode == WNI_CFG_DOT11_MODE_11G
|| active_phy_mode == WNI_CFG_DOT11_MODE_11B)
{
if ((ccmCfgGetStr(WLAN_HDD_GET_HAL_CTX(pAdapter),
WNI_CFG_SUPPORTED_RATES_11A,
supp_rates, &a_len) == eHAL_STATUS_SUCCESS) &&
(ccmCfgGetStr(WLAN_HDD_GET_HAL_CTX(pAdapter),
WNI_CFG_SUPPORTED_RATES_11B,
supp_rates, &b_len) == eHAL_STATUS_SUCCESS))
{
for (i = 0; i < (b_len + a_len); ++i)
{
/* supported rates returned is double the actual rate so we divide it by 2 */
if ((supp_rates[i]&0x7F)/2 == rate)
{
valid_rate = TRUE;
rate = i + WNI_CFG_FIXED_RATE_1MBPS;
break;
}
}
}
}
}
if (valid_rate != TRUE)
{
return -EINVAL;
}
if (ccmCfgSetInt(WLAN_HDD_GET_HAL_CTX(pAdapter),
WNI_CFG_FIXED_RATE, rate,
ccmCfgSetCallback,eANI_BOOLEAN_FALSE) != eHAL_STATUS_SUCCESS)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
FL("failed to set ini parameter, WNI_CFG_FIXED_RATE"));
return -EIO;
}
return 0;
}
/**
* iw_set_bitrate() - SSR wrapper for __iw_set_bitrate()
* @dev: pointer to net_device
* @info: pointer to iw_request_info
* @wrqu: pointer to iwreq_data
* @extra: pointer to extra ioctl payload
*
* Return: 0 on success, error number otherwise
*/
static int iw_set_bitrate(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_set_bitrate(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
/**
* __iw_set_genie() - SIOCSIWGENIE ioctl handler
* @dev: device upon which the ioctl was received
* @info: ioctl request information
* @wrqu: ioctl request data
* @extra: ioctl extra data
*
* Return: 0 on success, non-zero on error
*/
static int __iw_set_genie(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
u_int8_t *genie = NULL;
u_int8_t *base_genie = NULL;
v_U16_t remLen;
hdd_context_t *hdd_ctx;
int ret;
ENTER();
hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
ret = wlan_hdd_validate_context(hdd_ctx);
if (0 != ret)
return ret;
if (!wrqu->data.length) {
hdd_clearRoamProfileIe(pAdapter);
EXIT();
return 0;
}
base_genie = mem_alloc_copy_from_user_helper(wrqu->data.pointer,
wrqu->data.length);
if (NULL == base_genie)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
"mem_alloc_copy_from_user_helper fail");
return -ENOMEM;
}
genie = base_genie;
remLen = wrqu->data.length;
hddLog(LOG1,"iw_set_genie ioctl IE[0x%X], LEN[%d]", genie[0], genie[1]);
/* clear any previous genIE before this call */
memset( &pWextState->genIE, 0, sizeof(pWextState->genIE) );
while (remLen >= 2)
{
v_U16_t eLen = 0;
v_U8_t elementId;
elementId = *genie++;
eLen = *genie++;
remLen -= 2;
hddLog(VOS_TRACE_LEVEL_INFO, "%s: IE[0x%X], LEN[%d]",
__func__, elementId, eLen);
if (remLen < eLen) {
hddLog(LOGE, "Remaining len: %u less than ie len: %u",
remLen, eLen);
ret = -EINVAL;
goto exit;
}
switch ( elementId )
{
case IE_EID_VENDOR:
if ((IE_LEN_SIZE+IE_EID_SIZE+IE_VENDOR_OUI_SIZE) > eLen) /* should have at least OUI */
{
ret = -EINVAL;
goto exit;
}
if (0 == memcmp(&genie[0], "\x00\x50\xf2\x04", 4))
{
v_U16_t curGenIELen = pWextState->genIE.length;
hddLog (VOS_TRACE_LEVEL_INFO, "%s Set WPS OUI(%02x %02x %02x %02x) IE(len %d)",
__func__, genie[0], genie[1], genie[2], genie[3], eLen + 2);
if( SIR_MAC_MAX_IE_LENGTH < (pWextState->genIE.length + eLen) )
{
hddLog(VOS_TRACE_LEVEL_FATAL, "Cannot accommodate genIE. "
"Need bigger buffer space");
VOS_ASSERT(0);
ret = -EINVAL;
goto exit;
}
// save to Additional IE ; it should be accumulated to handle WPS IE + other IE
memcpy( pWextState->genIE.addIEdata + curGenIELen, genie - 2, eLen + 2);
pWextState->genIE.length += eLen + 2;
}
else if (0 == memcmp(&genie[0], "\x00\x50\xf2", 3))
{
hddLog (VOS_TRACE_LEVEL_INFO, "%s Set WPA IE (len %d)",__func__, eLen + 2);
if ((eLen + 2) > (sizeof(pWextState->WPARSNIE)))
{
hddLog(VOS_TRACE_LEVEL_FATAL, "Cannot accommodate genIE. "
"Need bigger buffer space");
ret = -EINVAL;
VOS_ASSERT(0);
goto exit;
}
memset( pWextState->WPARSNIE, 0, MAX_WPA_RSN_IE_LEN );
memcpy( pWextState->WPARSNIE, genie - 2, (eLen + 2));
pWextState->roamProfile.pWPAReqIE = pWextState->WPARSNIE;
pWextState->roamProfile.nWPAReqIELength = eLen + 2;
}
else /* any vendorId except WPA IE should be accumulated to genIE */
{
v_U16_t curGenIELen = pWextState->genIE.length;
hddLog (VOS_TRACE_LEVEL_INFO, "%s Set OUI(%02x %02x %02x %02x) IE(len %d)",
__func__, genie[0], genie[1], genie[2], genie[3], eLen + 2);
if( SIR_MAC_MAX_IE_LENGTH < (pWextState->genIE.length + eLen) )
{
hddLog(VOS_TRACE_LEVEL_FATAL, "Cannot accommodate genIE. "
"Need bigger buffer space");
VOS_ASSERT(0);
ret = -ENOMEM;
goto exit;
}
// save to Additional IE ; it should be accumulated to handle WPS IE + other IE
memcpy( pWextState->genIE.addIEdata + curGenIELen, genie - 2, eLen + 2);
pWextState->genIE.length += eLen + 2;
}
break;
case DOT11F_EID_RSN:
hddLog (LOG1, "%s Set RSN IE (len %d)",__func__, eLen+2);
if ((eLen + 2) > (sizeof(pWextState->WPARSNIE)))
{
hddLog(VOS_TRACE_LEVEL_FATAL, "Cannot accommodate genIE. "
"Need bigger buffer space");
ret = -EINVAL;
VOS_ASSERT(0);
goto exit;
}
memset( pWextState->WPARSNIE, 0, MAX_WPA_RSN_IE_LEN );
memcpy( pWextState->WPARSNIE, genie - 2, (eLen + 2));
pWextState->roamProfile.pRSNReqIE = pWextState->WPARSNIE;
pWextState->roamProfile.nRSNReqIELength = eLen + 2;
break;
default:
hddLog (LOGE, "%s Set UNKNOWN IE %X",__func__, elementId);
goto exit;
}
remLen -= eLen;
/* Move genie only if next element is present */
if (remLen >= 2)
genie += eLen;
}
exit:
EXIT();
vos_mem_free(base_genie);
return ret;
}
/**
* iw_set_genie() - SSR wrapper for __iw_set_genie()
* @dev: pointer to net_device
* @info: pointer to iw_request_info
* @wrqu: pointer to iwreq_data
* @extra: pointer to extra ioctl payload
*
* Return: 0 on success, error number otherwise
*/
static int iw_set_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_genie(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
/**
* __iw_get_genie() - SIOCGIWGENIE ioctl handler
* @dev: device upon which the ioctl was received
* @info: ioctl request information
* @wrqu: ioctl request data
* @extra: ioctl extra data
*
* Return: 0 on success, non-zero on error
*/
static int __iw_get_genie(struct net_device *dev, struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_wext_state_t *pWextState;
hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
hdd_station_ctx_t *pHddStaCtx = WLAN_HDD_GET_STATION_CTX_PTR(pAdapter);
eHalStatus status;
v_U32_t length = DOT11F_IE_RSN_MAX_LEN;
v_U8_t genIeBytes[DOT11F_IE_RSN_MAX_LEN];
hdd_context_t *hdd_ctx;
int ret;
ENTER();
hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
ret = wlan_hdd_validate_context(hdd_ctx);
if (0 != ret)
return ret;
hddLog(LOG1,"getGEN_IE ioctl");
pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
if( pHddStaCtx->conn_info.connState == eConnectionState_NotConnected)
{
return -ENXIO;
}
// Return something ONLY if we are associated with an RSN or WPA network
if ( VOS_TRUE != hdd_IsAuthTypeRSN(WLAN_HDD_GET_HAL_CTX(pAdapter),
pWextState->roamProfile.negotiatedAuthType))
{
return -ENXIO;
}
// Actually retrieve the RSN IE from CSR. (We previously sent it down in the CSR Roam Profile.)
status = csrRoamGetWpaRsnReqIE(WLAN_HDD_GET_HAL_CTX(pAdapter),
pAdapter->sessionId,
&length,
genIeBytes);
if (eHAL_STATUS_SUCCESS != status) {
hddLog(LOGE, FL("failed to get WPA-RSN IE data"));
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, (v_VOID_t*)genIeBytes, length);
hddLog(LOG1, FL("RSN IE of %d bytes returned"), wrqu->data.length );
EXIT();
return 0;
}
/**
* iw_get_genie() - SSR wrapper for __iw_get_genie()
* @dev: pointer to net_device
* @info: pointer to iw_request_info
* @wrqu: pointer to iwreq_data
* @extra: pointer to extra ioctl payload
*
* Return: 0 on success, error number otherwise
*/
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;
}
/**
* __iw_get_encode() - SIOCGIWENCODE ioctl handler
* @dev: device upon which the ioctl was received
* @info: ioctl request information
* @dwrq: ioctl request data
* @extra: ioctl extra data
*
* Return: 0 on success, non-zero on error
*/
static int __iw_get_encode(struct net_device *dev, struct iw_request_info *info,
struct iw_point *dwrq, char *extra)
{
hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
hdd_wext_state_t *pWextState = WLAN_HDD_GET_WEXT_STATE_PTR(pAdapter);
tCsrRoamProfile *pRoamProfile = &(pWextState->roamProfile);
int keyId;
eCsrAuthType authType = eCSR_AUTH_TYPE_NONE;
int i;
hdd_context_t *hdd_ctx;
int ret;
ENTER();
hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
ret = wlan_hdd_validate_context(hdd_ctx);
if (0 != ret)
return ret;
keyId = pRoamProfile->Keys.defaultIndex;
if(keyId < 0 || keyId >= MAX_WEP_KEYS)
{
hddLog(LOG1,"%s: Invalid keyId : %d", __func__, keyId);
return -EINVAL;
}
if(pRoamProfile->Keys.KeyLength[keyId] > 0)
{
dwrq->flags |= IW_ENCODE_ENABLED;
dwrq->length = pRoamProfile->Keys.KeyLength[keyId];
vos_mem_copy(extra,&(pRoamProfile->Keys.KeyMaterial[keyId][0]),pRoamProfile->Keys.KeyLength[keyId]);
dwrq->flags |= (keyId + 1);
}
else
{
dwrq->flags |= IW_ENCODE_DISABLED;
}
for(i=0; i < MAX_WEP_KEYS; i++)
{
if (pRoamProfile->Keys.KeyLength[i] == 0)
continue;
else
break;
}
if(MAX_WEP_KEYS == i)
{
dwrq->flags |= IW_ENCODE_NOKEY;
}
authType = ((hdd_station_ctx_t*)WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.authType;
if(eCSR_AUTH_TYPE_OPEN_SYSTEM == authType)
{
dwrq->flags |= IW_ENCODE_OPEN;
}
else
{
dwrq->flags |= IW_ENCODE_RESTRICTED;
}
EXIT();
return 0;
}
/**
* iw_get_encode() - SSR wrapper for __iw_get_encode()
* @dev: pointer to net_device
* @info: pointer to iw_request_info
* @dwrq: pointer to encoding information
* @extra: pointer to extra ioctl payload
*
* Return: 0 on success, error number otherwise
*/
static int iw_get_encode(struct net_device *dev, struct iw_request_info *info,
struct iw_point *dwrq, char *extra)
{
int ret;
vos_ssr_protect(__func__);
ret = __iw_get_encode(dev, info, dwrq, extra);
vos_ssr_unprotect(__func__);
return ret;
}
#define PAE_ROLE_AUTHENTICATOR 1 // =1 for authenticator,
#define PAE_ROLE_SUPPLICANT 0 // =0 for supplicant
/*
* This function sends a single 'key' to LIM at all time.
*/
/**
* __iw_get_rts_threshold() - SIOCGIWRTS ioctl handler
* @dev: device upon which the ioctl was received
* @info: ioctl request information
* @wrqu: ioctl request data
* @extra: ioctl extra data
*
* Return: 0 on success, non-zero on error
*/
static int __iw_get_rts_threshold(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
v_U32_t status = 0;
status = hdd_wlan_get_rts_threshold(pAdapter,wrqu);
return status;
}
/**
* iw_get_rts_threshold() - SSR wrapper for __iw_get_rts_threshold()
* @dev: pointer to net_device
* @info: pointer to iw_request_info
* @wrqu: pointer to iwreq_data
* @extra: pointer to extra ioctl payload
*
* Return: 0 on success, error number otherwise
*/
static int iw_get_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_rts_threshold(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
/**
* __iw_set_rts_threshold() - SIOCSIWRTS ioctl handler
* @dev: device upon which the ioctl was received
* @info: ioctl request information
* @wrqu: ioctl request data
* @extra: ioctl extra data
*
* Return: 0 on success, non-zero on error
*/
static int __iw_set_rts_threshold(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu, char *extra)
{
hdd_adapter_t *pAdapter = WLAN_HDD_GET_PRIV_PTR(dev);
tHalHandle hHal = WLAN_HDD_GET_HAL_CTX(pAdapter);
hdd_context_t *hdd_ctx;
int ret;
ENTER();
hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
ret = wlan_hdd_validate_context(hdd_ctx);
if (0 != ret)
return ret;
if ( wrqu->rts.value < WNI_CFG_RTS_THRESHOLD_STAMIN || wrqu->rts.value > WNI_CFG_RTS_THRESHOLD_STAMAX )
{
return -EINVAL;
}
if ( ccmCfgSetInt(hHal, WNI_CFG_RTS_THRESHOLD, wrqu->rts.value, ccmCfgSetCallback, eANI_BOOLEAN_TRUE) != eHAL_STATUS_SUCCESS )
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
FL("failed to set ini parameter, WNI_CFG_RTS_THRESHOLD"));
return -EIO;
}
EXIT();
return 0;
}
/**
* iw_set_rts_threshold() - SSR wrapper for __iw_set_rts_threshold()
* @dev: pointer to net_device
* @info: pointer to iw_request_info
* @wrqu: pointer to iwreq_data
* @extra: pointer to extra ioctl payload
*
* Return: 0 on success, error number otherwise
*/
static int iw_set_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_set_rts_threshold(dev, info, wrqu, extra);
vos_ssr_unprotect(__func__);
return ret;
}
/**
* __iw_get_frag_threshold() - SIOCGIWFRAG ioctl handler
* @dev: device upon which the ioctl was received
* @info: ioctl request information
* @wrqu: ioctl request data
* @extra: ioctl extra data